Skip to content
This repository was archived by the owner on Feb 24, 2025. It is now read-only.

Commit 902ee48

Browse files
committed
add huffman code lens checks
Fixes: #10
1 parent 426011f commit 902ee48

File tree

17 files changed

+1127
-25
lines changed

17 files changed

+1127
-25
lines changed

bin/fuzz_puff.zig

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
const std = @import("std");
2+
const flate = @import("flate");
3+
const c = @cImport(@cInclude("puff.h"));
4+
5+
pub export fn main() void {
6+
zigMain() catch unreachable;
7+
}
8+
9+
pub fn zigMain() !void {
10+
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
11+
defer std.debug.assert(gpa.deinit() == .ok);
12+
const allocator = gpa.allocator();
13+
14+
// Read the data from stdin
15+
const stdin = std.io.getStdIn();
16+
const data = try stdin.readToEndAlloc(allocator, std.math.maxInt(usize));
17+
defer allocator.free(data);
18+
19+
// Try to parse the data with puff
20+
var puff_error: anyerror = error.NoError;
21+
const inflated_puff: ?[]u8 = puffAlloc(allocator, data) catch |err| blk: {
22+
puff_error = err;
23+
break :blk null;
24+
};
25+
defer if (inflated_puff != null) {
26+
allocator.free(inflated_puff.?);
27+
};
28+
29+
var fbs = std.io.fixedBufferStream(data);
30+
const reader = fbs.reader();
31+
var inflate = flate.raw.decompressor(reader);
32+
33+
var zig_error: anyerror = error.NoError;
34+
const inflated: ?[]u8 = inflate.reader().readAllAlloc(allocator, std.math.maxInt(usize)) catch |err| blk: {
35+
zig_error = err;
36+
break :blk null;
37+
};
38+
defer if (inflated != null) {
39+
allocator.free(inflated.?);
40+
};
41+
42+
if (inflated_puff == null or inflated == null) {
43+
//std.debug.print("puff error: {}, zig error: {}\n", .{ puff_error, zig_error });
44+
45+
if (inflated_puff != null or inflated != null) {
46+
return error.MismatchedErrors;
47+
}
48+
} else {
49+
try std.testing.expectEqualSlices(u8, inflated_puff.?, inflated.?);
50+
}
51+
}
52+
53+
fn puffAlloc(allocator: std.mem.Allocator, input: []const u8) ![]u8 {
54+
// call once to get the uncompressed length
55+
var decoded_len: c_ulong = undefined;
56+
var source_len: c_ulong = input.len;
57+
const result = c.puff(c.NIL, &decoded_len, input.ptr, &source_len);
58+
59+
if (result != 0) {
60+
return translatePuffError(result);
61+
}
62+
63+
const dest = try allocator.alloc(u8, decoded_len);
64+
errdefer allocator.free(dest);
65+
66+
// call again to actually get the output
67+
_ = c.puff(dest.ptr, &decoded_len, input.ptr, &source_len);
68+
return dest;
69+
}
70+
71+
fn translatePuffError(code: c_int) anyerror {
72+
return switch (code) {
73+
2 => error.EndOfStream,
74+
1 => error.OutputSpaceExhausted,
75+
0 => unreachable,
76+
-1 => error.InvalidBlockType,
77+
-2 => error.StoredBlockLengthNotOnesComplement,
78+
-3 => error.TooManyLengthOrDistanceCodes,
79+
-4 => error.CodeLengthsCodesIncomplete,
80+
-5 => error.RepeatLengthsWithNoFirstLengths,
81+
-6 => error.RepeatMoreThanSpecifiedLengths,
82+
-7 => error.InvalidLiteralOrLengthCodeLengths,
83+
-8 => error.InvalidDistanceCodeLengths,
84+
-9 => error.MissingEOBCode,
85+
-10 => error.InvalidLiteralOrLengthOrDistanceCodeInBlock,
86+
-11 => error.DistanceTooFarBackInBlock,
87+
else => unreachable,
88+
};
89+
}

bin/puff/README

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
Puff -- A Simple Inflate
2+
3 Mar 2003
3+
Mark Adler
4+
madler@alumni.caltech.edu
5+
6+
What this is --
7+
8+
puff.c provides the routine puff() to decompress the deflate data format. It
9+
does so more slowly than zlib, but the code is about one-fifth the size of the
10+
inflate code in zlib, and written to be very easy to read.
11+
12+
Why I wrote this --
13+
14+
puff.c was written to document the deflate format unambiguously, by virtue of
15+
being working C code. It is meant to supplement RFC 1951, which formally
16+
describes the deflate format. I have received many questions on details of the
17+
deflate format, and I hope that reading this code will answer those questions.
18+
puff.c is heavily commented with details of the deflate format, especially
19+
those little nooks and cranies of the format that might not be obvious from a
20+
specification.
21+
22+
puff.c may also be useful in applications where code size or memory usage is a
23+
very limited resource, and speed is not as important.
24+
25+
How to use it --
26+
27+
Well, most likely you should just be reading puff.c and using zlib for actual
28+
applications, but if you must ...
29+
30+
Include puff.h in your code, which provides this prototype:
31+
32+
int puff(unsigned char *dest, /* pointer to destination pointer */
33+
unsigned long *destlen, /* amount of output space */
34+
unsigned char *source, /* pointer to source data pointer */
35+
unsigned long *sourcelen); /* amount of input available */
36+
37+
Then you can call puff() to decompress a deflate stream that is in memory in
38+
its entirety at source, to a sufficiently sized block of memory for the
39+
decompressed data at dest. puff() is the only external symbol in puff.c The
40+
only C library functions that puff.c needs are setjmp() and longjmp(), which
41+
are used to simplify error checking in the code to improve readabilty. puff.c
42+
does no memory allocation, and uses less than 2K bytes off of the stack.
43+
44+
If destlen is not enough space for the uncompressed data, then inflate will
45+
return an error without writing more than destlen bytes. Note that this means
46+
that in order to decompress the deflate data successfully, you need to know
47+
the size of the uncompressed data ahead of time.
48+
49+
If needed, puff() can determine the size of the uncompressed data with no
50+
output space. This is done by passing dest equal to (unsigned char *)0. Then
51+
the initial value of *destlen is ignored and *destlen is set to the length of
52+
the uncompressed data. So if the size of the uncompressed data is not known,
53+
then two passes of puff() can be used--first to determine the size, and second
54+
to do the actual inflation after allocating the appropriate memory. Not
55+
pretty, but it works. (This is one of the reasons you should be using zlib.)
56+
57+
The deflate format is self-terminating. If the deflate stream does not end
58+
in *sourcelen bytes, puff() will return an error without reading at or past
59+
endsource.
60+
61+
On return, *sourcelen is updated to the amount of input data consumed, and
62+
*destlen is updated to the size of the uncompressed data. See the comments
63+
in puff.c for the possible return codes for puff().

0 commit comments

Comments
 (0)