authorgravatar for igor.anic@gmail.comIgor Anić <igor.anic@gmail.com> 2024-02-14 23:34:13+01:00
committergravatar for igor.anic@gmail.comIgor Anić <igor.anic@gmail.com> 2024-02-14 23:34:13+01:00
logfd9db4962c3b06630c6b482e027a8babee9f12cb
tree73c6ad1637cce5ec9f63868e9d722f76d8589a8c
parent2457b68b2f008e7dfac6829c4ad7cfbb96e94c68

reorganize compress package root folder


8 files changed, 611 insertions(+), 616 deletions(-)

lib/std/compress.zig+3-4
...@@ -1,14 +1,13 @@...@@ -1,14 +1,13 @@
1const std = @import("std.zig");1const std = @import("std.zig");
22
3pub const flate = @import("compress/flate.zig");
4pub const gzip = @import("compress/gzip.zig");
5pub const zlib = @import("compress/zlib.zig");
3pub const lzma = @import("compress/lzma.zig");6pub const lzma = @import("compress/lzma.zig");
4pub const lzma2 = @import("compress/lzma2.zig");7pub const lzma2 = @import("compress/lzma2.zig");
5pub const xz = @import("compress/xz.zig");8pub const xz = @import("compress/xz.zig");
6pub const zstd = @import("compress/zstandard.zig");9pub const zstd = @import("compress/zstandard.zig");
710
8pub const flate = @import("compress/flate/root.zig").flate;
9pub const gzip = @import("compress/flate/root.zig").gzip;
10pub const zlib = @import("compress/flate/root.zig").zlib;
11
12pub fn HashedReader(11pub fn HashedReader(
13 comptime ReaderType: anytype,12 comptime ReaderType: anytype,
14 comptime HasherType: anytype,13 comptime HasherType: anytype,
lib/std/compress/flate.zig created+476
...@@ -0,0 +1,476 @@
1/// Deflate is a lossless data compression file format that uses a combination
2/// of LZ77 and Huffman coding.
3pub const deflate = @import("flate/deflate.zig");
4
5/// Inflate is the decoding process that takes a Deflate bitstream for
6/// decompression and correctly produces the original full-size data or file.
7pub const inflate = @import("flate/inflate.zig");
8
9/// Decompress compressed data from reader and write plain data to the writer.
10pub fn decompress(reader: anytype, writer: anytype) !void {
11 try inflate.decompress(.raw, reader, writer);
12}
13
14/// Decompressor type
15pub fn Decompressor(comptime ReaderType: type) type {
16 return inflate.Inflate(.raw, ReaderType);
17}
18
19/// Create Decompressor which will read compressed data from reader.
20pub fn decompressor(reader: anytype) Decompressor(@TypeOf(reader)) {
21 return inflate.decompressor(.raw, reader);
22}
23
24/// Compression level, trades between speed and compression size.
25pub const Options = deflate.Options;
26
27/// Compress plain data from reader and write compressed data to the writer.
28pub fn compress(reader: anytype, writer: anytype, options: Options) !void {
29 try deflate.compress(.raw, reader, writer, options);
30}
31
32/// Compressor type
33pub fn Compressor(comptime WriterType: type) type {
34 return deflate.Compressor(.raw, WriterType);
35}
36
37/// Create Compressor which outputs compressed data to the writer.
38pub fn compressor(writer: anytype, options: Options) !Compressor(@TypeOf(writer)) {
39 return try deflate.compressor(.raw, writer, options);
40}
41
42/// Huffman only compression. Without Lempel-Ziv match searching. Faster
43/// compression, less memory requirements but bigger compressed sizes.
44pub const huffman = struct {
45 pub fn compress(reader: anytype, writer: anytype) !void {
46 try deflate.huffman.compress(.raw, reader, writer);
47 }
48
49 pub fn Compressor(comptime WriterType: type) type {
50 return deflate.huffman.Compressor(.raw, WriterType);
51 }
52
53 pub fn compressor(writer: anytype) !huffman.Compressor(@TypeOf(writer)) {
54 return deflate.huffman.compressor(.raw, writer);
55 }
56};
57
58// No compression store only. Compressed size is slightly bigger than plain.
59pub const store = struct {
60 pub fn compress(reader: anytype, writer: anytype) !void {
61 try deflate.store.compress(.raw, reader, writer);
62 }
63
64 pub fn Compressor(comptime WriterType: type) type {
65 return deflate.store.Compressor(.raw, WriterType);
66 }
67
68 pub fn compressor(writer: anytype) !store.Compressor(@TypeOf(writer)) {
69 return deflate.store.compressor(.raw, writer);
70 }
71};
72
73/// Container defines header/footer arround deflate bit stream. Gzip and zlib
74/// compression algorithms are containers arround deflate bit stream body.
75const Container = @import("flate/container.zig").Container;
76const std = @import("std");
77const testing = std.testing;
78const fixedBufferStream = std.io.fixedBufferStream;
79const print = std.debug.print;
80
81test "flate" {
82 _ = @import("flate/deflate.zig");
83 _ = @import("flate/inflate.zig");
84}
85
86test "flate compress/decompress" {
87 var cmp_buf: [64 * 1024]u8 = undefined; // compressed data buffer
88 var dcm_buf: [64 * 1024]u8 = undefined; // decompressed data buffer
89
90 const levels = [_]deflate.Level{ .level_4, .level_5, .level_6, .level_7, .level_8, .level_9 };
91 const cases = [_]struct {
92 data: []const u8, // uncompressed content
93 // compressed data sizes per level 4-9
94 gzip_sizes: [levels.len]usize = [_]usize{0} ** levels.len,
95 huffman_only_size: usize = 0,
96 store_size: usize = 0,
97 }{
98 .{
99 .data = @embedFile("flate/testdata/rfc1951.txt"),
100 .gzip_sizes = [_]usize{ 11513, 11217, 11139, 11126, 11122, 11119 },
101 .huffman_only_size = 20287,
102 .store_size = 36967,
103 },
104 .{
105 .data = @embedFile("flate/testdata/fuzz/roundtrip1.input"),
106 .gzip_sizes = [_]usize{ 373, 370, 370, 370, 370, 370 },
107 .huffman_only_size = 393,
108 .store_size = 393,
109 },
110 .{
111 .data = @embedFile("flate/testdata/fuzz/roundtrip2.input"),
112 .gzip_sizes = [_]usize{ 373, 373, 373, 373, 373, 373 },
113 .huffman_only_size = 394,
114 .store_size = 394,
115 },
116 .{
117 .data = @embedFile("flate/testdata/fuzz/deflate-stream.expect"),
118 .gzip_sizes = [_]usize{ 351, 347, 347, 347, 347, 347 },
119 .huffman_only_size = 498,
120 .store_size = 747,
121 },
122 };
123
124 for (cases, 0..) |case, case_no| { // for each case
125 const data = case.data;
126
127 for (levels, 0..) |level, i| { // for each compression level
128
129 inline for (Container.list) |container| { // for each wrapping
130 var compressed_size: usize = if (case.gzip_sizes[i] > 0)
131 case.gzip_sizes[i] - Container.gzip.size() + container.size()
132 else
133 0;
134
135 // compress original stream to compressed stream
136 {
137 var original = fixedBufferStream(data);
138 var compressed = fixedBufferStream(&cmp_buf);
139 try deflate.compress(container, original.reader(), compressed.writer(), .{ .level = level });
140 if (compressed_size == 0) {
141 if (container == .gzip)
142 print("case {d} gzip level {} compressed size: {d}\n", .{ case_no, level, compressed.pos });
143 compressed_size = compressed.pos;
144 }
145 try testing.expectEqual(compressed_size, compressed.pos);
146 }
147 // decompress compressed stream to decompressed stream
148 {
149 var compressed = fixedBufferStream(cmp_buf[0..compressed_size]);
150 var decompressed = fixedBufferStream(&dcm_buf);
151 try inflate.decompress(container, compressed.reader(), decompressed.writer());
152 try testing.expectEqualSlices(u8, data, decompressed.getWritten());
153 }
154
155 // compressor writer interface
156 {
157 var compressed = fixedBufferStream(&cmp_buf);
158 var cmp = try deflate.compressor(container, compressed.writer(), .{ .level = level });
159 var cmp_wrt = cmp.writer();
160 try cmp_wrt.writeAll(data);
161 try cmp.finish();
162
163 try testing.expectEqual(compressed_size, compressed.pos);
164 }
165 // decompressor reader interface
166 {
167 var compressed = fixedBufferStream(cmp_buf[0..compressed_size]);
168 var dcm = inflate.decompressor(container, compressed.reader());
169 var dcm_rdr = dcm.reader();
170 const n = try dcm_rdr.readAll(&dcm_buf);
171 try testing.expectEqual(data.len, n);
172 try testing.expectEqualSlices(u8, data, dcm_buf[0..n]);
173 }
174 }
175 }
176 // huffman only compression
177 {
178 inline for (Container.list) |container| { // for each wrapping
179 var compressed_size: usize = if (case.huffman_only_size > 0)
180 case.huffman_only_size - Container.gzip.size() + container.size()
181 else
182 0;
183
184 // compress original stream to compressed stream
185 {
186 var original = fixedBufferStream(data);
187 var compressed = fixedBufferStream(&cmp_buf);
188 var cmp = try deflate.huffman.compressor(container, compressed.writer());
189 try cmp.compress(original.reader());
190 try cmp.finish();
191 if (compressed_size == 0) {
192 if (container == .gzip)
193 print("case {d} huffman only compressed size: {d}\n", .{ case_no, compressed.pos });
194 compressed_size = compressed.pos;
195 }
196 try testing.expectEqual(compressed_size, compressed.pos);
197 }
198 // decompress compressed stream to decompressed stream
199 {
200 var compressed = fixedBufferStream(cmp_buf[0..compressed_size]);
201 var decompressed = fixedBufferStream(&dcm_buf);
202 try inflate.decompress(container, compressed.reader(), decompressed.writer());
203 try testing.expectEqualSlices(u8, data, decompressed.getWritten());
204 }
205 }
206 }
207
208 // store only
209 {
210 inline for (Container.list) |container| { // for each wrapping
211 var compressed_size: usize = if (case.store_size > 0)
212 case.store_size - Container.gzip.size() + container.size()
213 else
214 0;
215
216 // compress original stream to compressed stream
217 {
218 var original = fixedBufferStream(data);
219 var compressed = fixedBufferStream(&cmp_buf);
220 var cmp = try deflate.store.compressor(container, compressed.writer());
221 try cmp.compress(original.reader());
222 try cmp.finish();
223 if (compressed_size == 0) {
224 if (container == .gzip)
225 print("case {d} store only compressed size: {d}\n", .{ case_no, compressed.pos });
226 compressed_size = compressed.pos;
227 }
228
229 try testing.expectEqual(compressed_size, compressed.pos);
230 }
231 // decompress compressed stream to decompressed stream
232 {
233 var compressed = fixedBufferStream(cmp_buf[0..compressed_size]);
234 var decompressed = fixedBufferStream(&dcm_buf);
235 try inflate.decompress(container, compressed.reader(), decompressed.writer());
236 try testing.expectEqualSlices(u8, data, decompressed.getWritten());
237 }
238 }
239 }
240 }
241}
242
243fn testDecompress(comptime container: Container, compressed: []const u8, expected_plain: []const u8) !void {
244 var in = fixedBufferStream(compressed);
245 var out = std.ArrayList(u8).init(testing.allocator);
246 defer out.deinit();
247
248 try inflate.decompress(container, in.reader(), out.writer());
249 try testing.expectEqualSlices(u8, expected_plain, out.items);
250}
251
252test "flate don't read past deflate stream's end" {
253 try testDecompress(.zlib, &[_]u8{
254 0x08, 0xd7, 0x63, 0xf8, 0xcf, 0xc0, 0xc0, 0x00, 0xc1, 0xff,
255 0xff, 0x43, 0x30, 0x03, 0x03, 0xc3, 0xff, 0xff, 0xff, 0x01,
256 0x83, 0x95, 0x0b, 0xf5,
257 }, &[_]u8{
258 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff,
259 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00,
260 0x00, 0x00, 0xff, 0xff, 0xff,
261 });
262}
263
264test "flate zlib header" {
265 // Truncated header
266 try testing.expectError(
267 error.EndOfStream,
268 testDecompress(.zlib, &[_]u8{0x78}, ""),
269 );
270 // Wrong CM
271 try testing.expectError(
272 error.BadZlibHeader,
273 testDecompress(.zlib, &[_]u8{ 0x79, 0x94 }, ""),
274 );
275 // Wrong CINFO
276 try testing.expectError(
277 error.BadZlibHeader,
278 testDecompress(.zlib, &[_]u8{ 0x88, 0x98 }, ""),
279 );
280 // Wrong checksum
281 try testing.expectError(
282 error.WrongZlibChecksum,
283 testDecompress(.zlib, &[_]u8{ 0x78, 0xda, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00 }, ""),
284 );
285 // Truncated checksum
286 try testing.expectError(
287 error.EndOfStream,
288 testDecompress(.zlib, &[_]u8{ 0x78, 0xda, 0x03, 0x00, 0x00 }, ""),
289 );
290}
291
292test "flate gzip header" {
293 // Truncated header
294 try testing.expectError(
295 error.EndOfStream,
296 testDecompress(.gzip, &[_]u8{ 0x1f, 0x8B }, undefined),
297 );
298 // Wrong CM
299 try testing.expectError(
300 error.BadGzipHeader,
301 testDecompress(.gzip, &[_]u8{
302 0x1f, 0x8b, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00,
303 0x00, 0x03,
304 }, undefined),
305 );
306
307 // Wrong checksum
308 try testing.expectError(
309 error.WrongGzipChecksum,
310 testDecompress(.gzip, &[_]u8{
311 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00,
312 0x00, 0x03, 0x03, 0x00, 0x00, 0x00, 0x00, 0x01,
313 0x00, 0x00, 0x00, 0x00,
314 }, undefined),
315 );
316 // Truncated checksum
317 try testing.expectError(
318 error.EndOfStream,
319 testDecompress(.gzip, &[_]u8{
320 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00,
321 0x00, 0x03, 0x03, 0x00, 0x00, 0x00, 0x00,
322 }, undefined),
323 );
324 // Wrong initial size
325 try testing.expectError(
326 error.WrongGzipSize,
327 testDecompress(.gzip, &[_]u8{
328 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00,
329 0x00, 0x03, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00,
330 0x00, 0x00, 0x00, 0x01,
331 }, undefined),
332 );
333 // Truncated initial size field
334 try testing.expectError(
335 error.EndOfStream,
336 testDecompress(.gzip, &[_]u8{
337 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00,
338 0x00, 0x03, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00,
339 0x00, 0x00, 0x00,
340 }, undefined),
341 );
342
343 try testDecompress(.gzip, &[_]u8{
344 // GZIP header
345 0x1f, 0x8b, 0x08, 0x12, 0x00, 0x09, 0x6e, 0x88, 0x00, 0xff, 0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x00,
346 // header.FHCRC (should cover entire header)
347 0x99, 0xd6,
348 // GZIP data
349 0x01, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
350 }, "");
351}
352
353test "flate public interface" {
354 const plain_data = [_]u8{ 'H', 'e', 'l', 'l', 'o', ' ', 'w', 'o', 'r', 'l', 'd', 0x0a };
355
356 // deflate final stored block, header + plain (stored) data
357 const deflate_block = [_]u8{
358 0b0000_0001, 0b0000_1100, 0x00, 0b1111_0011, 0xff, // deflate fixed buffer header len, nlen
359 } ++ plain_data;
360
361 // gzip header/footer + deflate block
362 const gzip_data =
363 [_]u8{ 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03 } ++ // gzip header (10 bytes)
364 deflate_block ++
365 [_]u8{ 0xd5, 0xe0, 0x39, 0xb7, 0x0c, 0x00, 0x00, 0x00 }; // gzip footer checksum (4 byte), size (4 bytes)
366
367 // zlib header/footer + deflate block
368 const zlib_data = [_]u8{ 0x78, 0b10_0_11100 } ++ // zlib header (2 bytes)}
369 deflate_block ++
370 [_]u8{ 0x1c, 0xf2, 0x04, 0x47 }; // zlib footer: checksum
371
372 const gzip = @import("gzip.zig");
373 const zlib = @import("zlib.zig");
374 const flate = @This();
375
376 try testInterface(gzip, &gzip_data, &plain_data);
377 try testInterface(zlib, &zlib_data, &plain_data);
378 try testInterface(flate, &deflate_block, &plain_data);
379}
380
381fn testInterface(comptime pkg: type, gzip_data: []const u8, plain_data: []const u8) !void {
382 var buffer1: [64]u8 = undefined;
383 var buffer2: [64]u8 = undefined;
384
385 var compressed = fixedBufferStream(&buffer1);
386 var plain = fixedBufferStream(&buffer2);
387
388 // decompress
389 {
390 var in = fixedBufferStream(gzip_data);
391 try pkg.decompress(in.reader(), plain.writer());
392 try testing.expectEqualSlices(u8, plain_data, plain.getWritten());
393 }
394 plain.reset();
395 compressed.reset();
396
397 // compress/decompress
398 {
399 var in = fixedBufferStream(plain_data);
400 try pkg.compress(in.reader(), compressed.writer(), .{});
401 compressed.reset();
402 try pkg.decompress(compressed.reader(), plain.writer());
403 try testing.expectEqualSlices(u8, plain_data, plain.getWritten());
404 }
405 plain.reset();
406 compressed.reset();
407
408 // compressor/decompressor
409 {
410 var in = fixedBufferStream(plain_data);
411 var cmp = try pkg.compressor(compressed.writer(), .{});
412 try cmp.compress(in.reader());
413 try cmp.finish();
414
415 compressed.reset();
416 var dcp = pkg.decompressor(compressed.reader());
417 try dcp.decompress(plain.writer());
418 try testing.expectEqualSlices(u8, plain_data, plain.getWritten());
419 }
420 plain.reset();
421 compressed.reset();
422
423 // huffman
424 {
425 // huffman compress/decompress
426 {
427 var in = fixedBufferStream(plain_data);
428 try pkg.huffman.compress(in.reader(), compressed.writer());
429 compressed.reset();
430 try pkg.decompress(compressed.reader(), plain.writer());
431 try testing.expectEqualSlices(u8, plain_data, plain.getWritten());
432 }
433 plain.reset();
434 compressed.reset();
435
436 // huffman compressor/decompressor
437 {
438 var in = fixedBufferStream(plain_data);
439 var cmp = try pkg.huffman.compressor(compressed.writer());
440 try cmp.compress(in.reader());
441 try cmp.finish();
442
443 compressed.reset();
444 try pkg.decompress(compressed.reader(), plain.writer());
445 try testing.expectEqualSlices(u8, plain_data, plain.getWritten());
446 }
447 }
448 plain.reset();
449 compressed.reset();
450
451 // store
452 {
453 // store compress/decompress
454 {
455 var in = fixedBufferStream(plain_data);
456 try pkg.store.compress(in.reader(), compressed.writer());
457 compressed.reset();
458 try pkg.decompress(compressed.reader(), plain.writer());
459 try testing.expectEqualSlices(u8, plain_data, plain.getWritten());
460 }
461 plain.reset();
462 compressed.reset();
463
464 // store compressor/decompressor
465 {
466 var in = fixedBufferStream(plain_data);
467 var cmp = try pkg.store.compressor(compressed.writer());
468 try cmp.compress(in.reader());
469 try cmp.finish();
470
471 compressed.reset();
472 try pkg.decompress(compressed.reader(), plain.writer());
473 try testing.expectEqualSlices(u8, plain_data, plain.getWritten());
474 }
475 }
476}
lib/std/compress/flate/flate.zig deleted-347
...@@ -1,347 +0,0 @@
1/// Deflate is a lossless data compression file format that uses a combination
2/// of LZ77 and Huffman coding.
3pub const deflate = @import("deflate.zig");
4
5/// Inflate is the decoding process that takes a Deflate bitstream for
6/// decompression and correctly produces the original full-size data or file.
7pub const inflate = @import("inflate.zig");
8
9/// Decompress compressed data from reader and write plain data to the writer.
10pub fn decompress(reader: anytype, writer: anytype) !void {
11 try inflate.decompress(.raw, reader, writer);
12}
13
14/// Decompressor type
15pub fn Decompressor(comptime ReaderType: type) type {
16 return inflate.Inflate(.raw, ReaderType);
17}
18
19/// Create Decompressor which will read compressed data from reader.
20pub fn decompressor(reader: anytype) Decompressor(@TypeOf(reader)) {
21 return inflate.decompressor(.raw, reader);
22}
23
24/// Compression level, trades between speed and compression size.
25pub const Options = deflate.Options;
26
27/// Compress plain data from reader and write compressed data to the writer.
28pub fn compress(reader: anytype, writer: anytype, options: Options) !void {
29 try deflate.compress(.raw, reader, writer, options);
30}
31
32/// Compressor type
33pub fn Compressor(comptime WriterType: type) type {
34 return deflate.Compressor(.raw, WriterType);
35}
36
37/// Create Compressor which outputs compressed data to the writer.
38pub fn compressor(writer: anytype, options: Options) !Compressor(@TypeOf(writer)) {
39 return try deflate.compressor(.raw, writer, options);
40}
41
42/// Huffman only compression. Without Lempel-Ziv match searching. Faster
43/// compression, less memory requirements but bigger compressed sizes.
44pub const huffman = struct {
45 pub fn compress(reader: anytype, writer: anytype) !void {
46 try deflate.huffman.compress(.raw, reader, writer);
47 }
48
49 pub fn Compressor(comptime WriterType: type) type {
50 return deflate.huffman.Compressor(.raw, WriterType);
51 }
52
53 pub fn compressor(writer: anytype) !huffman.Compressor(@TypeOf(writer)) {
54 return deflate.huffman.compressor(.raw, writer);
55 }
56};
57
58// No compression store only. Compressed size is slightly bigger than plain.
59pub const store = struct {
60 pub fn compress(reader: anytype, writer: anytype) !void {
61 try deflate.store.compress(.raw, reader, writer);
62 }
63
64 pub fn Compressor(comptime WriterType: type) type {
65 return deflate.store.Compressor(.raw, WriterType);
66 }
67
68 pub fn compressor(writer: anytype) !store.Compressor(@TypeOf(writer)) {
69 return deflate.store.compressor(.raw, writer);
70 }
71};
72
73/// Container defines header/footer arround deflate bit stream. Gzip and zlib
74/// compression algorithms are containers arround deflate bit stream body.
75const Container = @import("container.zig").Container;
76const std = @import("std");
77const testing = std.testing;
78const fixedBufferStream = std.io.fixedBufferStream;
79const print = std.debug.print;
80
81test "flate compress/decompress" {
82 var cmp_buf: [64 * 1024]u8 = undefined; // compressed data buffer
83 var dcm_buf: [64 * 1024]u8 = undefined; // decompressed data buffer
84
85 const levels = [_]deflate.Level{ .level_4, .level_5, .level_6, .level_7, .level_8, .level_9 };
86 const cases = [_]struct {
87 data: []const u8, // uncompressed content
88 // compressed data sizes per level 4-9
89 gzip_sizes: [levels.len]usize = [_]usize{0} ** levels.len,
90 huffman_only_size: usize = 0,
91 store_size: usize = 0,
92 }{
93 .{
94 .data = @embedFile("testdata/rfc1951.txt"),
95 .gzip_sizes = [_]usize{ 11513, 11217, 11139, 11126, 11122, 11119 },
96 .huffman_only_size = 20287,
97 .store_size = 36967,
98 },
99 .{
100 .data = @embedFile("testdata/fuzz/roundtrip1.input"),
101 .gzip_sizes = [_]usize{ 373, 370, 370, 370, 370, 370 },
102 .huffman_only_size = 393,
103 .store_size = 393,
104 },
105 .{
106 .data = @embedFile("testdata/fuzz/roundtrip2.input"),
107 .gzip_sizes = [_]usize{ 373, 373, 373, 373, 373, 373 },
108 .huffman_only_size = 394,
109 .store_size = 394,
110 },
111 .{
112 .data = @embedFile("testdata/fuzz/deflate-stream.expect"),
113 .gzip_sizes = [_]usize{ 351, 347, 347, 347, 347, 347 },
114 .huffman_only_size = 498,
115 .store_size = 747,
116 },
117 };
118
119 for (cases, 0..) |case, case_no| { // for each case
120 const data = case.data;
121
122 for (levels, 0..) |level, i| { // for each compression level
123
124 inline for (Container.list) |container| { // for each wrapping
125 var compressed_size: usize = if (case.gzip_sizes[i] > 0)
126 case.gzip_sizes[i] - Container.gzip.size() + container.size()
127 else
128 0;
129
130 // compress original stream to compressed stream
131 {
132 var original = fixedBufferStream(data);
133 var compressed = fixedBufferStream(&cmp_buf);
134 try deflate.compress(container, original.reader(), compressed.writer(), .{ .level = level });
135 if (compressed_size == 0) {
136 if (container == .gzip)
137 print("case {d} gzip level {} compressed size: {d}\n", .{ case_no, level, compressed.pos });
138 compressed_size = compressed.pos;
139 }
140 try testing.expectEqual(compressed_size, compressed.pos);
141 }
142 // decompress compressed stream to decompressed stream
143 {
144 var compressed = fixedBufferStream(cmp_buf[0..compressed_size]);
145 var decompressed = fixedBufferStream(&dcm_buf);
146 try inflate.decompress(container, compressed.reader(), decompressed.writer());
147 try testing.expectEqualSlices(u8, data, decompressed.getWritten());
148 }
149
150 // compressor writer interface
151 {
152 var compressed = fixedBufferStream(&cmp_buf);
153 var cmp = try deflate.compressor(container, compressed.writer(), .{ .level = level });
154 var cmp_wrt = cmp.writer();
155 try cmp_wrt.writeAll(data);
156 try cmp.finish();
157
158 try testing.expectEqual(compressed_size, compressed.pos);
159 }
160 // decompressor reader interface
161 {
162 var compressed = fixedBufferStream(cmp_buf[0..compressed_size]);
163 var dcm = inflate.decompressor(container, compressed.reader());
164 var dcm_rdr = dcm.reader();
165 const n = try dcm_rdr.readAll(&dcm_buf);
166 try testing.expectEqual(data.len, n);
167 try testing.expectEqualSlices(u8, data, dcm_buf[0..n]);
168 }
169 }
170 }
171 // huffman only compression
172 {
173 inline for (Container.list) |container| { // for each wrapping
174 var compressed_size: usize = if (case.huffman_only_size > 0)
175 case.huffman_only_size - Container.gzip.size() + container.size()
176 else
177 0;
178
179 // compress original stream to compressed stream
180 {
181 var original = fixedBufferStream(data);
182 var compressed = fixedBufferStream(&cmp_buf);
183 var cmp = try deflate.huffman.compressor(container, compressed.writer());
184 try cmp.compress(original.reader());
185 try cmp.finish();
186 if (compressed_size == 0) {
187 if (container == .gzip)
188 print("case {d} huffman only compressed size: {d}\n", .{ case_no, compressed.pos });
189 compressed_size = compressed.pos;
190 }
191 try testing.expectEqual(compressed_size, compressed.pos);
192 }
193 // decompress compressed stream to decompressed stream
194 {
195 var compressed = fixedBufferStream(cmp_buf[0..compressed_size]);
196 var decompressed = fixedBufferStream(&dcm_buf);
197 try inflate.decompress(container, compressed.reader(), decompressed.writer());
198 try testing.expectEqualSlices(u8, data, decompressed.getWritten());
199 }
200 }
201 }
202
203 // store only
204 {
205 inline for (Container.list) |container| { // for each wrapping
206 var compressed_size: usize = if (case.store_size > 0)
207 case.store_size - Container.gzip.size() + container.size()
208 else
209 0;
210
211 // compress original stream to compressed stream
212 {
213 var original = fixedBufferStream(data);
214 var compressed = fixedBufferStream(&cmp_buf);
215 var cmp = try deflate.store.compressor(container, compressed.writer());
216 try cmp.compress(original.reader());
217 try cmp.finish();
218 if (compressed_size == 0) {
219 if (container == .gzip)
220 print("case {d} store only compressed size: {d}\n", .{ case_no, compressed.pos });
221 compressed_size = compressed.pos;
222 }
223
224 try testing.expectEqual(compressed_size, compressed.pos);
225 }
226 // decompress compressed stream to decompressed stream
227 {
228 var compressed = fixedBufferStream(cmp_buf[0..compressed_size]);
229 var decompressed = fixedBufferStream(&dcm_buf);
230 try inflate.decompress(container, compressed.reader(), decompressed.writer());
231 try testing.expectEqualSlices(u8, data, decompressed.getWritten());
232 }
233 }
234 }
235 }
236}
237
238fn testDecompress(comptime container: Container, compressed: []const u8, expected_plain: []const u8) !void {
239 var in_stream = std.io.fixedBufferStream(compressed);
240 var al = std.ArrayList(u8).init(testing.allocator);
241 defer al.deinit();
242
243 try inflate.decompress(container, in_stream.reader(), al.writer());
244
245 try testing.expectEqualSlices(u8, expected_plain, al.items);
246}
247
248test "flate don't read past deflate stream's end" {
249 try testDecompress(.zlib, &[_]u8{
250 0x08, 0xd7, 0x63, 0xf8, 0xcf, 0xc0, 0xc0, 0x00, 0xc1, 0xff,
251 0xff, 0x43, 0x30, 0x03, 0x03, 0xc3, 0xff, 0xff, 0xff, 0x01,
252 0x83, 0x95, 0x0b, 0xf5,
253 }, &[_]u8{
254 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff,
255 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00,
256 0x00, 0x00, 0xff, 0xff, 0xff,
257 });
258}
259
260test "flate zlib header" {
261 // Truncated header
262 try testing.expectError(
263 error.EndOfStream,
264 testDecompress(.zlib, &[_]u8{0x78}, ""),
265 );
266 // Wrong CM
267 try testing.expectError(
268 error.BadZlibHeader,
269 testDecompress(.zlib, &[_]u8{ 0x79, 0x94 }, ""),
270 );
271 // Wrong CINFO
272 try testing.expectError(
273 error.BadZlibHeader,
274 testDecompress(.zlib, &[_]u8{ 0x88, 0x98 }, ""),
275 );
276 // Wrong checksum
277 try testing.expectError(
278 error.WrongZlibChecksum,
279 testDecompress(.zlib, &[_]u8{ 0x78, 0xda, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00 }, ""),
280 );
281 // Truncated checksum
282 try testing.expectError(
283 error.EndOfStream,
284 testDecompress(.zlib, &[_]u8{ 0x78, 0xda, 0x03, 0x00, 0x00 }, ""),
285 );
286}
287
288test "flate gzip header" {
289 // Truncated header
290 try testing.expectError(
291 error.EndOfStream,
292 testDecompress(.gzip, &[_]u8{ 0x1f, 0x8B }, undefined),
293 );
294 // Wrong CM
295 try testing.expectError(
296 error.BadGzipHeader,
297 testDecompress(.gzip, &[_]u8{
298 0x1f, 0x8b, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00,
299 0x00, 0x03,
300 }, undefined),
301 );
302
303 // Wrong checksum
304 try testing.expectError(
305 error.WrongGzipChecksum,
306 testDecompress(.gzip, &[_]u8{
307 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00,
308 0x00, 0x03, 0x03, 0x00, 0x00, 0x00, 0x00, 0x01,
309 0x00, 0x00, 0x00, 0x00,
310 }, undefined),
311 );
312 // Truncated checksum
313 try testing.expectError(
314 error.EndOfStream,
315 testDecompress(.gzip, &[_]u8{
316 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00,
317 0x00, 0x03, 0x03, 0x00, 0x00, 0x00, 0x00,
318 }, undefined),
319 );
320 // Wrong initial size
321 try testing.expectError(
322 error.WrongGzipSize,
323 testDecompress(.gzip, &[_]u8{
324 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00,
325 0x00, 0x03, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00,
326 0x00, 0x00, 0x00, 0x01,
327 }, undefined),
328 );
329 // Truncated initial size field
330 try testing.expectError(
331 error.EndOfStream,
332 testDecompress(.gzip, &[_]u8{
333 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00,
334 0x00, 0x03, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00,
335 0x00, 0x00, 0x00,
336 }, undefined),
337 );
338
339 try testDecompress(.gzip, &[_]u8{
340 // GZIP header
341 0x1f, 0x8b, 0x08, 0x12, 0x00, 0x09, 0x6e, 0x88, 0x00, 0xff, 0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x00,
342 // header.FHCRC (should cover entire header)
343 0x99, 0xd6,
344 // GZIP data
345 0x01, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
346 }, "");
347}
lib/std/compress/flate/gzip.zig deleted-66
...@@ -1,66 +0,0 @@
1const deflate = @import("deflate.zig");
2const inflate = @import("inflate.zig");
3
4/// Decompress compressed data from reader and write plain data to the writer.
5pub fn decompress(reader: anytype, writer: anytype) !void {
6 try inflate.decompress(.gzip, reader, writer);
7}
8
9/// Decompressor type
10pub fn Decompressor(comptime ReaderType: type) type {
11 return inflate.Inflate(.gzip, ReaderType);
12}
13
14/// Create Decompressor which will read compressed data from reader.
15pub fn decompressor(reader: anytype) Decompressor(@TypeOf(reader)) {
16 return inflate.decompressor(.gzip, reader);
17}
18
19/// Compression level, trades between speed and compression size.
20pub const Options = deflate.Options;
21
22/// Compress plain data from reader and write compressed data to the writer.
23pub fn compress(reader: anytype, writer: anytype, options: Options) !void {
24 try deflate.compress(.gzip, reader, writer, options);
25}
26
27/// Compressor type
28pub fn Compressor(comptime WriterType: type) type {
29 return deflate.Compressor(.gzip, WriterType);
30}
31
32/// Create Compressor which outputs compressed data to the writer.
33pub fn compressor(writer: anytype, options: Options) !Compressor(@TypeOf(writer)) {
34 return try deflate.compressor(.gzip, writer, options);
35}
36
37/// Huffman only compression. Without Lempel-Ziv match searching. Faster
38/// compression, less memory requirements but bigger compressed sizes.
39pub const huffman = struct {
40 pub fn compress(reader: anytype, writer: anytype) !void {
41 try deflate.huffman.compress(.gzip, reader, writer);
42 }
43
44 pub fn Compressor(comptime WriterType: type) type {
45 return deflate.huffman.Compressor(.gzip, WriterType);
46 }
47
48 pub fn compressor(writer: anytype) !huffman.Compressor(@TypeOf(writer)) {
49 return deflate.huffman.compressor(.gzip, writer);
50 }
51};
52
53// No compression store only. Compressed size is slightly bigger than plain.
54pub const store = struct {
55 pub fn compress(reader: anytype, writer: anytype) !void {
56 try deflate.store.compress(.gzip, reader, writer);
57 }
58
59 pub fn Compressor(comptime WriterType: type) type {
60 return deflate.store.Compressor(.gzip, WriterType);
61 }
62
63 pub fn compressor(writer: anytype) !store.Compressor(@TypeOf(writer)) {
64 return deflate.store.compressor(.gzip, writer);
65 }
66};
lib/std/compress/flate/root.zig deleted-133
...@@ -1,133 +0,0 @@
1pub const flate = @import("flate.zig");
2pub const gzip = @import("gzip.zig");
3pub const zlib = @import("zlib.zig");
4
5test "flate" {
6 _ = @import("deflate.zig");
7 _ = @import("inflate.zig");
8}
9
10test "flate public interface" {
11 const plain_data = [_]u8{ 'H', 'e', 'l', 'l', 'o', ' ', 'w', 'o', 'r', 'l', 'd', 0x0a };
12
13 // deflate final stored block, header + plain (stored) data
14 const deflate_block = [_]u8{
15 0b0000_0001, 0b0000_1100, 0x00, 0b1111_0011, 0xff, // deflate fixed buffer header len, nlen
16 } ++ plain_data;
17
18 // gzip header/footer + deflate block
19 const gzip_data =
20 [_]u8{ 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03 } ++ // gzip header (10 bytes)
21 deflate_block ++
22 [_]u8{ 0xd5, 0xe0, 0x39, 0xb7, 0x0c, 0x00, 0x00, 0x00 }; // gzip footer checksum (4 byte), size (4 bytes)
23
24 // zlib header/footer + deflate block
25 const zlib_data = [_]u8{ 0x78, 0b10_0_11100 } ++ // zlib header (2 bytes)}
26 deflate_block ++
27 [_]u8{ 0x1c, 0xf2, 0x04, 0x47 }; // zlib footer: checksum
28
29 try testInterface(gzip, &gzip_data, &plain_data);
30 try testInterface(zlib, &zlib_data, &plain_data);
31 try testInterface(flate, &deflate_block, &plain_data);
32}
33
34fn testInterface(comptime pkg: type, gzip_data: []const u8, plain_data: []const u8) !void {
35 const std = @import("std");
36 const testing = std.testing;
37 const fixedBufferStream = std.io.fixedBufferStream;
38
39 var buffer1: [64]u8 = undefined;
40 var buffer2: [64]u8 = undefined;
41
42 var compressed = fixedBufferStream(&buffer1);
43 var plain = fixedBufferStream(&buffer2);
44
45 // decompress
46 {
47 var in = fixedBufferStream(gzip_data);
48 try pkg.decompress(in.reader(), plain.writer());
49 try testing.expectEqualSlices(u8, plain_data, plain.getWritten());
50 }
51 plain.reset();
52 compressed.reset();
53
54 // compress/decompress
55 {
56 var in = fixedBufferStream(plain_data);
57 try pkg.compress(in.reader(), compressed.writer(), .{});
58 compressed.reset();
59 try pkg.decompress(compressed.reader(), plain.writer());
60 try testing.expectEqualSlices(u8, plain_data, plain.getWritten());
61 }
62 plain.reset();
63 compressed.reset();
64
65 // compressor/decompressor
66 {
67 var in = fixedBufferStream(plain_data);
68 var cmp = try pkg.compressor(compressed.writer(), .{});
69 try cmp.compress(in.reader());
70 try cmp.finish();
71
72 compressed.reset();
73 var dcp = pkg.decompressor(compressed.reader());
74 try dcp.decompress(plain.writer());
75 try testing.expectEqualSlices(u8, plain_data, plain.getWritten());
76 }
77 plain.reset();
78 compressed.reset();
79
80 // huffman
81 {
82 // huffman compress/decompress
83 {
84 var in = fixedBufferStream(plain_data);
85 try pkg.huffman.compress(in.reader(), compressed.writer());
86 compressed.reset();
87 try pkg.decompress(compressed.reader(), plain.writer());
88 try testing.expectEqualSlices(u8, plain_data, plain.getWritten());
89 }
90 plain.reset();
91 compressed.reset();
92
93 // huffman compressor/decompressor
94 {
95 var in = fixedBufferStream(plain_data);
96 var cmp = try pkg.huffman.compressor(compressed.writer());
97 try cmp.compress(in.reader());
98 try cmp.finish();
99
100 compressed.reset();
101 try pkg.decompress(compressed.reader(), plain.writer());
102 try testing.expectEqualSlices(u8, plain_data, plain.getWritten());
103 }
104 }
105 plain.reset();
106 compressed.reset();
107
108 // store
109 {
110 // store compress/decompress
111 {
112 var in = fixedBufferStream(plain_data);
113 try pkg.store.compress(in.reader(), compressed.writer());
114 compressed.reset();
115 try pkg.decompress(compressed.reader(), plain.writer());
116 try testing.expectEqualSlices(u8, plain_data, plain.getWritten());
117 }
118 plain.reset();
119 compressed.reset();
120
121 // store compressor/decompressor
122 {
123 var in = fixedBufferStream(plain_data);
124 var cmp = try pkg.store.compressor(compressed.writer());
125 try cmp.compress(in.reader());
126 try cmp.finish();
127
128 compressed.reset();
129 try pkg.decompress(compressed.reader(), plain.writer());
130 try testing.expectEqualSlices(u8, plain_data, plain.getWritten());
131 }
132 }
133}
lib/std/compress/flate/zlib.zig deleted-66
...@@ -1,66 +0,0 @@
1const deflate = @import("deflate.zig");
2const inflate = @import("inflate.zig");
3
4/// Decompress compressed data from reader and write plain data to the writer.
5pub fn decompress(reader: anytype, writer: anytype) !void {
6 try inflate.decompress(.zlib, reader, writer);
7}
8
9/// Decompressor type
10pub fn Decompressor(comptime ReaderType: type) type {
11 return inflate.Inflate(.zlib, ReaderType);
12}
13
14/// Create Decompressor which will read compressed data from reader.
15pub fn decompressor(reader: anytype) Decompressor(@TypeOf(reader)) {
16 return inflate.decompressor(.zlib, reader);
17}
18
19/// Compression level, trades between speed and compression size.
20pub const Options = deflate.Options;
21
22/// Compress plain data from reader and write compressed data to the writer.
23pub fn compress(reader: anytype, writer: anytype, options: Options) !void {
24 try deflate.compress(.zlib, reader, writer, options);
25}
26
27/// Compressor type
28pub fn Compressor(comptime WriterType: type) type {
29 return deflate.Compressor(.zlib, WriterType);
30}
31
32/// Create Compressor which outputs compressed data to the writer.
33pub fn compressor(writer: anytype, options: Options) !Compressor(@TypeOf(writer)) {
34 return try deflate.compressor(.zlib, writer, options);
35}
36
37/// Huffman only compression. Without Lempel-Ziv match searching. Faster
38/// compression, less memory requirements but bigger compressed sizes.
39pub const huffman = struct {
40 pub fn compress(reader: anytype, writer: anytype) !void {
41 try deflate.huffman.compress(.zlib, reader, writer);
42 }
43
44 pub fn Compressor(comptime WriterType: type) type {
45 return deflate.huffman.Compressor(.zlib, WriterType);
46 }
47
48 pub fn compressor(writer: anytype) !huffman.Compressor(@TypeOf(writer)) {
49 return deflate.huffman.compressor(.zlib, writer);
50 }
51};
52
53// No compression store only. Compressed size is slightly bigger than plain.
54pub const store = struct {
55 pub fn compress(reader: anytype, writer: anytype) !void {
56 try deflate.store.compress(.zlib, reader, writer);
57 }
58
59 pub fn Compressor(comptime WriterType: type) type {
60 return deflate.store.Compressor(.zlib, WriterType);
61 }
62
63 pub fn compressor(writer: anytype) !store.Compressor(@TypeOf(writer)) {
64 return deflate.store.compressor(.zlib, writer);
65 }
66};
lib/std/compress/gzip.zig created+66
...@@ -0,0 +1,66 @@
1const deflate = @import("flate/deflate.zig");
2const inflate = @import("flate/inflate.zig");
3
4/// Decompress compressed data from reader and write plain data to the writer.
5pub fn decompress(reader: anytype, writer: anytype) !void {
6 try inflate.decompress(.gzip, reader, writer);
7}
8
9/// Decompressor type
10pub fn Decompressor(comptime ReaderType: type) type {
11 return inflate.Inflate(.gzip, ReaderType);
12}
13
14/// Create Decompressor which will read compressed data from reader.
15pub fn decompressor(reader: anytype) Decompressor(@TypeOf(reader)) {
16 return inflate.decompressor(.gzip, reader);
17}
18
19/// Compression level, trades between speed and compression size.
20pub const Options = deflate.Options;
21
22/// Compress plain data from reader and write compressed data to the writer.
23pub fn compress(reader: anytype, writer: anytype, options: Options) !void {
24 try deflate.compress(.gzip, reader, writer, options);
25}
26
27/// Compressor type
28pub fn Compressor(comptime WriterType: type) type {
29 return deflate.Compressor(.gzip, WriterType);
30}
31
32/// Create Compressor which outputs compressed data to the writer.
33pub fn compressor(writer: anytype, options: Options) !Compressor(@TypeOf(writer)) {
34 return try deflate.compressor(.gzip, writer, options);
35}
36
37/// Huffman only compression. Without Lempel-Ziv match searching. Faster
38/// compression, less memory requirements but bigger compressed sizes.
39pub const huffman = struct {
40 pub fn compress(reader: anytype, writer: anytype) !void {
41 try deflate.huffman.compress(.gzip, reader, writer);
42 }
43
44 pub fn Compressor(comptime WriterType: type) type {
45 return deflate.huffman.Compressor(.gzip, WriterType);
46 }
47
48 pub fn compressor(writer: anytype) !huffman.Compressor(@TypeOf(writer)) {
49 return deflate.huffman.compressor(.gzip, writer);
50 }
51};
52
53// No compression store only. Compressed size is slightly bigger than plain.
54pub const store = struct {
55 pub fn compress(reader: anytype, writer: anytype) !void {
56 try deflate.store.compress(.gzip, reader, writer);
57 }
58
59 pub fn Compressor(comptime WriterType: type) type {
60 return deflate.store.Compressor(.gzip, WriterType);
61 }
62
63 pub fn compressor(writer: anytype) !store.Compressor(@TypeOf(writer)) {
64 return deflate.store.compressor(.gzip, writer);
65 }
66};
lib/std/compress/zlib.zig created+66
...@@ -0,0 +1,66 @@
1const deflate = @import("flate/deflate.zig");
2const inflate = @import("flate/inflate.zig");
3
4/// Decompress compressed data from reader and write plain data to the writer.
5pub fn decompress(reader: anytype, writer: anytype) !void {
6 try inflate.decompress(.zlib, reader, writer);
7}
8
9/// Decompressor type
10pub fn Decompressor(comptime ReaderType: type) type {
11 return inflate.Inflate(.zlib, ReaderType);
12}
13
14/// Create Decompressor which will read compressed data from reader.
15pub fn decompressor(reader: anytype) Decompressor(@TypeOf(reader)) {
16 return inflate.decompressor(.zlib, reader);
17}
18
19/// Compression level, trades between speed and compression size.
20pub const Options = deflate.Options;
21
22/// Compress plain data from reader and write compressed data to the writer.
23pub fn compress(reader: anytype, writer: anytype, options: Options) !void {
24 try deflate.compress(.zlib, reader, writer, options);
25}
26
27/// Compressor type
28pub fn Compressor(comptime WriterType: type) type {
29 return deflate.Compressor(.zlib, WriterType);
30}
31
32/// Create Compressor which outputs compressed data to the writer.
33pub fn compressor(writer: anytype, options: Options) !Compressor(@TypeOf(writer)) {
34 return try deflate.compressor(.zlib, writer, options);
35}
36
37/// Huffman only compression. Without Lempel-Ziv match searching. Faster
38/// compression, less memory requirements but bigger compressed sizes.
39pub const huffman = struct {
40 pub fn compress(reader: anytype, writer: anytype) !void {
41 try deflate.huffman.compress(.zlib, reader, writer);
42 }
43
44 pub fn Compressor(comptime WriterType: type) type {
45 return deflate.huffman.Compressor(.zlib, WriterType);
46 }
47
48 pub fn compressor(writer: anytype) !huffman.Compressor(@TypeOf(writer)) {
49 return deflate.huffman.compressor(.zlib, writer);
50 }
51};
52
53// No compression store only. Compressed size is slightly bigger than plain.
54pub const store = struct {
55 pub fn compress(reader: anytype, writer: anytype) !void {
56 try deflate.store.compress(.zlib, reader, writer);
57 }
58
59 pub fn Compressor(comptime WriterType: type) type {
60 return deflate.store.Compressor(.zlib, WriterType);
61 }
62
63 pub fn compressor(writer: anytype) !store.Compressor(@TypeOf(writer)) {
64 return deflate.store.compressor(.zlib, writer);
65 }
66};