puncture
a minimal implementation of a gzip (de)compressor
installation
using cargo:
usage
in general, the flags are comparable with the standard gzip utility, except for a few missing ones:
# decompress a file, replacing it with the original uncompressed version
# decompress a file, writing the contents to standard out
# compress a file, keeping the original and specifying the output filename
philosophy
i wanted to create a project that tries to strike the middle ground between two extremes: it tries to be simple (but not the simplest) and fast (but not the fastest).
there are certainly simpler and shorter gzip implementations, but these projects are usually so stripped down, that they sacrifice educational value for simplicity. there isn't a lot to be learned from a 280 line program for someone who is already even slightly familiar with the topic.
there are also certainly faster, and more complicated implementations. these are usually so heavily optimized, that code readability suffers as a result. there are things to be learnt from these projects as well, but their purpose is very different.
this project is mainly for those that want to move past code-golfed implementations, but aren't necessarily ready to dive head first into the zlib codebase (believe me, i tried).
if you are looking for a place to get started, read the documentation over at docs.rs, i tried to document everything to the best of my abilities (note that the compressor and bitwriter modules aren't documented yet)
resources
i mainly used RFC1952 for the GZIP header parsing, and RFC1951 for the actual DEFLATE algorithm. other notable resources that helped me include:
infgenfor viewing deflate streams with semantic information- An Explanation of the Deflate Algorithm by Anteus Feldspar
- this random youtube video
benchmarks
decompression
i used the Silesia Open Source Compression Benchmark as the input data, and hyperfine as the benchmark harness.
i ran this command:
)
)
)
)
tl;dr gzip is roughly 1.44x faster. to my knowledge, other "toy" implementations online are usually in the 2-3x range
compression
| command | mean compression time (s) | compression ratio (%) |
|---|---|---|
| gzip -9c ./silesia.tar | 16.575 | 68.1% |
| gzip -6c ./silesia.tar | 6.961 | 67.8% |
| gzip -1c ./silesia.tar | 2.230 | 63.5% |
| puncture -9c ./silesia.tar | 8.587 | 62.2% |
| puncture -6c ./silesia.tar | 5.054 | 62.0% |
| puncture -1c ./silesia.tar | 2.549 | 58.8% |
for compression there are multiple angles: speed and compression ratio. for compression speed, i ran this command:
)
)
)
)
)
)
)
)
)
)
)
)
to check the compression ratios, i compressed silesia.tar at different levels with both programs, and then ran
)
these results are somewhat expected, as i only implented fixed huffman encoding, and my LZ77 pattern matching is eager as well.
complexity
- creates LUTs for dynamic huffman trees
- use a split 64 KB linear buffer for the 32 KB LZ77 sliding window and the writing buffer
- handles overlapping LZ77 matches using an exponential doubling algorithm
- only uses fixed huffman trees for compression instead of dynamic tree generation
there are some optimizations i didn't end up implementing, such as:
- two-tier LUTs for huffman codes
- inlining the bit reading logic to extraction
- lazy LZ77 pattern matching
license
licensed under either of:
- Apache License, Version 2.0, (LICENSE-APACHE or https://www.apache.org/licenses/LICENSE-2.0)
- MIT license (LICENSE-MIT or https://opensource.org/license/mit)
at your option.