1
1
/// Deflate is a lossless data compression file format that uses a combination
2
2
/// of LZ77 and Huffman coding.
3
- pub const deflate = @import ("deflate.zig" );
3
+ pub const deflate = @import ("flate/ deflate.zig" );
4
4
5
5
/// Inflate is the decoding process that takes a Deflate bitstream for
6
6
/// decompression and correctly produces the original full-size data or file.
7
- pub const inflate = @import ("inflate.zig" );
7
+ pub const inflate = @import ("flate/ inflate.zig" );
8
8
9
9
/// Decompress compressed data from reader and write plain data to the writer.
10
10
pub fn decompress (reader : anytype , writer : anytype ) ! void {
@@ -72,12 +72,17 @@ pub const store = struct {
72
72
73
73
/// Container defines header/footer arround deflate bit stream. Gzip and zlib
74
74
/// compression algorithms are containers arround deflate bit stream body.
75
- const Container = @import ("container.zig" ).Container ;
75
+ const Container = @import ("flate/ container.zig" ).Container ;
76
76
const std = @import ("std" );
77
77
const testing = std .testing ;
78
78
const fixedBufferStream = std .io .fixedBufferStream ;
79
79
const print = std .debug .print ;
80
80
81
+ test "flate" {
82
+ _ = @import ("flate/deflate.zig" );
83
+ _ = @import ("flate/inflate.zig" );
84
+ }
85
+
81
86
test "flate compress/decompress" {
82
87
var cmp_buf : [64 * 1024 ]u8 = undefined ; // compressed data buffer
83
88
var dcm_buf : [64 * 1024 ]u8 = undefined ; // decompressed data buffer
@@ -91,25 +96,25 @@ test "flate compress/decompress" {
91
96
store_size : usize = 0 ,
92
97
}{
93
98
.{
94
- .data = @embedFile ("testdata/rfc1951.txt" ),
99
+ .data = @embedFile ("flate/ testdata/rfc1951.txt" ),
95
100
.gzip_sizes = [_ ]usize { 11513 , 11217 , 11139 , 11126 , 11122 , 11119 },
96
101
.huffman_only_size = 20287 ,
97
102
.store_size = 36967 ,
98
103
},
99
104
.{
100
- .data = @embedFile ("testdata/fuzz/roundtrip1.input" ),
105
+ .data = @embedFile ("flate/ testdata/fuzz/roundtrip1.input" ),
101
106
.gzip_sizes = [_ ]usize { 373 , 370 , 370 , 370 , 370 , 370 },
102
107
.huffman_only_size = 393 ,
103
108
.store_size = 393 ,
104
109
},
105
110
.{
106
- .data = @embedFile ("testdata/fuzz/roundtrip2.input" ),
111
+ .data = @embedFile ("flate/ testdata/fuzz/roundtrip2.input" ),
107
112
.gzip_sizes = [_ ]usize { 373 , 373 , 373 , 373 , 373 , 373 },
108
113
.huffman_only_size = 394 ,
109
114
.store_size = 394 ,
110
115
},
111
116
.{
112
- .data = @embedFile ("testdata/fuzz/deflate-stream.expect" ),
117
+ .data = @embedFile ("flate/ testdata/fuzz/deflate-stream.expect" ),
113
118
.gzip_sizes = [_ ]usize { 351 , 347 , 347 , 347 , 347 , 347 },
114
119
.huffman_only_size = 498 ,
115
120
.store_size = 747 ,
@@ -236,13 +241,12 @@ test "flate compress/decompress" {
236
241
}
237
242
238
243
fn 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 ();
244
+ var in = fixedBufferStream (compressed );
245
+ var out = std .ArrayList (u8 ).init (testing .allocator );
246
+ defer out .deinit ();
242
247
243
- try inflate .decompress (container , in_stream .reader (), al .writer ());
244
-
245
- try testing .expectEqualSlices (u8 , expected_plain , al .items );
248
+ try inflate .decompress (container , in .reader (), out .writer ());
249
+ try testing .expectEqualSlices (u8 , expected_plain , out .items );
246
250
}
247
251
248
252
test "flate don't read past deflate stream's end" {
@@ -345,3 +349,128 @@ test "flate gzip header" {
345
349
0x01 , 0x00 , 0x00 , 0xff , 0xff , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 ,
346
350
}, "" );
347
351
}
352
+
353
+ test "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
+
381
+ fn 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
+ }
0 commit comments