| ... | @@ -8,10 +8,14 @@ pub const compressed_block = types.compressed_block; | ... | @@ -8,10 +8,14 @@ pub const compressed_block = types.compressed_block; |
| 8 | | 8 | |
| 9 | pub const decompress = @import("zstandard/decompress.zig"); | 9 | pub const decompress = @import("zstandard/decompress.zig"); |
| 10 | | 10 | |
| | 11 | pub const DecompressStreamOptions = struct { |
| | 12 | verify_checksum: bool = true, |
| | 13 | window_size_max: usize = 1 << 23, // 8MiB default maximum window size, |
| | 14 | }; |
| | 15 | |
| 11 | pub fn DecompressStream( | 16 | pub fn DecompressStream( |
| 12 | comptime ReaderType: type, | 17 | comptime ReaderType: type, |
| 13 | comptime verify_checksum: bool, | 18 | comptime options: DecompressStreamOptions, |
| 14 | comptime window_size_max: usize, | | |
| 15 | ) type { | 19 | ) type { |
| 16 | return struct { | 20 | return struct { |
| 17 | const Self = @This(); | 21 | const Self = @This(); |
| ... | @@ -27,7 +31,7 @@ pub fn DecompressStream( | ... | @@ -27,7 +31,7 @@ pub fn DecompressStream( |
| 27 | offset_fse_buffer: []types.compressed_block.Table.Fse, | 31 | offset_fse_buffer: []types.compressed_block.Table.Fse, |
| 28 | literals_buffer: []u8, | 32 | literals_buffer: []u8, |
| 29 | sequence_buffer: []u8, | 33 | sequence_buffer: []u8, |
| 30 | checksum: if (verify_checksum) ?u32 else void, | 34 | checksum: if (options.verify_checksum) ?u32 else void, |
| 31 | current_frame_decompressed_size: usize, | 35 | current_frame_decompressed_size: usize, |
| 32 | | 36 | |
| 33 | pub const Error = ReaderType.Error || error{ | 37 | pub const Error = ReaderType.Error || error{ |
| ... | @@ -69,8 +73,8 @@ pub fn DecompressStream( | ... | @@ -69,8 +73,8 @@ pub fn DecompressStream( |
| 69 | const frame_context = context: { | 73 | const frame_context = context: { |
| 70 | break :context try decompress.FrameContext.init( | 74 | break :context try decompress.FrameContext.init( |
| 71 | header, | 75 | header, |
| 72 | window_size_max, | 76 | options.window_size_max, |
| 73 | verify_checksum, | 77 | options.verify_checksum, |
| 74 | ); | 78 | ); |
| 75 | }; | 79 | }; |
| 76 | | 80 | |
| ... | @@ -99,10 +103,10 @@ pub fn DecompressStream( | ... | @@ -99,10 +103,10 @@ pub fn DecompressStream( |
| 99 | ); | 103 | ); |
| 100 | const buffer = try RingBuffer.init(self.allocator, frame_context.window_size); | 104 | const buffer = try RingBuffer.init(self.allocator, frame_context.window_size); |
| 101 | | 105 | |
| 102 | const literals_data = try self.allocator.alloc(u8, window_size_max); | 106 | const literals_data = try self.allocator.alloc(u8, options.window_size_max); |
| 103 | errdefer self.allocator.free(literals_data); | 107 | errdefer self.allocator.free(literals_data); |
| 104 | | 108 | |
| 105 | const sequence_data = try self.allocator.alloc(u8, window_size_max); | 109 | const sequence_data = try self.allocator.alloc(u8, options.window_size_max); |
| 106 | errdefer self.allocator.free(sequence_data); | 110 | errdefer self.allocator.free(sequence_data); |
| 107 | | 111 | |
| 108 | self.literal_fse_buffer = literal_fse_buffer; | 112 | self.literal_fse_buffer = literal_fse_buffer; |
| ... | @@ -116,7 +120,7 @@ pub fn DecompressStream( | ... | @@ -116,7 +120,7 @@ pub fn DecompressStream( |
| 116 | self.decode_state = decode_state; | 120 | self.decode_state = decode_state; |
| 117 | self.frame_context = frame_context; | 121 | self.frame_context = frame_context; |
| 118 | | 122 | |
| 119 | self.checksum = if (verify_checksum) null else {}; | 123 | self.checksum = if (options.verify_checksum) null else {}; |
| 120 | self.current_frame_decompressed_size = 0; | 124 | self.current_frame_decompressed_size = 0; |
| 121 | | 125 | |
| 122 | self.state = .InFrame; | 126 | self.state = .InFrame; |
| ... | @@ -199,7 +203,7 @@ pub fn DecompressStream( | ... | @@ -199,7 +203,7 @@ pub fn DecompressStream( |
| 199 | if (self.frame_context.has_checksum) { | 203 | if (self.frame_context.has_checksum) { |
| 200 | const checksum = source_reader.readIntLittle(u32) catch | 204 | const checksum = source_reader.readIntLittle(u32) catch |
| 201 | return error.MalformedFrame; | 205 | return error.MalformedFrame; |
| 202 | if (comptime verify_checksum) { | 206 | if (comptime options.verify_checksum) { |
| 203 | if (self.frame_context.hasher_opt) |*hasher| { | 207 | if (self.frame_context.hasher_opt) |*hasher| { |
| 204 | if (checksum != decompress.computeChecksum(hasher)) | 208 | if (checksum != decompress.computeChecksum(hasher)) |
| 205 | return error.ChecksumFailure; | 209 | return error.ChecksumFailure; |
| ... | @@ -232,17 +236,24 @@ pub fn DecompressStream( | ... | @@ -232,17 +236,24 @@ pub fn DecompressStream( |
| 232 | }; | 236 | }; |
| 233 | } | 237 | } |
| 234 | | 238 | |
| | 239 | pub fn decompressStreamOptions( |
| | 240 | allocator: Allocator, |
| | 241 | reader: anytype, |
| | 242 | comptime options: DecompressStreamOptions, |
| | 243 | ) DecompressStream(@TypeOf(reader, options)) { |
| | 244 | return DecompressStream(@TypeOf(reader), options).init(allocator, reader); |
| | 245 | } |
| | 246 | |
| 235 | pub fn decompressStream( | 247 | pub fn decompressStream( |
| 236 | allocator: Allocator, | 248 | allocator: Allocator, |
| 237 | reader: anytype, | 249 | reader: anytype, |
| 238 | comptime window_size_max: usize, | 250 | ) DecompressStream(@TypeOf(reader), .{}) { |
| 239 | ) DecompressStream(@TypeOf(reader), true, window_size_max) { | 251 | return DecompressStream(@TypeOf(reader), .{}).init(allocator, reader); |
| 240 | return DecompressStream(@TypeOf(reader), true, 8 * (1 << 20)).init(allocator, reader); | | |
| 241 | } | 252 | } |
| 242 | | 253 | |
| 243 | fn testDecompress(data: []const u8) ![]u8 { | 254 | fn testDecompress(data: []const u8) ![]u8 { |
| 244 | var in_stream = std.io.fixedBufferStream(data); | 255 | var in_stream = std.io.fixedBufferStream(data); |
| 245 | var zstd_stream = decompressStream(std.testing.allocator, in_stream.reader(), 1 << 23); | 256 | var zstd_stream = decompressStream(std.testing.allocator, in_stream.reader()); |
| 246 | defer zstd_stream.deinit(); | 257 | defer zstd_stream.deinit(); |
| 247 | const result = zstd_stream.reader().readAllAlloc(std.testing.allocator, std.math.maxInt(usize)); | 258 | const result = zstd_stream.reader().readAllAlloc(std.testing.allocator, std.math.maxInt(usize)); |
| 248 | return result; | 259 | return result; |