| ... | @@ -10,6 +10,7 @@ input: *Reader, | ... | @@ -10,6 +10,7 @@ input: *Reader, |
| 10 | reader: Reader, | 10 | reader: Reader, |
| 11 | state: State, | 11 | state: State, |
| 12 | verify_checksum: bool, | 12 | verify_checksum: bool, |
| | 13 | window_len: u32, |
| 13 | err: ?Error = null, | 14 | err: ?Error = null, |
| 14 | | 15 | |
| 15 | const State = union(enum) { | 16 | const State = union(enum) { |
| ... | @@ -29,6 +30,8 @@ pub const Options = struct { | ... | @@ -29,6 +30,8 @@ pub const Options = struct { |
| 29 | /// Verifying checksums is not implemented yet and will cause a panic if | 30 | /// Verifying checksums is not implemented yet and will cause a panic if |
| 30 | /// you set this to true. | 31 | /// you set this to true. |
| 31 | verify_checksum: bool = false, | 32 | verify_checksum: bool = false, |
| | 33 | /// Affects the minimum capacity of the provided buffer. |
| | 34 | window_len: u32 = zstd.default_window_len, |
| 32 | }; | 35 | }; |
| 33 | | 36 | |
| 34 | pub const Error = error{ | 37 | pub const Error = error{ |
| ... | @@ -65,11 +68,14 @@ pub const Error = error{ | ... | @@ -65,11 +68,14 @@ pub const Error = error{ |
| 65 | WindowSizeUnknown, | 68 | WindowSizeUnknown, |
| 66 | }; | 69 | }; |
| 67 | | 70 | |
| | 71 | /// If buffer that is written to is not big enough, some streams will fail with |
| | 72 | /// `error.OutputBufferUndersize`. A safe value is `zstd.default_window_len * 2`. |
| 68 | pub fn init(input: *Reader, buffer: []u8, options: Options) Decompress { | 73 | pub fn init(input: *Reader, buffer: []u8, options: Options) Decompress { |
| 69 | return .{ | 74 | return .{ |
| 70 | .input = input, | 75 | .input = input, |
| 71 | .state = .new_frame, | 76 | .state = .new_frame, |
| 72 | .verify_checksum = options.verify_checksum, | 77 | .verify_checksum = options.verify_checksum, |
| | 78 | .window_len = options.window_len, |
| 73 | .reader = .{ | 79 | .reader = .{ |
| 74 | .vtable = &.{ .stream = stream }, | 80 | .vtable = &.{ .stream = stream }, |
| 75 | .buffer = buffer, | 81 | .buffer = buffer, |
| ... | @@ -143,6 +149,7 @@ fn initFrame(d: *Decompress, window_size_max: usize, magic: Frame.Magic) !void { | ... | @@ -143,6 +149,7 @@ fn initFrame(d: *Decompress, window_size_max: usize, magic: Frame.Magic) !void { |
| 143 | | 149 | |
| 144 | fn readInFrame(d: *Decompress, w: *Writer, limit: Limit, state: *State.InFrame) !usize { | 150 | fn readInFrame(d: *Decompress, w: *Writer, limit: Limit, state: *State.InFrame) !usize { |
| 145 | const in = d.input; | 151 | const in = d.input; |
| | 152 | const window_len = d.window_len; |
| 146 | | 153 | |
| 147 | const header_bytes = try in.takeArray(3); | 154 | const header_bytes = try in.takeArray(3); |
| 148 | const block_header: Frame.Zstandard.Block.Header = @bitCast(header_bytes.*); | 155 | const block_header: Frame.Zstandard.Block.Header = @bitCast(header_bytes.*); |
| ... | @@ -153,12 +160,12 @@ fn readInFrame(d: *Decompress, w: *Writer, limit: Limit, state: *State.InFrame) | ... | @@ -153,12 +160,12 @@ fn readInFrame(d: *Decompress, w: *Writer, limit: Limit, state: *State.InFrame) |
| 153 | var bytes_written: usize = 0; | 160 | var bytes_written: usize = 0; |
| 154 | switch (block_header.type) { | 161 | switch (block_header.type) { |
| 155 | .raw => { | 162 | .raw => { |
| 156 | try in.streamExact(w, block_size); | 163 | try in.streamExactPreserve(w, window_len, block_size); |
| 157 | bytes_written = block_size; | 164 | bytes_written = block_size; |
| 158 | }, | 165 | }, |
| 159 | .rle => { | 166 | .rle => { |
| 160 | const byte = try in.takeByte(); | 167 | const byte = try in.takeByte(); |
| 161 | try w.splatByteAll(byte, block_size); | 168 | try w.splatBytePreserve(window_len, byte, block_size); |
| 162 | bytes_written = block_size; | 169 | bytes_written = block_size; |
| 163 | }, | 170 | }, |
| 164 | .compressed => { | 171 | .compressed => { |
| ... | @@ -167,7 +174,7 @@ fn readInFrame(d: *Decompress, w: *Writer, limit: Limit, state: *State.InFrame) | ... | @@ -167,7 +174,7 @@ fn readInFrame(d: *Decompress, w: *Writer, limit: Limit, state: *State.InFrame) |
| 167 | var offset_fse_buffer: [zstd.table_size_max.offset]Table.Fse = undefined; | 174 | var offset_fse_buffer: [zstd.table_size_max.offset]Table.Fse = undefined; |
| 168 | var literals_buffer: [zstd.block_size_max]u8 = undefined; | 175 | var literals_buffer: [zstd.block_size_max]u8 = undefined; |
| 169 | var sequence_buffer: [zstd.block_size_max]u8 = undefined; | 176 | var sequence_buffer: [zstd.block_size_max]u8 = undefined; |
| 170 | var decode: Frame.Zstandard.Decode = .init(&literal_fse_buffer, &match_fse_buffer, &offset_fse_buffer); | 177 | var decode: Frame.Zstandard.Decode = .init(&literal_fse_buffer, &match_fse_buffer, &offset_fse_buffer, window_len); |
| 171 | var remaining: Limit = .limited(block_size); | 178 | var remaining: Limit = .limited(block_size); |
| 172 | const literals = try LiteralsSection.decode(in, &remaining, &literals_buffer); | 179 | const literals = try LiteralsSection.decode(in, &remaining, &literals_buffer); |
| 173 | const sequences_header = try SequencesSection.Header.decode(in, &remaining); | 180 | const sequences_header = try SequencesSection.Header.decode(in, &remaining); |
| ... | @@ -185,15 +192,16 @@ fn readInFrame(d: *Decompress, w: *Writer, limit: Limit, state: *State.InFrame) | ... | @@ -185,15 +192,16 @@ fn readInFrame(d: *Decompress, w: *Writer, limit: Limit, state: *State.InFrame) |
| 185 | try decode.readInitialFseState(&bit_stream); | 192 | try decode.readInitialFseState(&bit_stream); |
| 186 | | 193 | |
| 187 | // Ensures the following calls to `decodeSequence` will not flush. | 194 | // Ensures the following calls to `decodeSequence` will not flush. |
| 188 | if (frame_block_size_max > w.buffer.len) return error.OutputBufferUndersize; | 195 | if (window_len + frame_block_size_max > w.buffer.len) return error.OutputBufferUndersize; |
| 189 | const dest = (try w.writableSliceGreedy(frame_block_size_max))[0..frame_block_size_max]; | 196 | const dest = (try w.writableSliceGreedyPreserve(window_len, frame_block_size_max))[0..frame_block_size_max]; |
| | 197 | const write_pos = dest.ptr - w.buffer.ptr; |
| 190 | for (0..sequences_header.sequence_count - 1) |_| { | 198 | for (0..sequences_header.sequence_count - 1) |_| { |
| 191 | bytes_written += try decode.decodeSequence(dest, bytes_written, &bit_stream); | 199 | bytes_written += try decode.decodeSequence(w.buffer, write_pos + bytes_written, &bit_stream); |
| 192 | try decode.updateState(.literal, &bit_stream); | 200 | try decode.updateState(.literal, &bit_stream); |
| 193 | try decode.updateState(.match, &bit_stream); | 201 | try decode.updateState(.match, &bit_stream); |
| 194 | try decode.updateState(.offset, &bit_stream); | 202 | try decode.updateState(.offset, &bit_stream); |
| 195 | } | 203 | } |
| 196 | bytes_written += try decode.decodeSequence(dest, bytes_written, &bit_stream); | 204 | bytes_written += try decode.decodeSequence(w.buffer, write_pos + bytes_written, &bit_stream); |
| 197 | if (bytes_written > dest.len) return error.MalformedSequence; | 205 | if (bytes_written > dest.len) return error.MalformedSequence; |
| 198 | w.advance(bytes_written); | 206 | w.advance(bytes_written); |
| 199 | } | 207 | } |
| ... | @@ -363,6 +371,7 @@ pub const Frame = struct { | ... | @@ -363,6 +371,7 @@ pub const Frame = struct { |
| 363 | }; | 371 | }; |
| 364 | | 372 | |
| 365 | pub const Decode = struct { | 373 | pub const Decode = struct { |
| | 374 | window_len: u32, |
| 366 | repeat_offsets: [3]u32, | 375 | repeat_offsets: [3]u32, |
| 367 | | 376 | |
| 368 | offset: StateData(8), | 377 | offset: StateData(8), |
| ... | @@ -397,8 +406,10 @@ pub const Frame = struct { | ... | @@ -397,8 +406,10 @@ pub const Frame = struct { |
| 397 | literal_fse_buffer: []Table.Fse, | 406 | literal_fse_buffer: []Table.Fse, |
| 398 | match_fse_buffer: []Table.Fse, | 407 | match_fse_buffer: []Table.Fse, |
| 399 | offset_fse_buffer: []Table.Fse, | 408 | offset_fse_buffer: []Table.Fse, |
| | 409 | window_len: u32, |
| 400 | ) Decode { | 410 | ) Decode { |
| 401 | return .{ | 411 | return .{ |
| | 412 | .window_len = window_len, |
| 402 | .repeat_offsets = .{ | 413 | .repeat_offsets = .{ |
| 403 | zstd.start_repeated_offset_1, | 414 | zstd.start_repeated_offset_1, |
| 404 | zstd.start_repeated_offset_2, | 415 | zstd.start_repeated_offset_2, |
| ... | @@ -698,19 +709,19 @@ pub const Frame = struct { | ... | @@ -698,19 +709,19 @@ pub const Frame = struct { |
| 698 | }; | 709 | }; |
| 699 | } | 710 | } |
| 700 | | 711 | |
| 701 | /// Decode `len` bytes of literals into `dest`. | 712 | /// Decode `len` bytes of literals into `w`. |
| 702 | fn decodeLiterals(self: *Decode, dest: *Writer, len: usize) !void { | 713 | fn decodeLiterals(d: *Decode, w: *Writer, len: usize) !void { |
| 703 | switch (self.literal_header.block_type) { | 714 | switch (d.literal_header.block_type) { |
| 704 | .raw => { | 715 | .raw => { |
| 705 | try dest.writeAll(self.literal_streams.one[self.literal_written_count..][0..len]); | 716 | try w.writeAll(d.literal_streams.one[d.literal_written_count..][0..len]); |
| 706 | }, | 717 | }, |
| 707 | .rle => { | 718 | .rle => { |
| 708 | try dest.splatByteAll(self.literal_streams.one[0], len); | 719 | try w.splatByteAll(d.literal_streams.one[0], len); |
| 709 | }, | 720 | }, |
| 710 | .compressed, .treeless => { | 721 | .compressed, .treeless => { |
| 711 | if (len > dest.buffer.len) return error.OutputBufferUndersize; | 722 | if (len > w.buffer.len) return error.OutputBufferUndersize; |
| 712 | const buf = try dest.writableSlice(len); | 723 | const buf = try w.writableSlice(len); |
| 713 | const huffman_tree = self.huffman_tree.?; | 724 | const huffman_tree = d.huffman_tree.?; |
| 714 | const max_bit_count = huffman_tree.max_bit_count; | 725 | const max_bit_count = huffman_tree.max_bit_count; |
| 715 | const starting_bit_count = LiteralsSection.HuffmanTree.weightToBitCount( | 726 | const starting_bit_count = LiteralsSection.HuffmanTree.weightToBitCount( |
| 716 | huffman_tree.nodes[huffman_tree.symbol_count_minus_one].weight, | 727 | huffman_tree.nodes[huffman_tree.symbol_count_minus_one].weight, |
| ... | @@ -722,7 +733,7 @@ pub const Frame = struct { | ... | @@ -722,7 +733,7 @@ pub const Frame = struct { |
| 722 | for (buf) |*out| { | 733 | for (buf) |*out| { |
| 723 | var prefix: u16 = 0; | 734 | var prefix: u16 = 0; |
| 724 | while (true) { | 735 | while (true) { |
| 725 | const new_bits = try self.readLiteralsBits(bit_count_to_read); | 736 | const new_bits = try d.readLiteralsBits(bit_count_to_read); |
| 726 | prefix <<= bit_count_to_read; | 737 | prefix <<= bit_count_to_read; |
| 727 | prefix |= new_bits; | 738 | prefix |= new_bits; |
| 728 | bits_read += bit_count_to_read; | 739 | bits_read += bit_count_to_read; |