-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Fixes: #10
- Loading branch information
Showing
17 changed files
with
1,127 additions
and
25 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,89 @@ | ||
const std = @import("std"); | ||
const flate = @import("flate"); | ||
const c = @cImport(@cInclude("puff.h")); | ||
|
||
pub export fn main() void { | ||
zigMain() catch unreachable; | ||
} | ||
|
||
pub fn zigMain() !void { | ||
var gpa = std.heap.GeneralPurposeAllocator(.{}){}; | ||
defer std.debug.assert(gpa.deinit() == .ok); | ||
const allocator = gpa.allocator(); | ||
|
||
// Read the data from stdin | ||
const stdin = std.io.getStdIn(); | ||
const data = try stdin.readToEndAlloc(allocator, std.math.maxInt(usize)); | ||
defer allocator.free(data); | ||
|
||
// Try to parse the data with puff | ||
var puff_error: anyerror = error.NoError; | ||
const inflated_puff: ?[]u8 = puffAlloc(allocator, data) catch |err| blk: { | ||
puff_error = err; | ||
break :blk null; | ||
}; | ||
defer if (inflated_puff != null) { | ||
allocator.free(inflated_puff.?); | ||
}; | ||
|
||
var fbs = std.io.fixedBufferStream(data); | ||
const reader = fbs.reader(); | ||
var inflate = flate.raw.decompressor(reader); | ||
|
||
var zig_error: anyerror = error.NoError; | ||
const inflated: ?[]u8 = inflate.reader().readAllAlloc(allocator, std.math.maxInt(usize)) catch |err| blk: { | ||
zig_error = err; | ||
break :blk null; | ||
}; | ||
defer if (inflated != null) { | ||
allocator.free(inflated.?); | ||
}; | ||
|
||
if (inflated_puff == null or inflated == null) { | ||
//std.debug.print("puff error: {}, zig error: {}\n", .{ puff_error, zig_error }); | ||
|
||
if (inflated_puff != null or inflated != null) { | ||
return error.MismatchedErrors; | ||
} | ||
} else { | ||
try std.testing.expectEqualSlices(u8, inflated_puff.?, inflated.?); | ||
} | ||
} | ||
|
||
fn puffAlloc(allocator: std.mem.Allocator, input: []const u8) ![]u8 { | ||
// call once to get the uncompressed length | ||
var decoded_len: c_ulong = undefined; | ||
var source_len: c_ulong = input.len; | ||
const result = c.puff(c.NIL, &decoded_len, input.ptr, &source_len); | ||
|
||
if (result != 0) { | ||
return translatePuffError(result); | ||
} | ||
|
||
const dest = try allocator.alloc(u8, decoded_len); | ||
errdefer allocator.free(dest); | ||
|
||
// call again to actually get the output | ||
_ = c.puff(dest.ptr, &decoded_len, input.ptr, &source_len); | ||
return dest; | ||
} | ||
|
||
fn translatePuffError(code: c_int) anyerror { | ||
return switch (code) { | ||
2 => error.EndOfStream, | ||
1 => error.OutputSpaceExhausted, | ||
0 => unreachable, | ||
-1 => error.InvalidBlockType, | ||
-2 => error.StoredBlockLengthNotOnesComplement, | ||
-3 => error.TooManyLengthOrDistanceCodes, | ||
-4 => error.CodeLengthsCodesIncomplete, | ||
-5 => error.RepeatLengthsWithNoFirstLengths, | ||
-6 => error.RepeatMoreThanSpecifiedLengths, | ||
-7 => error.InvalidLiteralOrLengthCodeLengths, | ||
-8 => error.InvalidDistanceCodeLengths, | ||
-9 => error.MissingEOBCode, | ||
-10 => error.InvalidLiteralOrLengthOrDistanceCodeInBlock, | ||
-11 => error.DistanceTooFarBackInBlock, | ||
else => unreachable, | ||
}; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,63 @@ | ||
Puff -- A Simple Inflate | ||
3 Mar 2003 | ||
Mark Adler | ||
[email protected] | ||
|
||
What this is -- | ||
|
||
puff.c provides the routine puff() to decompress the deflate data format. It | ||
does so more slowly than zlib, but the code is about one-fifth the size of the | ||
inflate code in zlib, and written to be very easy to read. | ||
|
||
Why I wrote this -- | ||
|
||
puff.c was written to document the deflate format unambiguously, by virtue of | ||
being working C code. It is meant to supplement RFC 1951, which formally | ||
describes the deflate format. I have received many questions on details of the | ||
deflate format, and I hope that reading this code will answer those questions. | ||
puff.c is heavily commented with details of the deflate format, especially | ||
those little nooks and cranies of the format that might not be obvious from a | ||
specification. | ||
|
||
puff.c may also be useful in applications where code size or memory usage is a | ||
very limited resource, and speed is not as important. | ||
|
||
How to use it -- | ||
|
||
Well, most likely you should just be reading puff.c and using zlib for actual | ||
applications, but if you must ... | ||
|
||
Include puff.h in your code, which provides this prototype: | ||
|
||
int puff(unsigned char *dest, /* pointer to destination pointer */ | ||
unsigned long *destlen, /* amount of output space */ | ||
unsigned char *source, /* pointer to source data pointer */ | ||
unsigned long *sourcelen); /* amount of input available */ | ||
|
||
Then you can call puff() to decompress a deflate stream that is in memory in | ||
its entirety at source, to a sufficiently sized block of memory for the | ||
decompressed data at dest. puff() is the only external symbol in puff.c The | ||
only C library functions that puff.c needs are setjmp() and longjmp(), which | ||
are used to simplify error checking in the code to improve readabilty. puff.c | ||
does no memory allocation, and uses less than 2K bytes off of the stack. | ||
|
||
If destlen is not enough space for the uncompressed data, then inflate will | ||
return an error without writing more than destlen bytes. Note that this means | ||
that in order to decompress the deflate data successfully, you need to know | ||
the size of the uncompressed data ahead of time. | ||
|
||
If needed, puff() can determine the size of the uncompressed data with no | ||
output space. This is done by passing dest equal to (unsigned char *)0. Then | ||
the initial value of *destlen is ignored and *destlen is set to the length of | ||
the uncompressed data. So if the size of the uncompressed data is not known, | ||
then two passes of puff() can be used--first to determine the size, and second | ||
to do the actual inflation after allocating the appropriate memory. Not | ||
pretty, but it works. (This is one of the reasons you should be using zlib.) | ||
|
||
The deflate format is self-terminating. If the deflate stream does not end | ||
in *sourcelen bytes, puff() will return an error without reading at or past | ||
endsource. | ||
|
||
On return, *sourcelen is updated to the amount of input data consumed, and | ||
*destlen is updated to the size of the uncompressed data. See the comments | ||
in puff.c for the possible return codes for puff(). |
Oops, something went wrong.