Remove unneeded semicolons from the core library

This commit is contained in:
gingerBill
2021-08-31 22:21:13 +01:00
parent b176af2742
commit 251da264ed
187 changed files with 27227 additions and 27227 deletions
+99 -99
View File
@@ -22,7 +22,7 @@ import "core:bytes"
When a decompression routine doesn't stream its output, but writes to a buffer,
we pre-allocate an output buffer to speed up decompression. The default is 1 MiB.
*/
COMPRESS_OUTPUT_ALLOCATE_MIN :: int(#config(COMPRESS_OUTPUT_ALLOCATE_MIN, 1 << 20));
COMPRESS_OUTPUT_ALLOCATE_MIN :: int(#config(COMPRESS_OUTPUT_ALLOCATE_MIN, 1 << 20))
/*
This bounds the maximum a buffer will resize to as needed, or the maximum we'll
@@ -36,12 +36,12 @@ when size_of(uintptr) == 8 {
For 64-bit platforms, we set the default max buffer size to 4 GiB,
which is GZIP and PKZIP's max payload size.
*/
COMPRESS_OUTPUT_ALLOCATE_MAX :: int(#config(COMPRESS_OUTPUT_ALLOCATE_MAX, 1 << 32));
COMPRESS_OUTPUT_ALLOCATE_MAX :: int(#config(COMPRESS_OUTPUT_ALLOCATE_MAX, 1 << 32))
} else {
/*
For 32-bit platforms, we set the default max buffer size to 512 MiB.
*/
COMPRESS_OUTPUT_ALLOCATE_MAX :: int(#config(COMPRESS_OUTPUT_ALLOCATE_MAX, 1 << 29));
COMPRESS_OUTPUT_ALLOCATE_MAX :: int(#config(COMPRESS_OUTPUT_ALLOCATE_MAX, 1 << 29))
}
@@ -179,78 +179,78 @@ Context_Stream_Input :: struct #packed {
// TODO: Make these return compress.Error errors.
input_size_from_memory :: proc(z: ^Context_Memory_Input) -> (res: i64, err: Error) {
return i64(len(z.input_data)), nil;
return i64(len(z.input_data)), nil
}
input_size_from_stream :: proc(z: ^Context_Stream_Input) -> (res: i64, err: Error) {
return io.size(z.input), nil;
return io.size(z.input), nil
}
input_size :: proc{input_size_from_memory, input_size_from_stream};
input_size :: proc{input_size_from_memory, input_size_from_stream}
@(optimization_mode="speed")
read_slice_from_memory :: #force_inline proc(z: ^Context_Memory_Input, size: int) -> (res: []u8, err: io.Error) {
#no_bounds_check {
if len(z.input_data) >= size {
res = z.input_data[:size];
z.input_data = z.input_data[size:];
return res, .None;
res = z.input_data[:size]
z.input_data = z.input_data[size:]
return res, .None
}
}
if len(z.input_data) == 0 {
return []u8{}, .EOF;
return []u8{}, .EOF
} else {
return []u8{}, .Short_Buffer;
return []u8{}, .Short_Buffer
}
}
@(optimization_mode="speed")
read_slice_from_stream :: #force_inline proc(z: ^Context_Stream_Input, size: int) -> (res: []u8, err: io.Error) {
b := make([]u8, size, context.temp_allocator);
_, e := z.input->impl_read(b[:]);
b := make([]u8, size, context.temp_allocator)
_, e := z.input->impl_read(b[:])
if e == .None {
return b, .None;
return b, .None
}
return []u8{}, e;
return []u8{}, e
}
read_slice :: proc{read_slice_from_memory, read_slice_from_stream};
read_slice :: proc{read_slice_from_memory, read_slice_from_stream}
@(optimization_mode="speed")
read_data :: #force_inline proc(z: ^$C, $T: typeid) -> (res: T, err: io.Error) {
b, e := read_slice(z, size_of(T));
b, e := read_slice(z, size_of(T))
if e == .None {
return (^T)(&b[0])^, .None;
return (^T)(&b[0])^, .None
}
return T{}, e;
return T{}, e
}
@(optimization_mode="speed")
read_u8_from_memory :: #force_inline proc(z: ^Context_Memory_Input) -> (res: u8, err: io.Error) {
#no_bounds_check {
if len(z.input_data) >= 1 {
res = z.input_data[0];
z.input_data = z.input_data[1:];
return res, .None;
res = z.input_data[0]
z.input_data = z.input_data[1:]
return res, .None
}
}
return 0, .EOF;
return 0, .EOF
}
@(optimization_mode="speed")
read_u8_from_stream :: #force_inline proc(z: ^Context_Stream_Input) -> (res: u8, err: io.Error) {
b, e := read_slice_from_stream(z, 1);
b, e := read_slice_from_stream(z, 1)
if e == .None {
return b[0], .None;
return b[0], .None
}
return 0, e;
return 0, e
}
read_u8 :: proc{read_u8_from_memory, read_u8_from_stream};
read_u8 :: proc{read_u8_from_memory, read_u8_from_stream}
/*
You would typically only use this at the end of Inflate, to drain bits from the code buffer
@@ -259,64 +259,64 @@ read_u8 :: proc{read_u8_from_memory, read_u8_from_stream};
@(optimization_mode="speed")
read_u8_prefer_code_buffer_lsb :: #force_inline proc(z: ^$C) -> (res: u8, err: io.Error) {
if z.num_bits >= 8 {
res = u8(read_bits_no_refill_lsb(z, 8));
res = u8(read_bits_no_refill_lsb(z, 8))
} else {
size, _ := input_size(z);
size, _ := input_size(z)
if size > 0 {
res, err = read_u8(z);
res, err = read_u8(z)
} else {
err = .EOF;
err = .EOF
}
}
return;
return
}
@(optimization_mode="speed")
peek_data_from_memory :: #force_inline proc(z: ^Context_Memory_Input, $T: typeid) -> (res: T, err: io.Error) {
size :: size_of(T);
size :: size_of(T)
#no_bounds_check {
if len(z.input_data) >= size {
buf := z.input_data[:size];
return (^T)(&buf[0])^, .None;
buf := z.input_data[:size]
return (^T)(&buf[0])^, .None
}
}
if len(z.input_data) == 0 {
return T{}, .EOF;
return T{}, .EOF
} else {
return T{}, .Short_Buffer;
return T{}, .Short_Buffer
}
}
@(optimization_mode="speed")
peek_data_from_stream :: #force_inline proc(z: ^Context_Stream_Input, $T: typeid) -> (res: T, err: io.Error) {
size :: size_of(T);
size :: size_of(T)
// Get current position to read from.
curr, e1 := z.input->impl_seek(0, .Current);
curr, e1 := z.input->impl_seek(0, .Current)
if e1 != .None {
return T{}, e1;
return T{}, e1
}
r, e2 := io.to_reader_at(z.input);
r, e2 := io.to_reader_at(z.input)
if !e2 {
return T{}, .Empty;
return T{}, .Empty
}
when size <= 128 {
b: [size]u8;
b: [size]u8
} else {
b := make([]u8, size, context.temp_allocator);
b := make([]u8, size, context.temp_allocator)
}
_, e3 := io.read_at(r, b[:], curr);
_, e3 := io.read_at(r, b[:], curr)
if e3 != .None {
return T{}, .Empty;
return T{}, .Empty
}
res = (^T)(&b[0])^;
return res, .None;
res = (^T)(&b[0])^
return res, .None
}
peek_data :: proc{peek_data_from_memory, peek_data_from_stream};
peek_data :: proc{peek_data_from_memory, peek_data_from_stream}
@@ -324,31 +324,31 @@ peek_data :: proc{peek_data_from_memory, peek_data_from_stream};
@(optimization_mode="speed")
peek_back_byte :: #force_inline proc(z: ^$C, offset: i64) -> (res: u8, err: io.Error) {
// Look back into the sliding window.
return z.output.buf[z.bytes_written - offset], .None;
return z.output.buf[z.bytes_written - offset], .None
}
// Generalized bit reader LSB
@(optimization_mode="speed")
refill_lsb_from_memory :: #force_inline proc(z: ^Context_Memory_Input, width := i8(48)) {
refill := u64(width);
b := u64(0);
refill := u64(width)
b := u64(0)
if z.num_bits > refill {
return;
return
}
for {
if len(z.input_data) != 0 {
b = u64(z.input_data[0]);
z.input_data = z.input_data[1:];
b = u64(z.input_data[0])
z.input_data = z.input_data[1:]
} else {
b = 0;
b = 0
}
z.code_buffer |= b << u8(z.num_bits);
z.num_bits += 8;
z.code_buffer |= b << u8(z.num_bits)
z.num_bits += 8
if z.num_bits > refill {
break;
break
}
}
}
@@ -356,123 +356,123 @@ refill_lsb_from_memory :: #force_inline proc(z: ^Context_Memory_Input, width :=
// Generalized bit reader LSB
@(optimization_mode="speed")
refill_lsb_from_stream :: proc(z: ^Context_Stream_Input, width := i8(24)) {
refill := u64(width);
refill := u64(width)
for {
if z.num_bits > refill {
break;
break
}
if z.code_buffer == 0 && z.num_bits > 63 {
z.num_bits = 0;
z.num_bits = 0
}
if z.code_buffer >= 1 << uint(z.num_bits) {
// Code buffer is malformed.
z.num_bits = max(u64);
return;
z.num_bits = max(u64)
return
}
b, err := read_u8(z);
b, err := read_u8(z)
if err != .None {
// This is fine at the end of the file.
return;
return
}
z.code_buffer |= (u64(b) << u8(z.num_bits));
z.num_bits += 8;
z.code_buffer |= (u64(b) << u8(z.num_bits))
z.num_bits += 8
}
}
refill_lsb :: proc{refill_lsb_from_memory, refill_lsb_from_stream};
refill_lsb :: proc{refill_lsb_from_memory, refill_lsb_from_stream}
@(optimization_mode="speed")
consume_bits_lsb_from_memory :: #force_inline proc(z: ^Context_Memory_Input, width: u8) {
z.code_buffer >>= width;
z.num_bits -= u64(width);
z.code_buffer >>= width
z.num_bits -= u64(width)
}
@(optimization_mode="speed")
consume_bits_lsb_from_stream :: #force_inline proc(z: ^Context_Stream_Input, width: u8) {
z.code_buffer >>= width;
z.num_bits -= u64(width);
z.code_buffer >>= width
z.num_bits -= u64(width)
}
consume_bits_lsb :: proc{consume_bits_lsb_from_memory, consume_bits_lsb_from_stream};
consume_bits_lsb :: proc{consume_bits_lsb_from_memory, consume_bits_lsb_from_stream}
@(optimization_mode="speed")
peek_bits_lsb_from_memory :: #force_inline proc(z: ^Context_Memory_Input, width: u8) -> u32 {
if z.num_bits < u64(width) {
refill_lsb(z);
refill_lsb(z)
}
return u32(z.code_buffer & ~(~u64(0) << width));
return u32(z.code_buffer & ~(~u64(0) << width))
}
@(optimization_mode="speed")
peek_bits_lsb_from_stream :: #force_inline proc(z: ^Context_Stream_Input, width: u8) -> u32 {
if z.num_bits < u64(width) {
refill_lsb(z);
refill_lsb(z)
}
return u32(z.code_buffer & ~(~u64(0) << width));
return u32(z.code_buffer & ~(~u64(0) << width))
}
peek_bits_lsb :: proc{peek_bits_lsb_from_memory, peek_bits_lsb_from_stream};
peek_bits_lsb :: proc{peek_bits_lsb_from_memory, peek_bits_lsb_from_stream}
@(optimization_mode="speed")
peek_bits_no_refill_lsb_from_memory :: #force_inline proc(z: ^Context_Memory_Input, width: u8) -> u32 {
assert(z.num_bits >= u64(width));
return u32(z.code_buffer & ~(~u64(0) << width));
assert(z.num_bits >= u64(width))
return u32(z.code_buffer & ~(~u64(0) << width))
}
@(optimization_mode="speed")
peek_bits_no_refill_lsb_from_stream :: #force_inline proc(z: ^Context_Stream_Input, width: u8) -> u32 {
assert(z.num_bits >= u64(width));
return u32(z.code_buffer & ~(~u64(0) << width));
assert(z.num_bits >= u64(width))
return u32(z.code_buffer & ~(~u64(0) << width))
}
peek_bits_no_refill_lsb :: proc{peek_bits_no_refill_lsb_from_memory, peek_bits_no_refill_lsb_from_stream};
peek_bits_no_refill_lsb :: proc{peek_bits_no_refill_lsb_from_memory, peek_bits_no_refill_lsb_from_stream}
@(optimization_mode="speed")
read_bits_lsb_from_memory :: #force_inline proc(z: ^Context_Memory_Input, width: u8) -> u32 {
k := #force_inline peek_bits_lsb(z, width);
k := #force_inline peek_bits_lsb(z, width)
#force_inline consume_bits_lsb(z, width);
return k;
return k
}
@(optimization_mode="speed")
read_bits_lsb_from_stream :: #force_inline proc(z: ^Context_Stream_Input, width: u8) -> u32 {
k := peek_bits_lsb(z, width);
consume_bits_lsb(z, width);
return k;
k := peek_bits_lsb(z, width)
consume_bits_lsb(z, width)
return k
}
read_bits_lsb :: proc{read_bits_lsb_from_memory, read_bits_lsb_from_stream};
read_bits_lsb :: proc{read_bits_lsb_from_memory, read_bits_lsb_from_stream}
@(optimization_mode="speed")
read_bits_no_refill_lsb_from_memory :: #force_inline proc(z: ^Context_Memory_Input, width: u8) -> u32 {
k := #force_inline peek_bits_no_refill_lsb(z, width);
k := #force_inline peek_bits_no_refill_lsb(z, width)
#force_inline consume_bits_lsb(z, width);
return k;
return k
}
@(optimization_mode="speed")
read_bits_no_refill_lsb_from_stream :: #force_inline proc(z: ^Context_Stream_Input, width: u8) -> u32 {
k := peek_bits_no_refill_lsb(z, width);
consume_bits_lsb(z, width);
return k;
k := peek_bits_no_refill_lsb(z, width)
consume_bits_lsb(z, width)
return k
}
read_bits_no_refill_lsb :: proc{read_bits_no_refill_lsb_from_memory, read_bits_no_refill_lsb_from_stream};
read_bits_no_refill_lsb :: proc{read_bits_no_refill_lsb_from_memory, read_bits_no_refill_lsb_from_stream}
@(optimization_mode="speed")
discard_to_next_byte_lsb_from_memory :: proc(z: ^Context_Memory_Input) {
discard := u8(z.num_bits & 7);
discard := u8(z.num_bits & 7)
#force_inline consume_bits_lsb(z, discard);
}
@(optimization_mode="speed")
discard_to_next_byte_lsb_from_stream :: proc(z: ^Context_Stream_Input) {
discard := u8(z.num_bits & 7);
consume_bits_lsb(z, discard);
discard := u8(z.num_bits & 7)
consume_bits_lsb(z, discard)
}
discard_to_next_byte_lsb :: proc{discard_to_next_byte_lsb_from_memory, discard_to_next_byte_lsb_from_stream};
+28 -28
View File
@@ -28,62 +28,62 @@ TEST: []u8 = {
0x6d, 0x6d, 0x65, 0x6e, 0x74, 0x00, 0x2b, 0x48,
0xac, 0xcc, 0xc9, 0x4f, 0x4c, 0x01, 0x00, 0x15,
0x6a, 0x2c, 0x42, 0x07, 0x00, 0x00, 0x00,
};
}
main :: proc() {
// Set up output buffer.
buf := bytes.Buffer{};
buf := bytes.Buffer{}
stdout :: proc(s: string) {
os.write_string(os.stdout, s);
os.write_string(os.stdout, s)
}
stderr :: proc(s: string) {
os.write_string(os.stderr, s);
os.write_string(os.stderr, s)
}
args := os.args;
args := os.args
if len(args) < 2 {
stderr("No input file specified.\n");
err := load(slice=TEST, buf=&buf, known_gzip_size=len(TEST));
stderr("No input file specified.\n")
err := load(slice=TEST, buf=&buf, known_gzip_size=len(TEST))
if err == nil {
stdout("Displaying test vector: ");
stdout(bytes.buffer_to_string(&buf));
stdout("\n");
stdout("Displaying test vector: ")
stdout(bytes.buffer_to_string(&buf))
stdout("\n")
} else {
fmt.printf("gzip.load returned %v\n", err);
fmt.printf("gzip.load returned %v\n", err)
}
bytes.buffer_destroy(&buf);
os.exit(0);
bytes.buffer_destroy(&buf)
os.exit(0)
}
// The rest are all files.
args = args[1:];
err: Error;
args = args[1:]
err: Error
for file in args {
if file == "-" {
// Read from stdin
s := os.stream_from_handle(os.stdin);
s := os.stream_from_handle(os.stdin)
ctx := &compress.Context_Stream_Input{
input = s,
};
err = load(ctx, &buf);
}
err = load(ctx, &buf)
} else {
err = load(file, &buf);
err = load(file, &buf)
}
if err != nil {
if err != E_General.File_Not_Found {
stderr("File not found: ");
stderr(file);
stderr("\n");
os.exit(1);
stderr("File not found: ")
stderr(file)
stderr("\n")
os.exit(1)
}
stderr("GZIP returned an error.\n");
bytes.buffer_destroy(&buf);
os.exit(2);
stderr("GZIP returned an error.\n")
bytes.buffer_destroy(&buf)
os.exit(2)
}
stdout(bytes.buffer_to_string(&buf));
stdout(bytes.buffer_to_string(&buf))
}
bytes.buffer_destroy(&buf);
bytes.buffer_destroy(&buf)
}
+97 -97
View File
@@ -46,7 +46,7 @@ Header_Flag :: enum u8 {
reserved_2 = 6,
reserved_3 = 7,
}
Header_Flags :: distinct bit_set[Header_Flag; u8];
Header_Flags :: distinct bit_set[Header_Flag; u8]
OS :: enum u8 {
FAT = 0,
@@ -82,7 +82,7 @@ OS_Name :: #partial [OS]string{
.QDOS = "QDOS",
.Acorn_RISCOS = "Acorn RISCOS",
.Unknown = "Unknown",
};
}
Compression :: enum u8 {
DEFLATE = 8,
@@ -93,74 +93,74 @@ Compression_Flags :: enum u8 {
Fastest_Compression = 4,
}
Error :: compress.Error;
E_General :: compress.General_Error;
E_GZIP :: compress.GZIP_Error;
E_ZLIB :: compress.ZLIB_Error;
E_Deflate :: compress.Deflate_Error;
Error :: compress.Error
E_General :: compress.General_Error
E_GZIP :: compress.GZIP_Error
E_ZLIB :: compress.ZLIB_Error
E_Deflate :: compress.Deflate_Error
GZIP_MAX_PAYLOAD_SIZE :: int(max(u32le));
GZIP_MAX_PAYLOAD_SIZE :: int(max(u32le))
load :: proc{load_from_slice, load_from_file, load_from_context};
load :: proc{load_from_slice, load_from_file, load_from_context}
load_from_file :: proc(filename: string, buf: ^bytes.Buffer, expected_output_size := -1, allocator := context.allocator) -> (err: Error) {
data, ok := os.read_entire_file(filename, allocator);
defer delete(data);
data, ok := os.read_entire_file(filename, allocator)
defer delete(data)
err = E_General.File_Not_Found;
err = E_General.File_Not_Found
if ok {
err = load_from_slice(data, buf, len(data), expected_output_size, allocator);
err = load_from_slice(data, buf, len(data), expected_output_size, allocator)
}
return;
return
}
load_from_slice :: proc(slice: []u8, buf: ^bytes.Buffer, known_gzip_size := -1, expected_output_size := -1, allocator := context.allocator) -> (err: Error) {
buf := buf;
buf := buf
z := &compress.Context_Memory_Input{
input_data = slice,
output = buf,
};
return load_from_context(z, buf, known_gzip_size, expected_output_size, allocator);
}
return load_from_context(z, buf, known_gzip_size, expected_output_size, allocator)
}
load_from_context :: proc(z: ^$C, buf: ^bytes.Buffer, known_gzip_size := -1, expected_output_size := -1, allocator := context.allocator) -> (err: Error) {
buf := buf;
expected_output_size := expected_output_size;
buf := buf
expected_output_size := expected_output_size
input_data_consumed := 0;
input_data_consumed := 0
z.output = buf;
z.output = buf
if expected_output_size > GZIP_MAX_PAYLOAD_SIZE {
return E_GZIP.Payload_Size_Exceeds_Max_Payload;
return E_GZIP.Payload_Size_Exceeds_Max_Payload
}
if expected_output_size > compress.COMPRESS_OUTPUT_ALLOCATE_MAX {
return E_GZIP.Output_Exceeds_COMPRESS_OUTPUT_ALLOCATE_MAX;
return E_GZIP.Output_Exceeds_COMPRESS_OUTPUT_ALLOCATE_MAX
}
b: []u8;
b: []u8
header, e := compress.read_data(z, Header);
header, e := compress.read_data(z, Header)
if e != .None {
return E_General.File_Too_Short;
return E_General.File_Too_Short
}
input_data_consumed += size_of(Header);
input_data_consumed += size_of(Header)
if header.magic != .GZIP {
return E_GZIP.Invalid_GZIP_Signature;
return E_GZIP.Invalid_GZIP_Signature
}
if header.compression_method != .DEFLATE {
return E_General.Unknown_Compression_Method;
return E_General.Unknown_Compression_Method
}
if header.os >= ._Unknown {
header.os = .Unknown;
header.os = .Unknown
}
if .reserved_1 in header.flags || .reserved_2 in header.flags || .reserved_3 in header.flags {
return E_GZIP.Reserved_Flag_Set;
return E_GZIP.Reserved_Flag_Set
}
// printf("signature: %v\n", header.magic);
@@ -171,84 +171,84 @@ load_from_context :: proc(z: ^$C, buf: ^bytes.Buffer, known_gzip_size := -1, exp
// printf("os: %v\n", OS_Name[header.os]);
if .extra in header.flags {
xlen, e_extra := compress.read_data(z, u16le);
input_data_consumed += 2;
xlen, e_extra := compress.read_data(z, u16le)
input_data_consumed += 2
if e_extra != .None {
return E_General.Stream_Too_Short;
return E_General.Stream_Too_Short
}
// printf("Extra data present (%v bytes)\n", xlen);
if xlen < 4 {
// Minimum length is 2 for ID + 2 for a field length, if set to zero.
return E_GZIP.Invalid_Extra_Data;
return E_GZIP.Invalid_Extra_Data
}
field_id: [2]u8;
field_length: u16le;
field_error: io.Error;
field_id: [2]u8
field_length: u16le
field_error: io.Error
for xlen >= 4 {
// println("Parsing Extra field(s).");
field_id, field_error = compress.read_data(z, [2]u8);
field_id, field_error = compress.read_data(z, [2]u8)
if field_error != .None {
// printf("Parsing Extra returned: %v\n", field_error);
return E_General.Stream_Too_Short;
return E_General.Stream_Too_Short
}
xlen -= 2;
input_data_consumed += 2;
xlen -= 2
input_data_consumed += 2
field_length, field_error = compress.read_data(z, u16le);
field_length, field_error = compress.read_data(z, u16le)
if field_error != .None {
// printf("Parsing Extra returned: %v\n", field_error);
return E_General.Stream_Too_Short;
return E_General.Stream_Too_Short
}
xlen -= 2;
input_data_consumed += 2;
xlen -= 2
input_data_consumed += 2
if xlen <= 0 {
// We're not going to try and recover by scanning for a ZLIB header.
// Who knows what else is wrong with this file.
return E_GZIP.Invalid_Extra_Data;
return E_GZIP.Invalid_Extra_Data
}
// printf(" Field \"%v\" of length %v found: ", string(field_id[:]), field_length);
if field_length > 0 {
b, field_error = compress.read_slice(z, int(field_length));
b, field_error = compress.read_slice(z, int(field_length))
if field_error != .None {
// printf("Parsing Extra returned: %v\n", field_error);
return E_General.Stream_Too_Short;
return E_General.Stream_Too_Short
}
xlen -= field_length;
input_data_consumed += int(field_length);
xlen -= field_length
input_data_consumed += int(field_length)
// printf("%v\n", string(field_data));
}
if xlen != 0 {
return E_GZIP.Invalid_Extra_Data;
return E_GZIP.Invalid_Extra_Data
}
}
}
if .name in header.flags {
// Should be enough.
name: [1024]u8;
i := 0;
name_error: io.Error;
name: [1024]u8
i := 0
name_error: io.Error
for i < len(name) {
b, name_error = compress.read_slice(z, 1);
b, name_error = compress.read_slice(z, 1)
if name_error != .None {
return E_General.Stream_Too_Short;
return E_General.Stream_Too_Short
}
input_data_consumed += 1;
input_data_consumed += 1
if b[0] == 0 {
break;
break
}
name[i] = b[0];
i += 1;
name[i] = b[0]
i += 1
if i >= len(name) {
return E_GZIP.Original_Name_Too_Long;
return E_GZIP.Original_Name_Too_Long
}
}
// printf("Original filename: %v\n", string(name[:i]));
@@ -256,34 +256,34 @@ load_from_context :: proc(z: ^$C, buf: ^bytes.Buffer, known_gzip_size := -1, exp
if .comment in header.flags {
// Should be enough.
comment: [1024]u8;
i := 0;
comment_error: io.Error;
comment: [1024]u8
i := 0
comment_error: io.Error
for i < len(comment) {
b, comment_error = compress.read_slice(z, 1);
b, comment_error = compress.read_slice(z, 1)
if comment_error != .None {
return E_General.Stream_Too_Short;
return E_General.Stream_Too_Short
}
input_data_consumed += 1;
input_data_consumed += 1
if b[0] == 0 {
break;
break
}
comment[i] = b[0];
i += 1;
comment[i] = b[0]
i += 1
if i >= len(comment) {
return E_GZIP.Comment_Too_Long;
return E_GZIP.Comment_Too_Long
}
}
// printf("Comment: %v\n", string(comment[:i]));
}
if .header_crc in header.flags {
crc_error: io.Error;
_, crc_error = compress.read_slice(z, 2);
input_data_consumed += 2;
crc_error: io.Error
_, crc_error = compress.read_slice(z, 2)
input_data_consumed += 2
if crc_error != .None {
return E_General.Stream_Too_Short;
return E_General.Stream_Too_Short
}
/*
We don't actually check the CRC16 (lower 2 bytes of CRC32 of header data until the CRC field).
@@ -294,7 +294,7 @@ load_from_context :: proc(z: ^$C, buf: ^bytes.Buffer, known_gzip_size := -1, exp
/*
We should have arrived at the ZLIB payload.
*/
payload_u32le: u32le;
payload_u32le: u32le
// fmt.printf("known_gzip_size: %v | expected_output_size: %v\n", known_gzip_size, expected_output_size);
@@ -314,12 +314,12 @@ load_from_context :: proc(z: ^$C, buf: ^bytes.Buffer, known_gzip_size := -1, exp
*/
if known_gzip_size > -1 {
offset := i64(known_gzip_size - input_data_consumed - 4);
size, _ := compress.input_size(z);
offset := i64(known_gzip_size - input_data_consumed - 4)
size, _ := compress.input_size(z)
if size >= offset + 4 {
length_bytes := z.input_data[offset:][:4];
payload_u32le = (^u32le)(&length_bytes[0])^;
expected_output_size = int(payload_u32le);
length_bytes := z.input_data[offset:][:4]
payload_u32le = (^u32le)(&length_bytes[0])^
expected_output_size = int(payload_u32le)
}
} else {
/*
@@ -331,37 +331,37 @@ load_from_context :: proc(z: ^$C, buf: ^bytes.Buffer, known_gzip_size := -1, exp
// fmt.printf("GZIP: Expected Payload Size: %v\n", expected_output_size);
zlib_error := zlib.inflate_raw(z=z, expected_output_size=expected_output_size);
zlib_error := zlib.inflate_raw(z=z, expected_output_size=expected_output_size)
if zlib_error != nil {
return zlib_error;
return zlib_error
}
/*
Read CRC32 using the ctx bit reader because zlib may leave bytes in there.
*/
compress.discard_to_next_byte_lsb(z);
compress.discard_to_next_byte_lsb(z)
footer_error: io.Error;
footer_error: io.Error
payload_crc_b: [4]u8;
payload_crc_b: [4]u8
for _, i in payload_crc_b {
payload_crc_b[i], footer_error = compress.read_u8_prefer_code_buffer_lsb(z);
payload_crc_b[i], footer_error = compress.read_u8_prefer_code_buffer_lsb(z)
}
payload_crc := transmute(u32le)payload_crc_b;
payload_crc := transmute(u32le)payload_crc_b
payload := bytes.buffer_to_bytes(buf);
crc32 := u32le(hash.crc32(payload));
payload := bytes.buffer_to_bytes(buf)
crc32 := u32le(hash.crc32(payload))
if crc32 != payload_crc {
return E_GZIP.Payload_CRC_Invalid;
return E_GZIP.Payload_CRC_Invalid
}
payload_len_b: [4]u8;
payload_len_b: [4]u8
for _, i in payload_len_b {
payload_len_b[i], footer_error = compress.read_u8_prefer_code_buffer_lsb(z);
payload_len_b[i], footer_error = compress.read_u8_prefer_code_buffer_lsb(z)
}
payload_len := transmute(u32le)payload_len_b;
payload_len := transmute(u32le)payload_len_b
if len(payload) != int(payload_len) {
return E_GZIP.Payload_Length_Invalid;
return E_GZIP.Payload_Length_Invalid
}
return nil;
return nil
}
+9 -9
View File
@@ -34,19 +34,19 @@ main :: proc() {
98, 53, 8, 104, 213, 234, 201, 147, 7, 248, 192, 14, 170, 29, 25,
171, 15, 18, 59, 138, 112, 63, 23, 205, 110, 254, 136, 109, 78, 231,
63, 234, 138, 133, 204,
};
OUTPUT_SIZE :: 438;
}
OUTPUT_SIZE :: 438
buf: bytes.Buffer;
buf: bytes.Buffer
// We can pass ", true" to inflate a raw DEFLATE stream instead of a ZLIB wrapped one.
err := inflate(input=ODIN_DEMO, buf=&buf, expected_output_size=OUTPUT_SIZE);
defer bytes.buffer_destroy(&buf);
err := inflate(input=ODIN_DEMO, buf=&buf, expected_output_size=OUTPUT_SIZE)
defer bytes.buffer_destroy(&buf)
if err != nil {
fmt.printf("\nError: %v\n", err);
fmt.printf("\nError: %v\n", err)
}
s := bytes.buffer_to_string(&buf);
fmt.printf("Input: %v bytes, output (%v bytes):\n%v\n", len(ODIN_DEMO), len(s), s);
assert(len(s) == OUTPUT_SIZE);
s := bytes.buffer_to_string(&buf)
fmt.printf("Input: %v bytes, output (%v bytes):\n%v\n", len(ODIN_DEMO), len(s), s)
assert(len(s) == OUTPUT_SIZE)
}
+210 -210
View File
@@ -47,41 +47,41 @@ Options :: struct {
level: u8,
}
Error :: compress.Error;
E_General :: compress.General_Error;
E_ZLIB :: compress.ZLIB_Error;
E_Deflate :: compress.Deflate_Error;
Error :: compress.Error
E_General :: compress.General_Error
E_ZLIB :: compress.ZLIB_Error
E_Deflate :: compress.Deflate_Error
DEFLATE_MAX_CHUNK_SIZE :: 65535;
DEFLATE_MAX_LITERAL_SIZE :: 65535;
DEFLATE_MAX_DISTANCE :: 32768;
DEFLATE_MAX_LENGTH :: 258;
DEFLATE_MAX_CHUNK_SIZE :: 65535
DEFLATE_MAX_LITERAL_SIZE :: 65535
DEFLATE_MAX_DISTANCE :: 32768
DEFLATE_MAX_LENGTH :: 258
HUFFMAN_MAX_BITS :: 16;
HUFFMAN_FAST_BITS :: 9;
HUFFMAN_FAST_MASK :: ((1 << HUFFMAN_FAST_BITS) - 1);
HUFFMAN_MAX_BITS :: 16
HUFFMAN_FAST_BITS :: 9
HUFFMAN_FAST_MASK :: ((1 << HUFFMAN_FAST_BITS) - 1)
Z_LENGTH_BASE := [31]u16{
3,4,5,6,7,8,9,10,11,13,15,17,19,23,27,31,35,43,51,59,
67,83,99,115,131,163,195,227,258,0,0,
};
}
Z_LENGTH_EXTRA := [31]u8{
0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0,0,0,
};
}
Z_DIST_BASE := [32]u16{
1,2,3,4,5,7,9,13,17,25,33,49,65,97,129,193,
257,385,513,769,1025,1537,2049,3073,4097,6145,8193,12289,16385,24577,0,0,
};
}
Z_DIST_EXTRA := [32]u8{
0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13,0,0,
};
}
Z_LENGTH_DEZIGZAG := []u8{
16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15,
};
}
Z_FIXED_LENGTH := [288]u8{
8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
@@ -93,17 +93,17 @@ Z_FIXED_LENGTH := [288]u8{
9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,
9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,
7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,8,8,8,8,8,8,8,8,
};
}
Z_FIXED_DIST := [32]u8{
5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
};
}
/*
Accelerate all cases in default tables.
*/
ZFAST_BITS :: 9;
ZFAST_MASK :: ((1 << ZFAST_BITS) - 1);
ZFAST_BITS :: 9
ZFAST_MASK :: ((1 << ZFAST_BITS) - 1)
/*
ZLIB-style Huffman encoding.
@@ -116,22 +116,22 @@ Huffman_Table :: struct {
firstsymbol: [16]u16,
size: [288]u8,
value: [288]u16,
};
}
// Implementation starts here
@(optimization_mode="speed")
z_bit_reverse :: #force_inline proc(n: u16, bits: u8) -> (r: u16) {
assert(bits <= 16);
assert(bits <= 16)
// NOTE: Can optimize with llvm.bitreverse.i64 or some bit twiddling
// by reversing all of the bits and masking out the unneeded ones.
r = n;
r = ((r & 0xAAAA) >> 1) | ((r & 0x5555) << 1);
r = ((r & 0xCCCC) >> 2) | ((r & 0x3333) << 2);
r = ((r & 0xF0F0) >> 4) | ((r & 0x0F0F) << 4);
r = ((r & 0xFF00) >> 8) | ((r & 0x00FF) << 8);
r = n
r = ((r & 0xAAAA) >> 1) | ((r & 0x5555) << 1)
r = ((r & 0xCCCC) >> 2) | ((r & 0x3333) << 2)
r = ((r & 0xF0F0) >> 4) | ((r & 0x0F0F) << 4)
r = ((r & 0xFF00) >> 8) | ((r & 0x00FF) << 8)
r >>= (16 - bits);
return;
r >>= (16 - bits)
return
}
@@ -145,16 +145,16 @@ grow_buffer :: proc(buf: ^[dynamic]u8) -> (err: compress.Error) {
/*
Double until we reach the maximum allowed.
*/
new_size := min(len(buf) << 1, compress.COMPRESS_OUTPUT_ALLOCATE_MAX);
resize(buf, new_size);
new_size := min(len(buf) << 1, compress.COMPRESS_OUTPUT_ALLOCATE_MAX)
resize(buf, new_size)
if len(buf) != new_size {
/*
Resize failed.
*/
return .Resize_Failed;
return .Resize_Failed
}
return nil;
return nil
}
/*
@@ -167,17 +167,17 @@ write_byte :: #force_inline proc(z: ^$C, c: u8) -> (err: io.Error) #no_bounds_ch
Resize if needed.
*/
if int(z.bytes_written) + 1 >= len(z.output.buf) {
e := grow_buffer(&z.output.buf);
e := grow_buffer(&z.output.buf)
if e != nil {
return .Short_Write;
return .Short_Write
}
}
#no_bounds_check {
z.output.buf[z.bytes_written] = c;
z.output.buf[z.bytes_written] = c
}
z.bytes_written += 1;
return .None;
z.bytes_written += 1
return .None
}
@(optimization_mode="speed")
@@ -192,20 +192,20 @@ repl_byte :: proc(z: ^$C, count: u16, c: u8) -> (err: io.Error) #no_bounds_chec
Resize if needed.
*/
if int(z.bytes_written) + int(count) >= len(z.output.buf) {
e := grow_buffer(&z.output.buf);
e := grow_buffer(&z.output.buf)
if e != nil {
return .Short_Write;
return .Short_Write
}
}
#no_bounds_check {
for _ in 0..<count {
z.output.buf[z.bytes_written] = c;
z.bytes_written += 1;
z.output.buf[z.bytes_written] = c
z.bytes_written += 1
}
}
return .None;
return .None
}
@(optimization_mode="speed")
@@ -216,178 +216,178 @@ repl_bytes :: proc(z: ^$C, count: u16, distance: u16) -> (err: io.Error) {
the output stream, just give it _that_ slice.
*/
offset := i64(distance);
offset := i64(distance)
if int(z.bytes_written) + int(count) >= len(z.output.buf) {
e := grow_buffer(&z.output.buf);
e := grow_buffer(&z.output.buf)
if e != nil {
return .Short_Write;
return .Short_Write
}
}
#no_bounds_check {
for _ in 0..<count {
c := z.output.buf[z.bytes_written - offset];
z.output.buf[z.bytes_written] = c;
z.bytes_written += 1;
c := z.output.buf[z.bytes_written - offset]
z.output.buf[z.bytes_written] = c
z.bytes_written += 1
}
}
return .None;
return .None
}
allocate_huffman_table :: proc(allocator := context.allocator) -> (z: ^Huffman_Table, err: Error) {
return new(Huffman_Table, allocator), nil;
return new(Huffman_Table, allocator), nil
}
@(optimization_mode="speed")
build_huffman :: proc(z: ^Huffman_Table, code_lengths: []u8) -> (err: Error) {
sizes: [HUFFMAN_MAX_BITS+1]int;
next_code: [HUFFMAN_MAX_BITS]int;
sizes: [HUFFMAN_MAX_BITS+1]int
next_code: [HUFFMAN_MAX_BITS]int
k := int(0);
k := int(0)
mem.zero_slice(sizes[:]);
mem.zero_slice(z.fast[:]);
mem.zero_slice(sizes[:])
mem.zero_slice(z.fast[:])
for v in code_lengths {
sizes[v] += 1;
sizes[v] += 1
}
sizes[0] = 0;
sizes[0] = 0
for i in 1..<(HUFFMAN_MAX_BITS+1) {
if sizes[i] > (1 << uint(i)) {
return E_Deflate.Huffman_Bad_Sizes;
return E_Deflate.Huffman_Bad_Sizes
}
}
code := int(0);
code := int(0)
for i in 1..<HUFFMAN_MAX_BITS {
next_code[i] = code;
z.firstcode[i] = u16(code);
z.firstsymbol[i] = u16(k);
code = code + sizes[i];
next_code[i] = code
z.firstcode[i] = u16(code)
z.firstsymbol[i] = u16(k)
code = code + sizes[i]
if sizes[i] != 0 {
if code - 1 >= (1 << u16(i)) {
return E_Deflate.Huffman_Bad_Code_Lengths;
return E_Deflate.Huffman_Bad_Code_Lengths
}
}
z.maxcode[i] = code << (HUFFMAN_MAX_BITS - uint(i));
code <<= 1;
k += int(sizes[i]);
z.maxcode[i] = code << (HUFFMAN_MAX_BITS - uint(i))
code <<= 1
k += int(sizes[i])
}
z.maxcode[HUFFMAN_MAX_BITS] = 0x10000; // Sentinel
c: int;
z.maxcode[HUFFMAN_MAX_BITS] = 0x10000 // Sentinel
c: int
for v, ci in code_lengths {
if v != 0 {
c = next_code[v] - int(z.firstcode[v]) + int(z.firstsymbol[v]);
fastv := u16((u16(v) << 9) | u16(ci));
z.size[c] = u8(v);
z.value[c] = u16(ci);
c = next_code[v] - int(z.firstcode[v]) + int(z.firstsymbol[v])
fastv := u16((u16(v) << 9) | u16(ci))
z.size[c] = u8(v)
z.value[c] = u16(ci)
if v <= ZFAST_BITS {
j := z_bit_reverse(u16(next_code[v]), v);
j := z_bit_reverse(u16(next_code[v]), v)
for j < (1 << ZFAST_BITS) {
z.fast[j] = fastv;
j += (1 << v);
z.fast[j] = fastv
j += (1 << v)
}
}
next_code[v] += 1;
next_code[v] += 1
}
}
return nil;
return nil
}
@(optimization_mode="speed")
decode_huffman_slowpath :: proc(z: ^$C, t: ^Huffman_Table) -> (r: u16, err: Error) #no_bounds_check {
code := u16(compress.peek_bits_lsb(z,16));
code := u16(compress.peek_bits_lsb(z,16))
k := int(z_bit_reverse(code, 16));
s: u8;
k := int(z_bit_reverse(code, 16))
s: u8
#no_bounds_check for s = HUFFMAN_FAST_BITS+1; ; {
if k < t.maxcode[s] {
break;
break
}
s += 1;
s += 1
}
if s >= 16 {
return 0, E_Deflate.Bad_Huffman_Code;
return 0, E_Deflate.Bad_Huffman_Code
}
// code size is s, so:
b := (k >> (16-s)) - int(t.firstcode[s]) + int(t.firstsymbol[s]);
b := (k >> (16-s)) - int(t.firstcode[s]) + int(t.firstsymbol[s])
if b >= size_of(t.size) {
return 0, E_Deflate.Bad_Huffman_Code;
return 0, E_Deflate.Bad_Huffman_Code
}
if t.size[b] != s {
return 0, E_Deflate.Bad_Huffman_Code;
return 0, E_Deflate.Bad_Huffman_Code
}
compress.consume_bits_lsb(z, s);
compress.consume_bits_lsb(z, s)
r = t.value[b];
return r, nil;
r = t.value[b]
return r, nil
}
@(optimization_mode="speed")
decode_huffman :: proc(z: ^$C, t: ^Huffman_Table) -> (r: u16, err: Error) #no_bounds_check {
if z.num_bits < 16 {
if z.num_bits > 63 {
return 0, E_ZLIB.Code_Buffer_Malformed;
return 0, E_ZLIB.Code_Buffer_Malformed
}
compress.refill_lsb(z);
compress.refill_lsb(z)
if z.num_bits > 63 {
return 0, E_General.Stream_Too_Short;
return 0, E_General.Stream_Too_Short
}
}
#no_bounds_check b := t.fast[z.code_buffer & ZFAST_MASK];
#no_bounds_check b := t.fast[z.code_buffer & ZFAST_MASK]
if b != 0 {
s := u8(b >> ZFAST_BITS);
compress.consume_bits_lsb(z, s);
return b & 511, nil;
s := u8(b >> ZFAST_BITS)
compress.consume_bits_lsb(z, s)
return b & 511, nil
}
return decode_huffman_slowpath(z, t);
return decode_huffman_slowpath(z, t)
}
@(optimization_mode="speed")
parse_huffman_block :: proc(z: ^$C, z_repeat, z_offset: ^Huffman_Table) -> (err: Error) #no_bounds_check {
#no_bounds_check for {
value, e := decode_huffman(z, z_repeat);
value, e := decode_huffman(z, z_repeat)
if e != nil {
return err;
return err
}
if value < 256 {
e := write_byte(z, u8(value));
e := write_byte(z, u8(value))
if e != .None {
return E_General.Output_Too_Short;
return E_General.Output_Too_Short
}
} else {
if value == 256 {
// End of block
return nil;
return nil
}
value -= 257;
length := Z_LENGTH_BASE[value];
value -= 257
length := Z_LENGTH_BASE[value]
if Z_LENGTH_EXTRA[value] > 0 {
length += u16(compress.read_bits_lsb(z, Z_LENGTH_EXTRA[value]));
length += u16(compress.read_bits_lsb(z, Z_LENGTH_EXTRA[value]))
}
value, e = decode_huffman(z, z_offset);
value, e = decode_huffman(z, z_offset)
if e != nil {
return E_Deflate.Bad_Huffman_Code;
return E_Deflate.Bad_Huffman_Code
}
distance := Z_DIST_BASE[value];
distance := Z_DIST_BASE[value]
if Z_DIST_EXTRA[value] > 0 {
distance += u16(compress.read_bits_lsb(z, Z_DIST_EXTRA[value]));
distance += u16(compress.read_bits_lsb(z, Z_DIST_EXTRA[value]))
}
if z.bytes_written < i64(distance) {
// Distance is longer than we've decoded so far.
return E_Deflate.Bad_Distance;
return E_Deflate.Bad_Distance
}
/*
@@ -402,17 +402,17 @@ parse_huffman_block :: proc(z: ^$C, z_repeat, z_offset: ^Huffman_Table) -> (err:
Replicate the last outputted byte, length times.
*/
if length > 0 {
c := z.output.buf[z.bytes_written - i64(distance)];
e := repl_byte(z, length, c);
c := z.output.buf[z.bytes_written - i64(distance)]
e := repl_byte(z, length, c)
if e != .None {
return E_General.Output_Too_Short;
return E_General.Output_Too_Short
}
}
} else {
if length > 0 {
e := repl_bytes(z, length, distance);
e := repl_bytes(z, length, distance)
if e != .None {
return E_General.Output_Too_Short;
return E_General.Output_Too_Short
}
}
}
@@ -430,27 +430,27 @@ inflate_from_context :: proc(using ctx: ^compress.Context_Memory_Input, raw := f
*/
if !raw {
size, size_err := compress.input_size(ctx);
size, size_err := compress.input_size(ctx)
if size < 6 || size_err != nil {
return E_General.Stream_Too_Short;
return E_General.Stream_Too_Short
}
cmf, _ := compress.read_u8(ctx);
cmf, _ := compress.read_u8(ctx)
method := Compression_Method(cmf & 0xf);
method := Compression_Method(cmf & 0xf)
if method != .DEFLATE {
return E_General.Unknown_Compression_Method;
return E_General.Unknown_Compression_Method
}
if cinfo := (cmf >> 4) & 0xf; cinfo > 7 {
return E_ZLIB.Unsupported_Window_Size;
return E_ZLIB.Unsupported_Window_Size
}
flg, _ := compress.read_u8(ctx);
flg, _ := compress.read_u8(ctx)
fcheck := flg & 0x1f;
fcheck_computed := (cmf << 8 | flg) & 0x1f;
fcheck := flg & 0x1f
fcheck_computed := (cmf << 8 | flg) & 0x1f
if fcheck != fcheck_computed {
return E_General.Checksum_Failed;
return E_General.Checksum_Failed
}
/*
@@ -458,7 +458,7 @@ inflate_from_context :: proc(using ctx: ^compress.Context_Memory_Input, raw := f
They're application specific and PNG doesn't use them.
*/
if fdict := (flg >> 5) & 1; fdict != 0 {
return E_ZLIB.FDICT_Unsupported;
return E_ZLIB.FDICT_Unsupported
}
// flevel := Compression_Level((flg >> 6) & 3);
@@ -471,36 +471,36 @@ inflate_from_context :: proc(using ctx: ^compress.Context_Memory_Input, raw := f
}
// Parse ZLIB stream without header.
inflate_raw(z=ctx, expected_output_size=expected_output_size) or_return;
inflate_raw(z=ctx, expected_output_size=expected_output_size) or_return
if !raw {
compress.discard_to_next_byte_lsb(ctx);
compress.discard_to_next_byte_lsb(ctx)
adler_b: [4]u8;
adler_b: [4]u8
for _, i in adler_b {
adler_b[i], _ = compress.read_u8_prefer_code_buffer_lsb(ctx);
adler_b[i], _ = compress.read_u8_prefer_code_buffer_lsb(ctx)
}
adler := transmute(u32be)adler_b;
adler := transmute(u32be)adler_b
output_hash := hash.adler32(ctx.output.buf[:]);
output_hash := hash.adler32(ctx.output.buf[:])
if output_hash != u32(adler) {
return E_General.Checksum_Failed;
return E_General.Checksum_Failed
}
}
return nil;
return nil
}
// TODO: Check alignment of reserve/resize.
@(optimization_mode="speed")
inflate_raw :: proc(z: ^$C, expected_output_size := -1, allocator := context.allocator) -> (err: Error) #no_bounds_check {
expected_output_size := expected_output_size;
expected_output_size := expected_output_size
/*
Always set up a minimum allocation size.
*/
expected_output_size = max(max(expected_output_size, compress.COMPRESS_OUTPUT_ALLOCATE_MIN), 512);
expected_output_size = max(max(expected_output_size, compress.COMPRESS_OUTPUT_ALLOCATE_MIN), 512)
// fmt.printf("\nZLIB: Expected Payload Size: %v\n\n", expected_output_size);
@@ -508,34 +508,34 @@ inflate_raw :: proc(z: ^$C, expected_output_size := -1, allocator := context.all
/*
Try to pre-allocate the output buffer.
*/
reserve(&z.output.buf, expected_output_size);
resize (&z.output.buf, expected_output_size);
reserve(&z.output.buf, expected_output_size)
resize (&z.output.buf, expected_output_size)
};
if len(z.output.buf) != expected_output_size {
return .Resize_Failed;
return .Resize_Failed
}
z.num_bits = 0;
z.code_buffer = 0;
z.num_bits = 0
z.code_buffer = 0
z_repeat: ^Huffman_Table;
z_offset: ^Huffman_Table;
codelength_ht: ^Huffman_Table;
defer free(z_repeat);
defer free(z_offset);
defer free(codelength_ht);
z_repeat: ^Huffman_Table
z_offset: ^Huffman_Table
codelength_ht: ^Huffman_Table
defer free(z_repeat)
defer free(z_offset)
defer free(codelength_ht)
z_repeat = allocate_huffman_table(allocator=context.allocator) or_return;
z_offset = allocate_huffman_table(allocator=context.allocator) or_return;
codelength_ht = allocate_huffman_table(allocator=context.allocator) or_return;
z_repeat = allocate_huffman_table(allocator=context.allocator) or_return
z_offset = allocate_huffman_table(allocator=context.allocator) or_return
codelength_ht = allocate_huffman_table(allocator=context.allocator) or_return
final := u32(0);
type := u32(0);
final := u32(0)
type := u32(0)
for {
final = compress.read_bits_lsb(z, 1);
type = compress.read_bits_lsb(z, 2);
final = compress.read_bits_lsb(z, 1)
type = compress.read_bits_lsb(z, 2)
// fmt.printf("Final: %v | Type: %v\n", final, type);
@@ -544,16 +544,16 @@ inflate_raw :: proc(z: ^$C, expected_output_size := -1, allocator := context.all
// Uncompressed block
// Discard bits until next byte boundary
compress.discard_to_next_byte_lsb(z);
compress.discard_to_next_byte_lsb(z)
uncompressed_len := i16(compress.read_bits_lsb(z, 16));
length_check := i16(compress.read_bits_lsb(z, 16));
uncompressed_len := i16(compress.read_bits_lsb(z, 16))
length_check := i16(compress.read_bits_lsb(z, 16))
// fmt.printf("LEN: %v, ~LEN: %v, NLEN: %v, ~NLEN: %v\n", uncompressed_len, ~uncompressed_len, length_check, ~length_check);
if ~uncompressed_len != length_check {
return E_Deflate.Len_Nlen_Mismatch;
return E_Deflate.Len_Nlen_Mismatch
}
/*
@@ -561,116 +561,116 @@ inflate_raw :: proc(z: ^$C, expected_output_size := -1, allocator := context.all
and a single Adler32 update after.
*/
#no_bounds_check for uncompressed_len > 0 {
compress.refill_lsb(z);
lit := compress.read_bits_lsb(z, 8);
write_byte(z, u8(lit));
uncompressed_len -= 1;
compress.refill_lsb(z)
lit := compress.read_bits_lsb(z, 8)
write_byte(z, u8(lit))
uncompressed_len -= 1
}
case 3:
return E_Deflate.BType_3;
return E_Deflate.BType_3
case:
// log.debugf("Err: %v | Final: %v | Type: %v\n", err, final, type);
if type == 1 {
// Use fixed code lengths.
build_huffman(z_repeat, Z_FIXED_LENGTH[:]) or_return;
build_huffman(z_offset, Z_FIXED_DIST[:]) or_return;
build_huffman(z_repeat, Z_FIXED_LENGTH[:]) or_return
build_huffman(z_offset, Z_FIXED_DIST[:]) or_return
} else {
lencodes: [286+32+137]u8;
codelength_sizes: [19]u8;
lencodes: [286+32+137]u8
codelength_sizes: [19]u8
//i: u32;
n: u32;
n: u32
compress.refill_lsb(z, 14);
hlit := compress.read_bits_no_refill_lsb(z, 5) + 257;
hdist := compress.read_bits_no_refill_lsb(z, 5) + 1;
hclen := compress.read_bits_no_refill_lsb(z, 4) + 4;
ntot := hlit + hdist;
compress.refill_lsb(z, 14)
hlit := compress.read_bits_no_refill_lsb(z, 5) + 257
hdist := compress.read_bits_no_refill_lsb(z, 5) + 1
hclen := compress.read_bits_no_refill_lsb(z, 4) + 4
ntot := hlit + hdist
#no_bounds_check for i in 0..<hclen {
s := compress.read_bits_lsb(z, 3);
codelength_sizes[Z_LENGTH_DEZIGZAG[i]] = u8(s);
s := compress.read_bits_lsb(z, 3)
codelength_sizes[Z_LENGTH_DEZIGZAG[i]] = u8(s)
}
build_huffman(codelength_ht, codelength_sizes[:]) or_return;
build_huffman(codelength_ht, codelength_sizes[:]) or_return
n = 0;
c: u16;
n = 0
c: u16
for n < ntot {
c = decode_huffman(z, codelength_ht) or_return;
c = decode_huffman(z, codelength_ht) or_return
if c < 0 || c >= 19 {
return E_Deflate.Huffman_Bad_Code_Lengths;
return E_Deflate.Huffman_Bad_Code_Lengths
}
if c < 16 {
lencodes[n] = u8(c);
n += 1;
lencodes[n] = u8(c)
n += 1
} else {
fill := u8(0);
compress.refill_lsb(z, 7);
fill := u8(0)
compress.refill_lsb(z, 7)
switch c {
case 16:
c = u16(compress.read_bits_no_refill_lsb(z, 2) + 3);
c = u16(compress.read_bits_no_refill_lsb(z, 2) + 3)
if n == 0 {
return E_Deflate.Huffman_Bad_Code_Lengths;
return E_Deflate.Huffman_Bad_Code_Lengths
}
fill = lencodes[n - 1];
fill = lencodes[n - 1]
case 17:
c = u16(compress.read_bits_no_refill_lsb(z, 3) + 3);
c = u16(compress.read_bits_no_refill_lsb(z, 3) + 3)
case 18:
c = u16(compress.read_bits_no_refill_lsb(z, 7) + 11);
c = u16(compress.read_bits_no_refill_lsb(z, 7) + 11)
case:
return E_Deflate.Huffman_Bad_Code_Lengths;
return E_Deflate.Huffman_Bad_Code_Lengths
}
if ntot - n < u32(c) {
return E_Deflate.Huffman_Bad_Code_Lengths;
return E_Deflate.Huffman_Bad_Code_Lengths
}
nc := n + u32(c);
nc := n + u32(c)
#no_bounds_check for ; n < nc; n += 1 {
lencodes[n] = fill;
lencodes[n] = fill
}
}
}
if n != ntot {
return E_Deflate.Huffman_Bad_Code_Lengths;
return E_Deflate.Huffman_Bad_Code_Lengths
}
build_huffman(z_repeat, lencodes[:hlit]) or_return;
build_huffman(z_offset, lencodes[hlit:ntot]) or_return;
build_huffman(z_repeat, lencodes[:hlit]) or_return
build_huffman(z_offset, lencodes[hlit:ntot]) or_return
}
parse_huffman_block(z, z_repeat, z_offset) or_return;
parse_huffman_block(z, z_repeat, z_offset) or_return
}
if final == 1 {
break;
break
}
}
if int(z.bytes_written) != len(z.output.buf) {
resize(&z.output.buf, int(z.bytes_written));
resize(&z.output.buf, int(z.bytes_written))
}
return nil;
return nil
}
inflate_from_byte_array :: proc(input: []u8, buf: ^bytes.Buffer, raw := false, expected_output_size := -1) -> (err: Error) {
ctx := compress.Context_Memory_Input{};
ctx := compress.Context_Memory_Input{}
ctx.input_data = input;
ctx.output = buf;
ctx.input_data = input
ctx.output = buf
return inflate_from_context(ctx=&ctx, raw=raw, expected_output_size=expected_output_size);
return inflate_from_context(ctx=&ctx, raw=raw, expected_output_size=expected_output_size)
}
inflate_from_byte_array_raw :: proc(input: []u8, buf: ^bytes.Buffer, raw := false, expected_output_size := -1) -> (err: Error) {
ctx := compress.Context_Memory_Input{};
ctx := compress.Context_Memory_Input{}
ctx.input_data = input;
ctx.output = buf;
ctx.input_data = input
ctx.output = buf
return inflate_raw(z=&ctx, expected_output_size=expected_output_size);
return inflate_raw(z=&ctx, expected_output_size=expected_output_size)
}
inflate :: proc{inflate_from_context, inflate_from_byte_array};