From 69f9277bd7271210f89516dc8cecf587903df8e0 Mon Sep 17 00:00:00 2001 From: Marko Seidel Date: Fri, 13 Nov 2020 15:34:37 +0100 Subject: [PATCH] archium - go/src (20201113) --- github.com/klauspost/compress/.gitattributes | 1 + github.com/klauspost/compress/.gitignore | 24 + github.com/klauspost/compress/.goreleaser.yml | 98 + github.com/klauspost/compress/.travis.yml | 45 + github.com/klauspost/compress/LICENSE | 28 + github.com/klauspost/compress/README.md | 300 + github.com/klauspost/compress/compressible.go | 85 + .../klauspost/compress/compressible_test.go | 302 + .../klauspost/compress/flate/deflate.go | 821 ++ .../klauspost/compress/flate/deflate_test.go | 658 ++ .../klauspost/compress/flate/dict_decoder.go | 184 + .../compress/flate/dict_decoder_test.go | 139 + .../klauspost/compress/flate/fast_encoder.go | 254 + .../klauspost/compress/flate/flate_test.go | 360 + github.com/klauspost/compress/flate/gen.go | 265 + .../klauspost/compress/flate/gen_inflate.go | 274 + .../compress/flate/huffman_bit_writer.go | 911 ++ .../compress/flate/huffman_bit_writer_test.go | 382 + .../klauspost/compress/flate/huffman_code.go | 363 + .../compress/flate/huffman_sortByFreq.go | 178 + .../compress/flate/huffman_sortByLiteral.go | 201 + .../klauspost/compress/flate/inflate.go | 1001 ++ .../klauspost/compress/flate/inflate_gen.go | 922 ++ .../klauspost/compress/flate/inflate_test.go | 282 + github.com/klauspost/compress/flate/level1.go | 179 + github.com/klauspost/compress/flate/level2.go | 205 + github.com/klauspost/compress/flate/level3.go | 229 + github.com/klauspost/compress/flate/level4.go | 212 + github.com/klauspost/compress/flate/level5.go | 279 + github.com/klauspost/compress/flate/level6.go | 282 + .../klauspost/compress/flate/reader_test.go | 106 + .../klauspost/compress/flate/stateless.go | 297 + .../testdata/huffman-null-max.dyn.expect | Bin 0 -> 101 bytes .../huffman-null-max.dyn.expect-noinput | Bin 0 -> 101 bytes .../flate/testdata/huffman-null-max.golden | Bin 0 -> 8219 bytes .../flate/testdata/huffman-null-max.in | Bin 0 -> 65535 bytes .../testdata/huffman-null-max.sync.expect | Bin 0 -> 78 bytes .../huffman-null-max.sync.expect-noinput | Bin 0 -> 78 bytes .../flate/testdata/huffman-null-max.wb.expect | Bin 0 -> 78 bytes .../huffman-null-max.wb.expect-noinput | Bin 0 -> 78 bytes .../flate/testdata/huffman-pi.dyn.expect | Bin 0 -> 1751 bytes .../testdata/huffman-pi.dyn.expect-noinput | Bin 0 -> 1751 bytes .../compress/flate/testdata/huffman-pi.golden | Bin 0 -> 1626 bytes .../compress/flate/testdata/huffman-pi.in | 1 + .../flate/testdata/huffman-pi.sync.expect | Bin 0 -> 1696 bytes .../testdata/huffman-pi.sync.expect-noinput | Bin 0 -> 1696 bytes .../flate/testdata/huffman-pi.wb.expect | Bin 0 -> 1696 bytes .../testdata/huffman-pi.wb.expect-noinput | Bin 0 -> 1696 bytes .../flate/testdata/huffman-rand-1k.dyn.expect | Bin 0 -> 1005 bytes .../huffman-rand-1k.dyn.expect-noinput | Bin 0 -> 1069 bytes .../flate/testdata/huffman-rand-1k.golden | Bin 0 -> 1005 bytes .../flate/testdata/huffman-rand-1k.in | Bin 0 -> 1000 bytes .../testdata/huffman-rand-1k.sync.expect | Bin 0 -> 1005 bytes .../huffman-rand-1k.sync.expect-noinput | Bin 0 -> 1054 bytes .../flate/testdata/huffman-rand-1k.wb.expect | Bin 0 -> 1005 bytes .../huffman-rand-1k.wb.expect-noinput | Bin 0 -> 1054 bytes .../testdata/huffman-rand-limit.dyn.expect | Bin 0 -> 252 bytes .../huffman-rand-limit.dyn.expect-noinput | 1 + .../flate/testdata/huffman-rand-limit.golden | Bin 0 -> 239 bytes .../flate/testdata/huffman-rand-limit.in | 4 + .../testdata/huffman-rand-limit.sync.expect | Bin 0 -> 229 bytes .../huffman-rand-limit.sync.expect-noinput | Bin 0 -> 229 bytes .../testdata/huffman-rand-limit.wb.expect | Bin 0 -> 186 bytes .../huffman-rand-limit.wb.expect-noinput | Bin 0 -> 186 bytes .../flate/testdata/huffman-rand-max.golden | Bin 0 -> 65540 bytes .../flate/testdata/huffman-rand-max.in | Bin 0 -> 65535 bytes .../flate/testdata/huffman-shifts.dyn.expect | Bin 0 -> 59 bytes .../huffman-shifts.dyn.expect-noinput | Bin 0 -> 59 bytes .../flate/testdata/huffman-shifts.golden | Bin 0 -> 1826 bytes .../compress/flate/testdata/huffman-shifts.in | 2 + .../flate/testdata/huffman-shifts.sync.expect | Bin 0 -> 32 bytes .../huffman-shifts.sync.expect-noinput | Bin 0 -> 32 bytes .../flate/testdata/huffman-shifts.wb.expect | Bin 0 -> 32 bytes .../testdata/huffman-shifts.wb.expect-noinput | Bin 0 -> 32 bytes .../testdata/huffman-text-shift.dyn.expect | Bin 0 -> 258 bytes .../huffman-text-shift.dyn.expect-noinput | 2 + .../flate/testdata/huffman-text-shift.golden | Bin 0 -> 252 bytes .../flate/testdata/huffman-text-shift.in | 14 + .../testdata/huffman-text-shift.sync.expect | Bin 0 -> 231 bytes .../huffman-text-shift.sync.expect-noinput | Bin 0 -> 231 bytes .../testdata/huffman-text-shift.wb.expect | Bin 0 -> 231 bytes .../huffman-text-shift.wb.expect-noinput | Bin 0 -> 231 bytes .../flate/testdata/huffman-text.dyn.expect | Bin 0 -> 304 bytes .../testdata/huffman-text.dyn.expect-noinput | 3 + .../flate/testdata/huffman-text.golden | Bin 0 -> 270 bytes .../compress/flate/testdata/huffman-text.in | 13 + .../flate/testdata/huffman-text.sync.expect | 1 + .../testdata/huffman-text.sync.expect-noinput | 1 + .../flate/testdata/huffman-text.wb.expect | 1 + .../testdata/huffman-text.wb.expect-noinput | 1 + .../flate/testdata/huffman-zero.dyn.expect | Bin 0 -> 313 bytes .../testdata/huffman-zero.dyn.expect-noinput | 1 + .../flate/testdata/huffman-zero.golden | Bin 0 -> 66 bytes .../compress/flate/testdata/huffman-zero.in | 1 + .../flate/testdata/huffman-zero.sync.expect | Bin 0 -> 17 bytes .../testdata/huffman-zero.sync.expect-noinput | Bin 0 -> 17 bytes .../flate/testdata/huffman-zero.wb.expect | Bin 0 -> 6 bytes .../testdata/huffman-zero.wb.expect-noinput | Bin 0 -> 6 bytes .../null-long-match.dyn.expect-noinput | Bin 0 -> 227 bytes .../null-long-match.sync.expect-noinput | Bin 0 -> 206 bytes .../null-long-match.wb.expect-noinput | Bin 0 -> 206 bytes .../compress/flate/testdata/regression.zip | Bin 0 -> 475404 bytes .../compress/flate/testdata/tokens.bin | 63 + github.com/klauspost/compress/flate/token.go | 375 + .../klauspost/compress/flate/token_test.go | 54 + .../klauspost/compress/flate/writer_test.go | 451 + github.com/klauspost/compress/fse/README.md | 79 + .../klauspost/compress/fse/bitreader.go | 122 + .../klauspost/compress/fse/bitwriter.go | 168 + .../klauspost/compress/fse/bytereader.go | 47 + github.com/klauspost/compress/fse/compress.go | 684 ++ .../klauspost/compress/fse/decompress.go | 374 + github.com/klauspost/compress/fse/fse.go | 144 + github.com/klauspost/compress/fse/fse_test.go | 288 + github.com/klauspost/compress/go.mod | 3 + .../klauspost/compress/gzip/example_test.go | 128 + github.com/klauspost/compress/gzip/gunzip.go | 344 + .../klauspost/compress/gzip/gunzip_test.go | 716 ++ github.com/klauspost/compress/gzip/gzip.go | 269 + .../klauspost/compress/gzip/gzip_test.go | 521 + .../compress/gzip/testdata/issue6550.gz | Bin 0 -> 65536 bytes .../compress/gzip/testdata/test.json | 5902 +++++++++++ .../klauspost/compress/huff0/.gitignore | 1 + github.com/klauspost/compress/huff0/README.md | 87 + .../klauspost/compress/huff0/bitreader.go | 329 + .../klauspost/compress/huff0/bitwriter.go | 197 + .../klauspost/compress/huff0/bytereader.go | 54 + .../klauspost/compress/huff0/compress.go | 651 ++ .../klauspost/compress/huff0/compress_test.go | 718 ++ .../klauspost/compress/huff0/decompress.go | 1146 +++ .../compress/huff0/decompress_test.go | 518 + github.com/klauspost/compress/huff0/huff0.go | 260 + .../compress/huff0/testdata/regression.zip | Bin 0 -> 137774 bytes github.com/klauspost/compress/s2/.gitignore | 15 + github.com/klauspost/compress/s2/LICENSE | 28 + github.com/klauspost/compress/s2/README.md | 493 + .../klauspost/compress/s2/_generate/gen.go | 1817 ++++ .../klauspost/compress/s2/_generate/go.mod | 5 + .../klauspost/compress/s2/_generate/go.sum | 23 + .../s2/cmd/internal/readahead/LICENSE | 22 + .../s2/cmd/internal/readahead/README.md | 57 + .../s2/cmd/internal/readahead/reader.go | 275 + .../klauspost/compress/s2/cmd/s2c/main.go | 253 + .../klauspost/compress/s2/cmd/s2d/main.go | 178 + .../klauspost/compress/s2/cpuid_amd64.go | 1194 +++ .../klauspost/compress/s2/cpuid_amd64.s | 44 + github.com/klauspost/compress/s2/decode.go | 403 + .../klauspost/compress/s2/decode_amd64.go | 15 + .../klauspost/compress/s2/decode_amd64.s | 570 ++ .../klauspost/compress/s2/decode_other.go | 161 + .../klauspost/compress/s2/decode_test.go | 43 + github.com/klauspost/compress/s2/encode.go | 924 ++ .../klauspost/compress/s2/encode_all.go | 276 + .../klauspost/compress/s2/encode_amd64.go | 68 + .../klauspost/compress/s2/encode_better.go | 225 + github.com/klauspost/compress/s2/encode_go.go | 450 + .../klauspost/compress/s2/encode_test.go | 207 + .../compress/s2/encodeblock_amd64.go | 98 + .../klauspost/compress/s2/encodeblock_amd64.s | 9046 +++++++++++++++++ github.com/klauspost/compress/s2/s2.go | 129 + github.com/klauspost/compress/s2/s2_test.go | 1853 ++++ ...9e1a0da7915a3d69632f5613ed78bc998a8a23.zst | Bin 0 -> 43785 bytes .../s2/testdata/Mark.Twain-Tom.Sawyer.txt | 396 + .../Mark.Twain-Tom.Sawyer.txt.rawsnappy | Bin 0 -> 9871 bytes .../s2/testdata/dec-block-regressions.zip | Bin 0 -> 371 bytes .../compress/s2/testdata/enc_regressions.zip | Bin 0 -> 487927 bytes .../klauspost/compress/s2/testdata/random | Bin 0 -> 1048576 bytes .../klauspost/compress/snappy/.gitignore | 16 + github.com/klauspost/compress/snappy/AUTHORS | 15 + .../klauspost/compress/snappy/CONTRIBUTORS | 37 + github.com/klauspost/compress/snappy/LICENSE | 27 + github.com/klauspost/compress/snappy/README | 107 + .../klauspost/compress/snappy/decode.go | 237 + .../klauspost/compress/snappy/decode_amd64.go | 14 + .../klauspost/compress/snappy/decode_amd64.s | 482 + .../klauspost/compress/snappy/decode_other.go | 115 + .../klauspost/compress/snappy/encode.go | 285 + .../klauspost/compress/snappy/encode_amd64.go | 29 + .../klauspost/compress/snappy/encode_amd64.s | 730 ++ .../klauspost/compress/snappy/encode_other.go | 238 + .../klauspost/compress/snappy/golden_test.go | 1965 ++++ .../klauspost/compress/snappy/runbench.cmd | 2 + .../klauspost/compress/snappy/snappy.go | 98 + .../klauspost/compress/snappy/snappy_test.go | 1353 +++ .../snappy/testdata/Mark.Twain-Tom.Sawyer.txt | 396 + .../Mark.Twain-Tom.Sawyer.txt.rawsnappy | Bin 0 -> 9871 bytes .../klauspost/compress/snappy/testdata/random | Bin 0 -> 1048576 bytes .../testdata/Mark.Twain-Tom.Sawyer.txt | 8472 +++++++++++++++ .../klauspost/compress/testdata/case1.bin | Bin 0 -> 55 bytes .../klauspost/compress/testdata/case2.bin | 1 + .../klauspost/compress/testdata/case3.bin | 1 + .../klauspost/compress/testdata/crash1.bin | Bin 0 -> 5 bytes .../klauspost/compress/testdata/crash2.bin | 1 + .../klauspost/compress/testdata/crash3.bin | 1 + .../klauspost/compress/testdata/crash4.bin | 1 + .../klauspost/compress/testdata/crash5.bin | 1 + .../compress/testdata/dec-crash6.bin | Bin 0 -> 11 bytes .../klauspost/compress/testdata/dec-hang1.bin | 1 + .../klauspost/compress/testdata/dec-hang2.bin | 1 + .../klauspost/compress/testdata/dec-hang3.bin | 1 + .../compress/testdata/dec-symlen1.bin | Bin 0 -> 49 bytes github.com/klauspost/compress/testdata/e.txt | 1 + .../compress/testdata/endnonzero.bin | Bin 0 -> 7 bytes .../compress/testdata/endzerobits.bin | Bin 0 -> 5 bytes .../compress/testdata/fse-artifact3.bin | Bin 0 -> 4116 bytes .../compress/testdata/gettysburg.txt | 29 + .../klauspost/compress/testdata/html.txt | 1183 +++ .../compress/testdata/normcount2.bin | 1 + github.com/klauspost/compress/testdata/pi.txt | 1 + .../klauspost/compress/testdata/pngdata.bin | Bin 0 -> 51200 bytes .../klauspost/compress/testdata/sharnd.out | Bin 0 -> 100004 bytes .../klauspost/compress/zip/example_test.go | 94 + github.com/klauspost/compress/zip/reader.go | 623 ++ .../klauspost/compress/zip/reader_test.go | 1054 ++ github.com/klauspost/compress/zip/register.go | 149 + github.com/klauspost/compress/zip/struct.go | 387 + .../zip/testdata/crc32-not-streamed.zip | Bin 0 -> 314 bytes .../klauspost/compress/zip/testdata/dd.zip | Bin 0 -> 154 bytes .../zip/testdata/go-no-datadesc-sig.zip | Bin 0 -> 330 bytes .../zip/testdata/go-with-datadesc-sig.zip | Bin 0 -> 242 bytes .../zip/testdata/gophercolor16x16.png | Bin 0 -> 785 bytes .../compress/zip/testdata/readme.notzip | Bin 0 -> 1906 bytes .../compress/zip/testdata/readme.zip | Bin 0 -> 1886 bytes .../compress/zip/testdata/symlink.zip | Bin 0 -> 173 bytes .../zip/testdata/test-trailing-junk.zip | Bin 0 -> 1184 bytes .../klauspost/compress/zip/testdata/test.zip | Bin 0 -> 1170 bytes .../compress/zip/testdata/time-22738.zip | Bin 0 -> 140 bytes .../compress/zip/testdata/time-7zip.zip | Bin 0 -> 150 bytes .../compress/zip/testdata/time-go.zip | Bin 0 -> 148 bytes .../compress/zip/testdata/time-infozip.zip | Bin 0 -> 166 bytes .../compress/zip/testdata/time-osx.zip | Bin 0 -> 142 bytes .../compress/zip/testdata/time-win7.zip | Bin 0 -> 114 bytes .../compress/zip/testdata/time-winrar.zip | Bin 0 -> 150 bytes .../compress/zip/testdata/time-winzip.zip | Bin 0 -> 150 bytes .../klauspost/compress/zip/testdata/unix.zip | Bin 0 -> 620 bytes .../compress/zip/testdata/utf8-7zip.zip | Bin 0 -> 146 bytes .../compress/zip/testdata/utf8-infozip.zip | Bin 0 -> 162 bytes .../compress/zip/testdata/utf8-osx.zip | Bin 0 -> 138 bytes .../compress/zip/testdata/utf8-winrar.zip | Bin 0 -> 146 bytes .../compress/zip/testdata/utf8-winzip.zip | Bin 0 -> 146 bytes .../klauspost/compress/zip/testdata/winxp.zip | Bin 0 -> 412 bytes .../compress/zip/testdata/zip64-2.zip | Bin 0 -> 266 bytes .../klauspost/compress/zip/testdata/zip64.zip | Bin 0 -> 242 bytes github.com/klauspost/compress/zip/writer.go | 747 ++ .../klauspost/compress/zip/writer_test.go | 477 + github.com/klauspost/compress/zip/zip_test.go | 828 ++ .../klauspost/compress/zlib/example_test.go | 37 + github.com/klauspost/compress/zlib/reader.go | 183 + .../klauspost/compress/zlib/reader_test.go | 179 + github.com/klauspost/compress/zlib/writer.go | 201 + .../klauspost/compress/zlib/writer_test.go | 212 + github.com/klauspost/compress/zstd/README.md | 427 + .../klauspost/compress/zstd/bitreader.go | 136 + .../klauspost/compress/zstd/bitwriter.go | 169 + .../klauspost/compress/zstd/blockdec.go | 739 ++ .../klauspost/compress/zstd/blockenc.go | 837 ++ .../compress/zstd/blocktype_string.go | 85 + github.com/klauspost/compress/zstd/bytebuf.go | 127 + .../klauspost/compress/zstd/bytereader.go | 88 + github.com/klauspost/compress/zstd/decoder.go | 540 + .../compress/zstd/decoder_options.go | 84 + .../klauspost/compress/zstd/decoder_test.go | 1454 +++ github.com/klauspost/compress/zstd/dict.go | 104 + .../klauspost/compress/zstd/dict_test.go | 134 + .../klauspost/compress/zstd/enc_better.go | 518 + .../klauspost/compress/zstd/enc_dfast.go | 678 ++ .../klauspost/compress/zstd/enc_fast.go | 755 ++ .../klauspost/compress/zstd/enc_params.go | 157 + github.com/klauspost/compress/zstd/encoder.go | 560 + .../compress/zstd/encoder_options.go | 267 + .../compress/zstd/encoder_options_test.go | 154 + .../klauspost/compress/zstd/encoder_test.go | 1064 ++ .../klauspost/compress/zstd/framedec.go | 494 + .../klauspost/compress/zstd/frameenc.go | 115 + .../klauspost/compress/zstd/fse_decoder.go | 385 + .../klauspost/compress/zstd/fse_encoder.go | 726 ++ .../klauspost/compress/zstd/fse_predefined.go | 158 + github.com/klauspost/compress/zstd/hash.go | 77 + github.com/klauspost/compress/zstd/history.go | 89 + .../compress/zstd/internal/xxhash/LICENSE.txt | 22 + .../compress/zstd/internal/xxhash/README.md | 58 + .../compress/zstd/internal/xxhash/xxhash.go | 238 + .../zstd/internal/xxhash/xxhash_amd64.go | 13 + .../zstd/internal/xxhash/xxhash_amd64.s | 215 + .../zstd/internal/xxhash/xxhash_other.go | 76 + .../zstd/internal/xxhash/xxhash_safe.go | 11 + .../zstd/internal/xxhash/xxhash_test.go | 162 + github.com/klauspost/compress/zstd/seqdec.go | 485 + github.com/klauspost/compress/zstd/seqenc.go | 115 + github.com/klauspost/compress/zstd/snappy.go | 436 + .../klauspost/compress/zstd/snappy_test.go | 331 + .../klauspost/compress/zstd/testdata/bad.zip | Bin 0 -> 3241 bytes .../compress/zstd/testdata/benchdecoder.zip | Bin 0 -> 918471 bytes .../compress/zstd/testdata/comp-crashers.zip | Bin 0 -> 1201418 bytes .../compress/zstd/testdata/decoder.zip | Bin 0 -> 7619808 bytes .../zstd/testdata/dict-tests-small.zip | Bin 0 -> 1432607 bytes .../klauspost/compress/zstd/testdata/good.zip | Bin 0 -> 3914 bytes .../compress/zstd/testdata/large.zip | Bin 0 -> 10826 bytes .../compress/zstd/testdata/regression.zip | Bin 0 -> 1457951 bytes .../klauspost/compress/zstd/testdata/xml.zst | Bin 0 -> 454654 bytes .../klauspost/compress/zstd/testdata/z000028 | Bin 0 -> 39807 bytes .../compress/zstd/testdata/z000028.zst | Bin 0 -> 15383 bytes github.com/klauspost/compress/zstd/zstd.go | 144 + .../klauspost/compress/zstd/zstd_test.go | 28 + github.com/lib/pq/.gitignore | 4 + github.com/lib/pq/.travis.sh | 73 + github.com/lib/pq/.travis.yml | 44 + github.com/lib/pq/LICENSE.md | 8 + github.com/lib/pq/README.md | 33 + github.com/lib/pq/TESTS.md | 33 + github.com/lib/pq/array.go | 756 ++ github.com/lib/pq/array_test.go | 1311 +++ github.com/lib/pq/auth/kerberos/go.mod | 8 + github.com/lib/pq/auth/kerberos/go.sum | 40 + github.com/lib/pq/auth/kerberos/krb.go | 29 + github.com/lib/pq/auth/kerberos/krb_unix.go | 127 + .../lib/pq/auth/kerberos/krb_windows.go | 66 + github.com/lib/pq/bench_test.go | 434 + github.com/lib/pq/buf.go | 91 + github.com/lib/pq/buf_test.go | 16 + github.com/lib/pq/certs/README | 3 + github.com/lib/pq/certs/bogus_root.crt | 19 + github.com/lib/pq/certs/postgresql.crt | 69 + github.com/lib/pq/certs/postgresql.key | 15 + github.com/lib/pq/certs/root.crt | 24 + github.com/lib/pq/certs/server.crt | 81 + github.com/lib/pq/certs/server.key | 27 + github.com/lib/pq/conn.go | 1996 ++++ github.com/lib/pq/conn_go18.go | 149 + github.com/lib/pq/conn_test.go | 1777 ++++ github.com/lib/pq/connector.go | 115 + github.com/lib/pq/connector_example_test.go | 29 + github.com/lib/pq/connector_test.go | 67 + github.com/lib/pq/copy.go | 307 + github.com/lib/pq/copy_test.go | 477 + github.com/lib/pq/doc.go | 263 + github.com/lib/pq/encode.go | 622 ++ github.com/lib/pq/encode_test.go | 845 ++ github.com/lib/pq/error.go | 515 + github.com/lib/pq/example/listen/doc.go | 98 + github.com/lib/pq/go.mod | 3 + github.com/lib/pq/go18_test.go | 319 + github.com/lib/pq/go19_test.go | 98 + github.com/lib/pq/hstore/hstore.go | 118 + github.com/lib/pq/hstore/hstore_test.go | 148 + github.com/lib/pq/issues_test.go | 26 + github.com/lib/pq/krb.go | 27 + github.com/lib/pq/notice.go | 71 + github.com/lib/pq/notice_example_test.go | 33 + github.com/lib/pq/notice_test.go | 49 + github.com/lib/pq/notify.go | 858 ++ github.com/lib/pq/notify_test.go | 612 ++ github.com/lib/pq/oid/doc.go | 6 + github.com/lib/pq/oid/gen.go | 93 + github.com/lib/pq/oid/types.go | 343 + github.com/lib/pq/rows.go | 93 + github.com/lib/pq/rows_test.go | 218 + github.com/lib/pq/scram/scram.go | 264 + github.com/lib/pq/ssl.go | 175 + github.com/lib/pq/ssl_permissions.go | 20 + github.com/lib/pq/ssl_test.go | 279 + github.com/lib/pq/ssl_windows.go | 9 + github.com/lib/pq/url.go | 76 + github.com/lib/pq/url_test.go | 66 + github.com/lib/pq/user_posix.go | 24 + github.com/lib/pq/user_windows.go | 27 + github.com/lib/pq/uuid.go | 23 + github.com/lib/pq/uuid_test.go | 46 + github.com/xlsx-reader/.gitignore | 1 + github.com/xlsx-reader/excelTime.go | 125 + github.com/xlsx-reader/go.mod | 3 + github.com/xlsx-reader/go.sum | 6 + github.com/xlsx-reader/hasher_vorlage.xlsx | Bin 0 -> 6179 bytes github.com/xlsx-reader/openXml.go | 122 + github.com/xlsx-reader/reader.go | 558 + github.com/xlsx-reader/reader_test.go | 165 + github.com/xlsx-reader/readme.md | 48 + .../xlsx-reader/testfiles/test300k.xlsx | Bin 0 -> 11369624 bytes helper/tools/tools.go | 181 + 379 files changed, 94246 insertions(+) create mode 100644 github.com/klauspost/compress/.gitattributes create mode 100644 github.com/klauspost/compress/.gitignore create mode 100644 github.com/klauspost/compress/.goreleaser.yml create mode 100644 github.com/klauspost/compress/.travis.yml create mode 100644 github.com/klauspost/compress/LICENSE create mode 100644 github.com/klauspost/compress/README.md create mode 100644 github.com/klauspost/compress/compressible.go create mode 100644 github.com/klauspost/compress/compressible_test.go create mode 100644 github.com/klauspost/compress/flate/deflate.go create mode 100644 github.com/klauspost/compress/flate/deflate_test.go create mode 100644 github.com/klauspost/compress/flate/dict_decoder.go create mode 100644 github.com/klauspost/compress/flate/dict_decoder_test.go create mode 100644 github.com/klauspost/compress/flate/fast_encoder.go create mode 100644 github.com/klauspost/compress/flate/flate_test.go create mode 100644 github.com/klauspost/compress/flate/gen.go create mode 100644 github.com/klauspost/compress/flate/gen_inflate.go create mode 100644 github.com/klauspost/compress/flate/huffman_bit_writer.go create mode 100644 github.com/klauspost/compress/flate/huffman_bit_writer_test.go create mode 100644 github.com/klauspost/compress/flate/huffman_code.go create mode 100644 github.com/klauspost/compress/flate/huffman_sortByFreq.go create mode 100644 github.com/klauspost/compress/flate/huffman_sortByLiteral.go create mode 100644 github.com/klauspost/compress/flate/inflate.go create mode 100644 github.com/klauspost/compress/flate/inflate_gen.go create mode 100644 github.com/klauspost/compress/flate/inflate_test.go create mode 100644 github.com/klauspost/compress/flate/level1.go create mode 100644 github.com/klauspost/compress/flate/level2.go create mode 100644 github.com/klauspost/compress/flate/level3.go create mode 100644 github.com/klauspost/compress/flate/level4.go create mode 100644 github.com/klauspost/compress/flate/level5.go create mode 100644 github.com/klauspost/compress/flate/level6.go create mode 100644 github.com/klauspost/compress/flate/reader_test.go create mode 100644 github.com/klauspost/compress/flate/stateless.go create mode 100644 github.com/klauspost/compress/flate/testdata/huffman-null-max.dyn.expect create mode 100644 github.com/klauspost/compress/flate/testdata/huffman-null-max.dyn.expect-noinput create mode 100644 github.com/klauspost/compress/flate/testdata/huffman-null-max.golden create mode 100644 github.com/klauspost/compress/flate/testdata/huffman-null-max.in create mode 100644 github.com/klauspost/compress/flate/testdata/huffman-null-max.sync.expect create mode 100644 github.com/klauspost/compress/flate/testdata/huffman-null-max.sync.expect-noinput create mode 100644 github.com/klauspost/compress/flate/testdata/huffman-null-max.wb.expect create mode 100644 github.com/klauspost/compress/flate/testdata/huffman-null-max.wb.expect-noinput create mode 100644 github.com/klauspost/compress/flate/testdata/huffman-pi.dyn.expect create mode 100644 github.com/klauspost/compress/flate/testdata/huffman-pi.dyn.expect-noinput create mode 100644 github.com/klauspost/compress/flate/testdata/huffman-pi.golden create mode 100644 github.com/klauspost/compress/flate/testdata/huffman-pi.in create mode 100644 github.com/klauspost/compress/flate/testdata/huffman-pi.sync.expect create mode 100644 github.com/klauspost/compress/flate/testdata/huffman-pi.sync.expect-noinput create mode 100644 github.com/klauspost/compress/flate/testdata/huffman-pi.wb.expect create mode 100644 github.com/klauspost/compress/flate/testdata/huffman-pi.wb.expect-noinput create mode 100644 github.com/klauspost/compress/flate/testdata/huffman-rand-1k.dyn.expect create mode 100644 github.com/klauspost/compress/flate/testdata/huffman-rand-1k.dyn.expect-noinput create mode 100644 github.com/klauspost/compress/flate/testdata/huffman-rand-1k.golden create mode 100644 github.com/klauspost/compress/flate/testdata/huffman-rand-1k.in create mode 100644 github.com/klauspost/compress/flate/testdata/huffman-rand-1k.sync.expect create mode 100644 github.com/klauspost/compress/flate/testdata/huffman-rand-1k.sync.expect-noinput create mode 100644 github.com/klauspost/compress/flate/testdata/huffman-rand-1k.wb.expect create mode 100644 github.com/klauspost/compress/flate/testdata/huffman-rand-1k.wb.expect-noinput create mode 100644 github.com/klauspost/compress/flate/testdata/huffman-rand-limit.dyn.expect create mode 100644 github.com/klauspost/compress/flate/testdata/huffman-rand-limit.dyn.expect-noinput create mode 100644 github.com/klauspost/compress/flate/testdata/huffman-rand-limit.golden create mode 100644 github.com/klauspost/compress/flate/testdata/huffman-rand-limit.in create mode 100644 github.com/klauspost/compress/flate/testdata/huffman-rand-limit.sync.expect create mode 100644 github.com/klauspost/compress/flate/testdata/huffman-rand-limit.sync.expect-noinput create mode 100644 github.com/klauspost/compress/flate/testdata/huffman-rand-limit.wb.expect create mode 100644 github.com/klauspost/compress/flate/testdata/huffman-rand-limit.wb.expect-noinput create mode 100644 github.com/klauspost/compress/flate/testdata/huffman-rand-max.golden create mode 100644 github.com/klauspost/compress/flate/testdata/huffman-rand-max.in create mode 100644 github.com/klauspost/compress/flate/testdata/huffman-shifts.dyn.expect create mode 100644 github.com/klauspost/compress/flate/testdata/huffman-shifts.dyn.expect-noinput create mode 100644 github.com/klauspost/compress/flate/testdata/huffman-shifts.golden create mode 100644 github.com/klauspost/compress/flate/testdata/huffman-shifts.in create mode 100644 github.com/klauspost/compress/flate/testdata/huffman-shifts.sync.expect create mode 100644 github.com/klauspost/compress/flate/testdata/huffman-shifts.sync.expect-noinput create mode 100644 github.com/klauspost/compress/flate/testdata/huffman-shifts.wb.expect create mode 100644 github.com/klauspost/compress/flate/testdata/huffman-shifts.wb.expect-noinput create mode 100644 github.com/klauspost/compress/flate/testdata/huffman-text-shift.dyn.expect create mode 100644 github.com/klauspost/compress/flate/testdata/huffman-text-shift.dyn.expect-noinput create mode 100644 github.com/klauspost/compress/flate/testdata/huffman-text-shift.golden create mode 100644 github.com/klauspost/compress/flate/testdata/huffman-text-shift.in create mode 100644 github.com/klauspost/compress/flate/testdata/huffman-text-shift.sync.expect create mode 100644 github.com/klauspost/compress/flate/testdata/huffman-text-shift.sync.expect-noinput create mode 100644 github.com/klauspost/compress/flate/testdata/huffman-text-shift.wb.expect create mode 100644 github.com/klauspost/compress/flate/testdata/huffman-text-shift.wb.expect-noinput create mode 100644 github.com/klauspost/compress/flate/testdata/huffman-text.dyn.expect create mode 100644 github.com/klauspost/compress/flate/testdata/huffman-text.dyn.expect-noinput create mode 100644 github.com/klauspost/compress/flate/testdata/huffman-text.golden create mode 100644 github.com/klauspost/compress/flate/testdata/huffman-text.in create mode 100644 github.com/klauspost/compress/flate/testdata/huffman-text.sync.expect create mode 100644 github.com/klauspost/compress/flate/testdata/huffman-text.sync.expect-noinput create mode 100644 github.com/klauspost/compress/flate/testdata/huffman-text.wb.expect create mode 100644 github.com/klauspost/compress/flate/testdata/huffman-text.wb.expect-noinput create mode 100644 github.com/klauspost/compress/flate/testdata/huffman-zero.dyn.expect create mode 100644 github.com/klauspost/compress/flate/testdata/huffman-zero.dyn.expect-noinput create mode 100644 github.com/klauspost/compress/flate/testdata/huffman-zero.golden create mode 100644 github.com/klauspost/compress/flate/testdata/huffman-zero.in create mode 100644 github.com/klauspost/compress/flate/testdata/huffman-zero.sync.expect create mode 100644 github.com/klauspost/compress/flate/testdata/huffman-zero.sync.expect-noinput create mode 100644 github.com/klauspost/compress/flate/testdata/huffman-zero.wb.expect create mode 100644 github.com/klauspost/compress/flate/testdata/huffman-zero.wb.expect-noinput create mode 100644 github.com/klauspost/compress/flate/testdata/null-long-match.dyn.expect-noinput create mode 100644 github.com/klauspost/compress/flate/testdata/null-long-match.sync.expect-noinput create mode 100644 github.com/klauspost/compress/flate/testdata/null-long-match.wb.expect-noinput create mode 100644 github.com/klauspost/compress/flate/testdata/regression.zip create mode 100644 github.com/klauspost/compress/flate/testdata/tokens.bin create mode 100644 github.com/klauspost/compress/flate/token.go create mode 100644 github.com/klauspost/compress/flate/token_test.go create mode 100644 github.com/klauspost/compress/flate/writer_test.go create mode 100644 github.com/klauspost/compress/fse/README.md create mode 100644 github.com/klauspost/compress/fse/bitreader.go create mode 100644 github.com/klauspost/compress/fse/bitwriter.go create mode 100644 github.com/klauspost/compress/fse/bytereader.go create mode 100644 github.com/klauspost/compress/fse/compress.go create mode 100644 github.com/klauspost/compress/fse/decompress.go create mode 100644 github.com/klauspost/compress/fse/fse.go create mode 100644 github.com/klauspost/compress/fse/fse_test.go create mode 100644 github.com/klauspost/compress/go.mod create mode 100644 github.com/klauspost/compress/gzip/example_test.go create mode 100644 github.com/klauspost/compress/gzip/gunzip.go create mode 100644 github.com/klauspost/compress/gzip/gunzip_test.go create mode 100644 github.com/klauspost/compress/gzip/gzip.go create mode 100644 github.com/klauspost/compress/gzip/gzip_test.go create mode 100644 github.com/klauspost/compress/gzip/testdata/issue6550.gz create mode 100644 github.com/klauspost/compress/gzip/testdata/test.json create mode 100644 github.com/klauspost/compress/huff0/.gitignore create mode 100644 github.com/klauspost/compress/huff0/README.md create mode 100644 github.com/klauspost/compress/huff0/bitreader.go create mode 100644 github.com/klauspost/compress/huff0/bitwriter.go create mode 100644 github.com/klauspost/compress/huff0/bytereader.go create mode 100644 github.com/klauspost/compress/huff0/compress.go create mode 100644 github.com/klauspost/compress/huff0/compress_test.go create mode 100644 github.com/klauspost/compress/huff0/decompress.go create mode 100644 github.com/klauspost/compress/huff0/decompress_test.go create mode 100644 github.com/klauspost/compress/huff0/huff0.go create mode 100644 github.com/klauspost/compress/huff0/testdata/regression.zip create mode 100644 github.com/klauspost/compress/s2/.gitignore create mode 100644 github.com/klauspost/compress/s2/LICENSE create mode 100644 github.com/klauspost/compress/s2/README.md create mode 100644 github.com/klauspost/compress/s2/_generate/gen.go create mode 100644 github.com/klauspost/compress/s2/_generate/go.mod create mode 100644 github.com/klauspost/compress/s2/_generate/go.sum create mode 100644 github.com/klauspost/compress/s2/cmd/internal/readahead/LICENSE create mode 100644 github.com/klauspost/compress/s2/cmd/internal/readahead/README.md create mode 100644 github.com/klauspost/compress/s2/cmd/internal/readahead/reader.go create mode 100644 github.com/klauspost/compress/s2/cmd/s2c/main.go create mode 100644 github.com/klauspost/compress/s2/cmd/s2d/main.go create mode 100644 github.com/klauspost/compress/s2/cpuid_amd64.go create mode 100644 github.com/klauspost/compress/s2/cpuid_amd64.s create mode 100644 github.com/klauspost/compress/s2/decode.go create mode 100644 github.com/klauspost/compress/s2/decode_amd64.go create mode 100644 github.com/klauspost/compress/s2/decode_amd64.s create mode 100644 github.com/klauspost/compress/s2/decode_other.go create mode 100644 github.com/klauspost/compress/s2/decode_test.go create mode 100644 github.com/klauspost/compress/s2/encode.go create mode 100644 github.com/klauspost/compress/s2/encode_all.go create mode 100644 github.com/klauspost/compress/s2/encode_amd64.go create mode 100644 github.com/klauspost/compress/s2/encode_better.go create mode 100644 github.com/klauspost/compress/s2/encode_go.go create mode 100644 github.com/klauspost/compress/s2/encode_test.go create mode 100644 github.com/klauspost/compress/s2/encodeblock_amd64.go create mode 100644 github.com/klauspost/compress/s2/encodeblock_amd64.s create mode 100644 github.com/klauspost/compress/s2/s2.go create mode 100644 github.com/klauspost/compress/s2/s2_test.go create mode 100644 github.com/klauspost/compress/s2/testdata/4f9e1a0da7915a3d69632f5613ed78bc998a8a23.zst create mode 100644 github.com/klauspost/compress/s2/testdata/Mark.Twain-Tom.Sawyer.txt create mode 100644 github.com/klauspost/compress/s2/testdata/Mark.Twain-Tom.Sawyer.txt.rawsnappy create mode 100644 github.com/klauspost/compress/s2/testdata/dec-block-regressions.zip create mode 100644 github.com/klauspost/compress/s2/testdata/enc_regressions.zip create mode 100644 github.com/klauspost/compress/s2/testdata/random create mode 100644 github.com/klauspost/compress/snappy/.gitignore create mode 100644 github.com/klauspost/compress/snappy/AUTHORS create mode 100644 github.com/klauspost/compress/snappy/CONTRIBUTORS create mode 100644 github.com/klauspost/compress/snappy/LICENSE create mode 100644 github.com/klauspost/compress/snappy/README create mode 100644 github.com/klauspost/compress/snappy/decode.go create mode 100644 github.com/klauspost/compress/snappy/decode_amd64.go create mode 100644 github.com/klauspost/compress/snappy/decode_amd64.s create mode 100644 github.com/klauspost/compress/snappy/decode_other.go create mode 100644 github.com/klauspost/compress/snappy/encode.go create mode 100644 github.com/klauspost/compress/snappy/encode_amd64.go create mode 100644 github.com/klauspost/compress/snappy/encode_amd64.s create mode 100644 github.com/klauspost/compress/snappy/encode_other.go create mode 100644 github.com/klauspost/compress/snappy/golden_test.go create mode 100644 github.com/klauspost/compress/snappy/runbench.cmd create mode 100644 github.com/klauspost/compress/snappy/snappy.go create mode 100644 github.com/klauspost/compress/snappy/snappy_test.go create mode 100644 github.com/klauspost/compress/snappy/testdata/Mark.Twain-Tom.Sawyer.txt create mode 100644 github.com/klauspost/compress/snappy/testdata/Mark.Twain-Tom.Sawyer.txt.rawsnappy create mode 100644 github.com/klauspost/compress/snappy/testdata/random create mode 100644 github.com/klauspost/compress/testdata/Mark.Twain-Tom.Sawyer.txt create mode 100644 github.com/klauspost/compress/testdata/case1.bin create mode 100644 github.com/klauspost/compress/testdata/case2.bin create mode 100644 github.com/klauspost/compress/testdata/case3.bin create mode 100644 github.com/klauspost/compress/testdata/crash1.bin create mode 100644 github.com/klauspost/compress/testdata/crash2.bin create mode 100644 github.com/klauspost/compress/testdata/crash3.bin create mode 100644 github.com/klauspost/compress/testdata/crash4.bin create mode 100644 github.com/klauspost/compress/testdata/crash5.bin create mode 100644 github.com/klauspost/compress/testdata/dec-crash6.bin create mode 100644 github.com/klauspost/compress/testdata/dec-hang1.bin create mode 100644 github.com/klauspost/compress/testdata/dec-hang2.bin create mode 100644 github.com/klauspost/compress/testdata/dec-hang3.bin create mode 100644 github.com/klauspost/compress/testdata/dec-symlen1.bin create mode 100644 github.com/klauspost/compress/testdata/e.txt create mode 100644 github.com/klauspost/compress/testdata/endnonzero.bin create mode 100644 github.com/klauspost/compress/testdata/endzerobits.bin create mode 100644 github.com/klauspost/compress/testdata/fse-artifact3.bin create mode 100644 github.com/klauspost/compress/testdata/gettysburg.txt create mode 100644 github.com/klauspost/compress/testdata/html.txt create mode 100644 github.com/klauspost/compress/testdata/normcount2.bin create mode 100644 github.com/klauspost/compress/testdata/pi.txt create mode 100644 github.com/klauspost/compress/testdata/pngdata.bin create mode 100644 github.com/klauspost/compress/testdata/sharnd.out create mode 100644 github.com/klauspost/compress/zip/example_test.go create mode 100644 github.com/klauspost/compress/zip/reader.go create mode 100644 github.com/klauspost/compress/zip/reader_test.go create mode 100644 github.com/klauspost/compress/zip/register.go create mode 100644 github.com/klauspost/compress/zip/struct.go create mode 100644 github.com/klauspost/compress/zip/testdata/crc32-not-streamed.zip create mode 100644 github.com/klauspost/compress/zip/testdata/dd.zip create mode 100644 github.com/klauspost/compress/zip/testdata/go-no-datadesc-sig.zip create mode 100644 github.com/klauspost/compress/zip/testdata/go-with-datadesc-sig.zip create mode 100644 github.com/klauspost/compress/zip/testdata/gophercolor16x16.png create mode 100644 github.com/klauspost/compress/zip/testdata/readme.notzip create mode 100644 github.com/klauspost/compress/zip/testdata/readme.zip create mode 100644 github.com/klauspost/compress/zip/testdata/symlink.zip create mode 100644 github.com/klauspost/compress/zip/testdata/test-trailing-junk.zip create mode 100644 github.com/klauspost/compress/zip/testdata/test.zip create mode 100644 github.com/klauspost/compress/zip/testdata/time-22738.zip create mode 100644 github.com/klauspost/compress/zip/testdata/time-7zip.zip create mode 100644 github.com/klauspost/compress/zip/testdata/time-go.zip create mode 100644 github.com/klauspost/compress/zip/testdata/time-infozip.zip create mode 100644 github.com/klauspost/compress/zip/testdata/time-osx.zip create mode 100644 github.com/klauspost/compress/zip/testdata/time-win7.zip create mode 100644 github.com/klauspost/compress/zip/testdata/time-winrar.zip create mode 100644 github.com/klauspost/compress/zip/testdata/time-winzip.zip create mode 100644 github.com/klauspost/compress/zip/testdata/unix.zip create mode 100644 github.com/klauspost/compress/zip/testdata/utf8-7zip.zip create mode 100644 github.com/klauspost/compress/zip/testdata/utf8-infozip.zip create mode 100644 github.com/klauspost/compress/zip/testdata/utf8-osx.zip create mode 100644 github.com/klauspost/compress/zip/testdata/utf8-winrar.zip create mode 100644 github.com/klauspost/compress/zip/testdata/utf8-winzip.zip create mode 100644 github.com/klauspost/compress/zip/testdata/winxp.zip create mode 100644 github.com/klauspost/compress/zip/testdata/zip64-2.zip create mode 100644 github.com/klauspost/compress/zip/testdata/zip64.zip create mode 100644 github.com/klauspost/compress/zip/writer.go create mode 100644 github.com/klauspost/compress/zip/writer_test.go create mode 100644 github.com/klauspost/compress/zip/zip_test.go create mode 100644 github.com/klauspost/compress/zlib/example_test.go create mode 100644 github.com/klauspost/compress/zlib/reader.go create mode 100644 github.com/klauspost/compress/zlib/reader_test.go create mode 100644 github.com/klauspost/compress/zlib/writer.go create mode 100644 github.com/klauspost/compress/zlib/writer_test.go create mode 100644 github.com/klauspost/compress/zstd/README.md create mode 100644 github.com/klauspost/compress/zstd/bitreader.go create mode 100644 github.com/klauspost/compress/zstd/bitwriter.go create mode 100644 github.com/klauspost/compress/zstd/blockdec.go create mode 100644 github.com/klauspost/compress/zstd/blockenc.go create mode 100644 github.com/klauspost/compress/zstd/blocktype_string.go create mode 100644 github.com/klauspost/compress/zstd/bytebuf.go create mode 100644 github.com/klauspost/compress/zstd/bytereader.go create mode 100644 github.com/klauspost/compress/zstd/decoder.go create mode 100644 github.com/klauspost/compress/zstd/decoder_options.go create mode 100644 github.com/klauspost/compress/zstd/decoder_test.go create mode 100644 github.com/klauspost/compress/zstd/dict.go create mode 100644 github.com/klauspost/compress/zstd/dict_test.go create mode 100644 github.com/klauspost/compress/zstd/enc_better.go create mode 100644 github.com/klauspost/compress/zstd/enc_dfast.go create mode 100644 github.com/klauspost/compress/zstd/enc_fast.go create mode 100644 github.com/klauspost/compress/zstd/enc_params.go create mode 100644 github.com/klauspost/compress/zstd/encoder.go create mode 100644 github.com/klauspost/compress/zstd/encoder_options.go create mode 100644 github.com/klauspost/compress/zstd/encoder_options_test.go create mode 100644 github.com/klauspost/compress/zstd/encoder_test.go create mode 100644 github.com/klauspost/compress/zstd/framedec.go create mode 100644 github.com/klauspost/compress/zstd/frameenc.go create mode 100644 github.com/klauspost/compress/zstd/fse_decoder.go create mode 100644 github.com/klauspost/compress/zstd/fse_encoder.go create mode 100644 github.com/klauspost/compress/zstd/fse_predefined.go create mode 100644 github.com/klauspost/compress/zstd/hash.go create mode 100644 github.com/klauspost/compress/zstd/history.go create mode 100644 github.com/klauspost/compress/zstd/internal/xxhash/LICENSE.txt create mode 100644 github.com/klauspost/compress/zstd/internal/xxhash/README.md create mode 100644 github.com/klauspost/compress/zstd/internal/xxhash/xxhash.go create mode 100644 github.com/klauspost/compress/zstd/internal/xxhash/xxhash_amd64.go create mode 100644 github.com/klauspost/compress/zstd/internal/xxhash/xxhash_amd64.s create mode 100644 github.com/klauspost/compress/zstd/internal/xxhash/xxhash_other.go create mode 100644 github.com/klauspost/compress/zstd/internal/xxhash/xxhash_safe.go create mode 100644 github.com/klauspost/compress/zstd/internal/xxhash/xxhash_test.go create mode 100644 github.com/klauspost/compress/zstd/seqdec.go create mode 100644 github.com/klauspost/compress/zstd/seqenc.go create mode 100644 github.com/klauspost/compress/zstd/snappy.go create mode 100644 github.com/klauspost/compress/zstd/snappy_test.go create mode 100644 github.com/klauspost/compress/zstd/testdata/bad.zip create mode 100644 github.com/klauspost/compress/zstd/testdata/benchdecoder.zip create mode 100644 github.com/klauspost/compress/zstd/testdata/comp-crashers.zip create mode 100644 github.com/klauspost/compress/zstd/testdata/decoder.zip create mode 100644 github.com/klauspost/compress/zstd/testdata/dict-tests-small.zip create mode 100644 github.com/klauspost/compress/zstd/testdata/good.zip create mode 100644 github.com/klauspost/compress/zstd/testdata/large.zip create mode 100644 github.com/klauspost/compress/zstd/testdata/regression.zip create mode 100644 github.com/klauspost/compress/zstd/testdata/xml.zst create mode 100644 github.com/klauspost/compress/zstd/testdata/z000028 create mode 100644 github.com/klauspost/compress/zstd/testdata/z000028.zst create mode 100644 github.com/klauspost/compress/zstd/zstd.go create mode 100644 github.com/klauspost/compress/zstd/zstd_test.go create mode 100644 github.com/lib/pq/.gitignore create mode 100644 github.com/lib/pq/.travis.sh create mode 100644 github.com/lib/pq/.travis.yml create mode 100644 github.com/lib/pq/LICENSE.md create mode 100644 github.com/lib/pq/README.md create mode 100644 github.com/lib/pq/TESTS.md create mode 100644 github.com/lib/pq/array.go create mode 100644 github.com/lib/pq/array_test.go create mode 100644 github.com/lib/pq/auth/kerberos/go.mod create mode 100644 github.com/lib/pq/auth/kerberos/go.sum create mode 100644 github.com/lib/pq/auth/kerberos/krb.go create mode 100644 github.com/lib/pq/auth/kerberos/krb_unix.go create mode 100644 github.com/lib/pq/auth/kerberos/krb_windows.go create mode 100644 github.com/lib/pq/bench_test.go create mode 100644 github.com/lib/pq/buf.go create mode 100644 github.com/lib/pq/buf_test.go create mode 100644 github.com/lib/pq/certs/README create mode 100644 github.com/lib/pq/certs/bogus_root.crt create mode 100644 github.com/lib/pq/certs/postgresql.crt create mode 100644 github.com/lib/pq/certs/postgresql.key create mode 100644 github.com/lib/pq/certs/root.crt create mode 100644 github.com/lib/pq/certs/server.crt create mode 100644 github.com/lib/pq/certs/server.key create mode 100644 github.com/lib/pq/conn.go create mode 100644 github.com/lib/pq/conn_go18.go create mode 100644 github.com/lib/pq/conn_test.go create mode 100644 github.com/lib/pq/connector.go create mode 100644 github.com/lib/pq/connector_example_test.go create mode 100644 github.com/lib/pq/connector_test.go create mode 100644 github.com/lib/pq/copy.go create mode 100644 github.com/lib/pq/copy_test.go create mode 100644 github.com/lib/pq/doc.go create mode 100644 github.com/lib/pq/encode.go create mode 100644 github.com/lib/pq/encode_test.go create mode 100644 github.com/lib/pq/error.go create mode 100644 github.com/lib/pq/example/listen/doc.go create mode 100644 github.com/lib/pq/go.mod create mode 100644 github.com/lib/pq/go18_test.go create mode 100644 github.com/lib/pq/go19_test.go create mode 100644 github.com/lib/pq/hstore/hstore.go create mode 100644 github.com/lib/pq/hstore/hstore_test.go create mode 100644 github.com/lib/pq/issues_test.go create mode 100644 github.com/lib/pq/krb.go create mode 100644 github.com/lib/pq/notice.go create mode 100644 github.com/lib/pq/notice_example_test.go create mode 100644 github.com/lib/pq/notice_test.go create mode 100644 github.com/lib/pq/notify.go create mode 100644 github.com/lib/pq/notify_test.go create mode 100644 github.com/lib/pq/oid/doc.go create mode 100644 github.com/lib/pq/oid/gen.go create mode 100644 github.com/lib/pq/oid/types.go create mode 100644 github.com/lib/pq/rows.go create mode 100644 github.com/lib/pq/rows_test.go create mode 100644 github.com/lib/pq/scram/scram.go create mode 100644 github.com/lib/pq/ssl.go create mode 100644 github.com/lib/pq/ssl_permissions.go create mode 100644 github.com/lib/pq/ssl_test.go create mode 100644 github.com/lib/pq/ssl_windows.go create mode 100644 github.com/lib/pq/url.go create mode 100644 github.com/lib/pq/url_test.go create mode 100644 github.com/lib/pq/user_posix.go create mode 100644 github.com/lib/pq/user_windows.go create mode 100644 github.com/lib/pq/uuid.go create mode 100644 github.com/lib/pq/uuid_test.go create mode 100644 github.com/xlsx-reader/.gitignore create mode 100644 github.com/xlsx-reader/excelTime.go create mode 100644 github.com/xlsx-reader/go.mod create mode 100644 github.com/xlsx-reader/go.sum create mode 100644 github.com/xlsx-reader/hasher_vorlage.xlsx create mode 100644 github.com/xlsx-reader/openXml.go create mode 100644 github.com/xlsx-reader/reader.go create mode 100644 github.com/xlsx-reader/reader_test.go create mode 100644 github.com/xlsx-reader/readme.md create mode 100644 github.com/xlsx-reader/testfiles/test300k.xlsx create mode 100644 helper/tools/tools.go diff --git a/github.com/klauspost/compress/.gitattributes b/github.com/klauspost/compress/.gitattributes new file mode 100644 index 0000000..e1c269d --- /dev/null +++ b/github.com/klauspost/compress/.gitattributes @@ -0,0 +1 @@ +*.bin -text -diff diff --git a/github.com/klauspost/compress/.gitignore b/github.com/klauspost/compress/.gitignore new file mode 100644 index 0000000..daf913b --- /dev/null +++ b/github.com/klauspost/compress/.gitignore @@ -0,0 +1,24 @@ +# Compiled Object files, Static and Dynamic libs (Shared Objects) +*.o +*.a +*.so + +# Folders +_obj +_test + +# Architecture specific extensions/prefixes +*.[568vq] +[568vq].out + +*.cgo1.go +*.cgo2.c +_cgo_defun.c +_cgo_gotypes.go +_cgo_export.* + +_testmain.go + +*.exe +*.test +*.prof diff --git a/github.com/klauspost/compress/.goreleaser.yml b/github.com/klauspost/compress/.goreleaser.yml new file mode 100644 index 0000000..bf49ec8 --- /dev/null +++ b/github.com/klauspost/compress/.goreleaser.yml @@ -0,0 +1,98 @@ +# This is an example goreleaser.yaml file with some sane defaults. +# Make sure to check the documentation at http://goreleaser.com +before: + hooks: +builds: + - + id: "s2c" + binary: s2c + main: ./s2/cmd/s2c/main.go + env: + - CGO_ENABLED=0 + goos: + - linux + - freebsd + - netbsd + - windows + goarch: + - 386 + - amd64 + - arm + - arm64 + - ppc64 + - ppc64le + - mips64 + - mips64le + goarm: + - 7 + - + id: "s2d" + binary: s2d + main: ./s2/cmd/s2d/main.go + env: + - CGO_ENABLED=0 + goos: + - linux + - freebsd + - netbsd + - windows + goarch: + - 386 + - amd64 + - arm + - arm64 + - ppc64 + - ppc64le + - mips64 + - mips64le + goarm: + - 7 + +archives: + - + id: s2-binaries + name_template: "s2-cmds_{{ .Version }}_{{ .Os }}_{{ .Arch }}" + replacements: + darwin: Darwin + linux: Linux + windows: Windows + 386: i386 + amd64: x86_64 + freebsd: FreeBSD + netbsd: NetBSD + format_overrides: + - goos: windows + format: zip + files: + - s2/LICENSE + - s2/README.md +checksum: + name_template: 'checksums.txt' +snapshot: + name_template: "s2-cmds_{{ .Tag }}-next" +changelog: + sort: asc + filters: + exclude: + - '^doc:' + - '^docs:' + - '^test:' + - '^tests:' + - '^Update\sREADME.md' + +nfpms: + - + name_template: "s2-cmds_{{ .Version }}_{{ .Os }}_{{ .Arch }}" + vendor: Klaus Post + homepage: https://github.com/klauspost/compress + maintainer: Klaus Post + description: S2 Compression Tool + license: BSD 3-Clause + formats: + - deb + - rpm + replacements: + darwin: Darwin + linux: Linux + freebsd: FreeBSD + amd64: x86_64 diff --git a/github.com/klauspost/compress/.travis.yml b/github.com/klauspost/compress/.travis.yml new file mode 100644 index 0000000..e5cd2a5 --- /dev/null +++ b/github.com/klauspost/compress/.travis.yml @@ -0,0 +1,45 @@ +language: go + +os: + - linux + - osx + +go: + - 1.12.x + - 1.13.x + - 1.14.x + - master + +env: + - GO111MODULE=off + +install: + - go get ./... + - go get github.com/klauspost/compress-fuzz + +script: + - diff <(gofmt -d .) <(printf "") + - IS_GO112=`go version | cut -d ' ' -f3 | grep 1.12`; if [ ! -z "$IS_GO112" ]; then echo 'Skipping vet on Go 1.12...'; else go vet ./...; fi + - go test -cpu=2 ./... + - go test -cpu=2 -tags=noasm ./... + - go test -cpu=1,4 -short -race ./... + - go build github.com/klauspost/compress/s2/cmd/s2c && go build github.com/klauspost/compress/s2/cmd/s2d && s2c s2c && s2d s2c.s2 && rm s2c && rm s2d && rm s2c.s2 + +jobs: + allow_failures: + - go: 'master' + fast_finish: true + include: + - stage: 386 linux test + go: 1.14.x + script: + - GOOS=linux GOARCH=386 go test -short ./... + +deploy: +- provider: script + skip_cleanup: true + script: curl -sL https://git.io/goreleaser | VERSION=v0.127.0 bash || true + on: + tags: true + condition: $TRAVIS_OS_NAME = linux + go: 1.14.x diff --git a/github.com/klauspost/compress/LICENSE b/github.com/klauspost/compress/LICENSE new file mode 100644 index 0000000..1eb75ef --- /dev/null +++ b/github.com/klauspost/compress/LICENSE @@ -0,0 +1,28 @@ +Copyright (c) 2012 The Go Authors. All rights reserved. +Copyright (c) 2019 Klaus Post. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the name of Google Inc. nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/github.com/klauspost/compress/README.md b/github.com/klauspost/compress/README.md new file mode 100644 index 0000000..d196091 --- /dev/null +++ b/github.com/klauspost/compress/README.md @@ -0,0 +1,300 @@ +# compress + +This package provides various compression algorithms. + +* [zstandard](https://github.com/klauspost/compress/tree/master/zstd#zstd) compression and decompression in pure Go. +* [S2](https://github.com/klauspost/compress/tree/master/s2#s2-compression) is a high performance replacement for Snappy. +* Optimized [deflate](https://godoc.org/github.com/klauspost/compress/flate) packages which can be used as a dropin replacement for [gzip](https://godoc.org/github.com/klauspost/compress/gzip), [zip](https://godoc.org/github.com/klauspost/compress/zip) and [zlib](https://godoc.org/github.com/klauspost/compress/zlib). +* [huff0](https://github.com/klauspost/compress/tree/master/huff0) and [FSE](https://github.com/klauspost/compress/tree/master/fse) implementations for raw entropy encoding. +* [pgzip](https://github.com/klauspost/pgzip) is a separate package that provides a very fast parallel gzip implementation. +* [fuzz package](https://github.com/klauspost/compress-fuzz) for fuzz testing all compressors/decompressors here. + +[![Documentation](https://godoc.org/github.com/klauspost/compress?status.svg)](https://pkg.go.dev/github.com/klauspost/compress?tab=subdirectories) +[![Build Status](https://travis-ci.org/klauspost/compress.svg?branch=master)](https://travis-ci.org/klauspost/compress) +[![Sourcegraph Badge](https://sourcegraph.com/github.com/klauspost/compress/-/badge.svg)](https://sourcegraph.com/github.com/klauspost/compress?badge) + +# changelog + +* June 23, 2020 (v1.10.10) zstd: Skip entropy compression in fastest mode when no matches. [#270](https://github.com/klauspost/compress/pull/270) +* June 16, 2020 (v1.10.9): zstd: API change for specifying dictionaries. See [#268](https://github.com/klauspost/compress/pull/268) +* June 16, 2020: zip: update CreateHeaderRaw to handle zip64 fields. [#266](https://github.com/klauspost/compress/pull/266) +* June 16, 2020: Fuzzit tests removed. The service has been purchased and is no longer available. +* June 5, 2020 (v1.10.8): 1.15x faster zstd block decompression. [#265](https://github.com/klauspost/compress/pull/265) +* June 1, 2020 (v1.10.7): Added zstd decompression [dictionary support](https://github.com/klauspost/compress/tree/master/zstd#dictionaries) +* June 1, 2020: Increase zstd decompression speed up to 1.19x. [#259](https://github.com/klauspost/compress/pull/259) +* June 1, 2020: Remove internal reset call in zstd compression and reduce allocations. [#263](https://github.com/klauspost/compress/pull/263) +* May 21, 2020: (v1.10.6) zstd: Reduce allocations while decoding. [#258](https://github.com/klauspost/compress/pull/258), [#252](https://github.com/klauspost/compress/pull/252) +* May 21, 2020: zstd: Stricter decompression checks. +* April 12, 2020: (v1.10.5) s2-commands: Flush output when receiving SIGINT. [#239](https://github.com/klauspost/compress/pull/239) +* Apr 8, 2020: (v1.10.4) zstd: Minor/special case optimizations. [#251](https://github.com/klauspost/compress/pull/251), [#250](https://github.com/klauspost/compress/pull/250), [#249](https://github.com/klauspost/compress/pull/249), [#247](https://github.com/klauspost/compress/pull/247) +* Mar 11, 2020: (v1.10.3) s2: Use S2 encoder in pure Go mode for Snappy output as well. [#245](https://github.com/klauspost/compress/pull/245) +* Mar 10, 2020: s2: Fix pure Go block encoder. [#244](https://github.com/klauspost/compress/pull/244) +* Mar 9, 2020: zstd: Added "better compression" mode. [#240](https://github.com/klauspost/compress/pull/240) +* Mar 9, 2020: zstd: Improve speed of fastest compression mode by 5-10% [#241](https://github.com/klauspost/compress/pull/241) +* Feb 28, 2020: zstd: Skip creating encoders when not needed. [#238](https://github.com/klauspost/compress/pull/238) +* Feb 27, 2020: (v1.10.2) Close to 50% speedup in inflate (gzip/zip decompression). [#236](https://github.com/klauspost/compress/pull/236) [#234](https://github.com/klauspost/compress/pull/234) [#232](https://github.com/klauspost/compress/pull/232) +* Feb 23, 2020: Reduce deflate level 1-6 memory usage up to 59%. [#227](https://github.com/klauspost/compress/pull/227) +* Feb 18, 2020: (v1.10.1) Fix zstd crash when resetting multiple times without sending data. [#226](https://github.com/klauspost/compress/pull/226) +* Feb 16, 2020: deflate: Fix dictionary use on level 1-6. [#224](https://github.com/klauspost/compress/pull/224) +* Feb 16, 2020: Remove deflate writer reference when closing. [#224](https://github.com/klauspost/compress/pull/224) +* Feb 4, 2020: (v1.10.0) Add optional dictionary to [stateless deflate](https://pkg.go.dev/github.com/klauspost/compress/flate?tab=doc#StatelessDeflate). Breaking change, send `nil` for previous behaviour. [#216](https://github.com/klauspost/compress/pull/216) +* Feb 3, 2020: Fix buffer overflow on repeated small block deflate. [#218](https://github.com/klauspost/compress/pull/218) +* Jan 31, 2020: Allow copying content from an existing ZIP file without decompressing+compressing. [#214](https://github.com/klauspost/compress/pull/214) +* Jan 28, 2020: Added [S2](https://github.com/klauspost/compress/tree/master/s2#s2-compression) AMD64 assembler and various optimizations. Stream speed >10GB/s. [#186](https://github.com/klauspost/compress/pull/186) + +
+ See changes prior to v1.10.0 + +* Jan 20,2020 (v1.9.8) Optimize gzip/deflate with better size estimates and faster table generation. [#207](https://github.com/klauspost/compress/pull/207) by [luyu6056](https://github.com/luyu6056), [#206](https://github.com/klauspost/compress/pull/206). +* Jan 11, 2020: S2 Encode/Decode will use provided buffer if capacity is big enough. [#204](https://github.com/klauspost/compress/pull/204) +* Jan 5, 2020: (v1.9.7) Fix another zstd regression in v1.9.5 - v1.9.6 removed. +* Jan 4, 2020: (v1.9.6) Regression in v1.9.5 fixed causing corrupt zstd encodes in rare cases. +* Jan 4, 2020: Faster IO in [s2c + s2d commandline tools](https://github.com/klauspost/compress/tree/master/s2#commandline-tools) compression/decompression. [#192](https://github.com/klauspost/compress/pull/192) +* Dec 29, 2019: Removed v1.9.5 since fuzz tests showed a compatibility problem with the reference zstandard decoder. +* Dec 29, 2019: (v1.9.5) zstd: 10-20% faster block compression. [#199](https://github.com/klauspost/compress/pull/199) +* Dec 29, 2019: [zip](https://godoc.org/github.com/klauspost/compress/zip) package updated with latest Go features +* Dec 29, 2019: zstd: Single segment flag condintions tweaked. [#197](https://github.com/klauspost/compress/pull/197) +* Dec 18, 2019: s2: Faster compression when ReadFrom is used. [#198](https://github.com/klauspost/compress/pull/198) +* Dec 10, 2019: s2: Fix repeat length output when just above at 16MB limit. +* Dec 10, 2019: zstd: Add function to get decoder as io.ReadCloser. [#191](https://github.com/klauspost/compress/pull/191) +* Dec 3, 2019: (v1.9.4) S2: limit max repeat length. [#188](https://github.com/klauspost/compress/pull/188) +* Dec 3, 2019: Add [WithNoEntropyCompression](https://godoc.org/github.com/klauspost/compress/zstd#WithNoEntropyCompression) to zstd [#187](https://github.com/klauspost/compress/pull/187) +* Dec 3, 2019: Reduce memory use for tests. Check for leaked goroutines. +* Nov 28, 2019 (v1.9.3) Less allocations in stateless deflate. +* Nov 28, 2019: 5-20% Faster huff0 decode. Impacts zstd as well. [#184](https://github.com/klauspost/compress/pull/184) +* Nov 12, 2019 (v1.9.2) Added [Stateless Compression](#stateless-compression) for gzip/deflate. +* Nov 12, 2019: Fixed zstd decompression of large single blocks. [#180](https://github.com/klauspost/compress/pull/180) +* Nov 11, 2019: Set default [s2c](https://github.com/klauspost/compress/tree/master/s2#commandline-tools) block size to 4MB. +* Nov 11, 2019: Reduce inflate memory use by 1KB. +* Nov 10, 2019: Less allocations in deflate bit writer. +* Nov 10, 2019: Fix inconsistent error returned by zstd decoder. +* Oct 28, 2019 (v1.9.1) ztsd: Fix crash when compressing blocks. [#174](https://github.com/klauspost/compress/pull/174) +* Oct 24, 2019 (v1.9.0) zstd: Fix rare data corruption [#173](https://github.com/klauspost/compress/pull/173) +* Oct 24, 2019 zstd: Fix huff0 out of buffer write [#171](https://github.com/klauspost/compress/pull/171) and always return errors [#172](https://github.com/klauspost/compress/pull/172) +* Oct 10, 2019: Big deflate rewrite, 30-40% faster with better compression [#105](https://github.com/klauspost/compress/pull/105) + +
+ +
+ See changes prior to v1.9.0 + +* Oct 10, 2019: (v1.8.6) zstd: Allow partial reads to get flushed data. [#169](https://github.com/klauspost/compress/pull/169) +* Oct 3, 2019: Fix inconsistent results on broken zstd streams. +* Sep 25, 2019: Added `-rm` (remove source files) and `-q` (no output except errors) to `s2c` and `s2d` [commands](https://github.com/klauspost/compress/tree/master/s2#commandline-tools) +* Sep 16, 2019: (v1.8.4) Add `s2c` and `s2d` [commandline tools](https://github.com/klauspost/compress/tree/master/s2#commandline-tools). +* Sep 10, 2019: (v1.8.3) Fix s2 decoder [Skip](https://godoc.org/github.com/klauspost/compress/s2#Reader.Skip). +* Sep 7, 2019: zstd: Added [WithWindowSize](https://godoc.org/github.com/klauspost/compress/zstd#WithWindowSize), contributed by [ianwilkes](https://github.com/ianwilkes). +* Sep 5, 2019: (v1.8.2) Add [WithZeroFrames](https://godoc.org/github.com/klauspost/compress/zstd#WithZeroFrames) which adds full zero payload block encoding option. +* Sep 5, 2019: Lazy initialization of zstandard predefined en/decoder tables. +* Aug 26, 2019: (v1.8.1) S2: 1-2% compression increase in "better" compression mode. +* Aug 26, 2019: zstd: Check maximum size of Huffman 1X compressed literals while decoding. +* Aug 24, 2019: (v1.8.0) Added [S2 compression](https://github.com/klauspost/compress/tree/master/s2#s2-compression), a high performance replacement for Snappy. +* Aug 21, 2019: (v1.7.6) Fixed minor issues found by fuzzer. One could lead to zstd not decompressing. +* Aug 18, 2019: Add [fuzzit](https://fuzzit.dev/) continuous fuzzing. +* Aug 14, 2019: zstd: Skip incompressible data 2x faster. [#147](https://github.com/klauspost/compress/pull/147) +* Aug 4, 2019 (v1.7.5): Better literal compression. [#146](https://github.com/klauspost/compress/pull/146) +* Aug 4, 2019: Faster zstd compression. [#143](https://github.com/klauspost/compress/pull/143) [#144](https://github.com/klauspost/compress/pull/144) +* Aug 4, 2019: Faster zstd decompression. [#145](https://github.com/klauspost/compress/pull/145) [#143](https://github.com/klauspost/compress/pull/143) [#142](https://github.com/klauspost/compress/pull/142) +* July 15, 2019 (v1.7.4): Fix double EOF block in rare cases on zstd encoder. +* July 15, 2019 (v1.7.3): Minor speedup/compression increase in default zstd encoder. +* July 14, 2019: zstd decoder: Fix decompression error on multiple uses with mixed content. +* July 7, 2019 (v1.7.2): Snappy update, zstd decoder potential race fix. +* June 17, 2019: zstd decompression bugfix. +* June 17, 2019: fix 32 bit builds. +* June 17, 2019: Easier use in modules (less dependencies). +* June 9, 2019: New stronger "default" [zstd](https://github.com/klauspost/compress/tree/master/zstd#zstd) compression mode. Matches zstd default compression ratio. +* June 5, 2019: 20-40% throughput in [zstandard](https://github.com/klauspost/compress/tree/master/zstd#zstd) compression and better compression. +* June 5, 2019: deflate/gzip compression: Reduce memory usage of lower compression levels. +* June 2, 2019: Added [zstandard](https://github.com/klauspost/compress/tree/master/zstd#zstd) compression! +* May 25, 2019: deflate/gzip: 10% faster bit writer, mostly visible in lower levels. +* Apr 22, 2019: [zstd](https://github.com/klauspost/compress/tree/master/zstd#zstd) decompression added. +* Aug 1, 2018: Added [huff0 README](https://github.com/klauspost/compress/tree/master/huff0#huff0-entropy-compression). +* Jul 8, 2018: Added [Performance Update 2018](#performance-update-2018) below. +* Jun 23, 2018: Merged [Go 1.11 inflate optimizations](https://go-review.googlesource.com/c/go/+/102235). Go 1.9 is now required. Backwards compatible version tagged with [v1.3.0](https://github.com/klauspost/compress/releases/tag/v1.3.0). +* Apr 2, 2018: Added [huff0](https://godoc.org/github.com/klauspost/compress/huff0) en/decoder. Experimental for now, API may change. +* Mar 4, 2018: Added [FSE Entropy](https://godoc.org/github.com/klauspost/compress/fse) en/decoder. Experimental for now, API may change. +* Nov 3, 2017: Add compression [Estimate](https://godoc.org/github.com/klauspost/compress#Estimate) function. +* May 28, 2017: Reduce allocations when resetting decoder. +* Apr 02, 2017: Change back to official crc32, since changes were merged in Go 1.7. +* Jan 14, 2017: Reduce stack pressure due to array copies. See [Issue #18625](https://github.com/golang/go/issues/18625). +* Oct 25, 2016: Level 2-4 have been rewritten and now offers significantly better performance than before. +* Oct 20, 2016: Port zlib changes from Go 1.7 to fix zlib writer issue. Please update. +* Oct 16, 2016: Go 1.7 changes merged. Apples to apples this package is a few percent faster, but has a significantly better balance between speed and compression per level. +* Mar 24, 2016: Always attempt Huffman encoding on level 4-7. This improves base 64 encoded data compression. +* Mar 24, 2016: Small speedup for level 1-3. +* Feb 19, 2016: Faster bit writer, level -2 is 15% faster, level 1 is 4% faster. +* Feb 19, 2016: Handle small payloads faster in level 1-3. +* Feb 19, 2016: Added faster level 2 + 3 compression modes. +* Feb 19, 2016: [Rebalanced compression levels](https://blog.klauspost.com/rebalancing-deflate-compression-levels/), so there is a more even progresssion in terms of compression. New default level is 5. +* Feb 14, 2016: Snappy: Merge upstream changes. +* Feb 14, 2016: Snappy: Fix aggressive skipping. +* Feb 14, 2016: Snappy: Update benchmark. +* Feb 13, 2016: Deflate: Fixed assembler problem that could lead to sub-optimal compression. +* Feb 12, 2016: Snappy: Added AMD64 SSE 4.2 optimizations to matching, which makes easy to compress material run faster. Typical speedup is around 25%. +* Feb 9, 2016: Added Snappy package fork. This version is 5-7% faster, much more on hard to compress content. +* Jan 30, 2016: Optimize level 1 to 3 by not considering static dictionary or storing uncompressed. ~4-5% speedup. +* Jan 16, 2016: Optimization on deflate level 1,2,3 compression. +* Jan 8 2016: Merge [CL 18317](https://go-review.googlesource.com/#/c/18317): fix reading, writing of zip64 archives. +* Dec 8 2015: Make level 1 and -2 deterministic even if write size differs. +* Dec 8 2015: Split encoding functions, so hashing and matching can potentially be inlined. 1-3% faster on AMD64. 5% faster on other platforms. +* Dec 8 2015: Fixed rare [one byte out-of bounds read](https://github.com/klauspost/compress/issues/20). Please update! +* Nov 23 2015: Optimization on token writer. ~2-4% faster. Contributed by [@dsnet](https://github.com/dsnet). +* Nov 20 2015: Small optimization to bit writer on 64 bit systems. +* Nov 17 2015: Fixed out-of-bound errors if the underlying Writer returned an error. See [#15](https://github.com/klauspost/compress/issues/15). +* Nov 12 2015: Added [io.WriterTo](https://golang.org/pkg/io/#WriterTo) support to gzip/inflate. +* Nov 11 2015: Merged [CL 16669](https://go-review.googlesource.com/#/c/16669/4): archive/zip: enable overriding (de)compressors per file +* Oct 15 2015: Added skipping on uncompressible data. Random data speed up >5x. + +
+ +# deflate usage + +* [High Throughput Benchmark](http://blog.klauspost.com/go-gzipdeflate-benchmarks/). +* [Small Payload/Webserver Benchmarks](http://blog.klauspost.com/gzip-performance-for-go-webservers/). +* [Linear Time Compression](http://blog.klauspost.com/constant-time-gzipzip-compression/). +* [Re-balancing Deflate Compression Levels](https://blog.klauspost.com/rebalancing-deflate-compression-levels/) + +The packages are drop-in replacements for standard libraries. Simply replace the import path to use them: + +| old import | new import | Documentation +|--------------------|-----------------------------------------|--------------------| +| `compress/gzip` | `github.com/klauspost/compress/gzip` | [gzip](https://pkg.go.dev/github.com/klauspost/compress/gzip?tab=doc) +| `compress/zlib` | `github.com/klauspost/compress/zlib` | [zlib](https://pkg.go.dev/github.com/klauspost/compress/zlib?tab=doc) +| `archive/zip` | `github.com/klauspost/compress/zip` | [zip](https://pkg.go.dev/github.com/klauspost/compress/zip?tab=doc) +| `compress/flate` | `github.com/klauspost/compress/flate` | [flate](https://pkg.go.dev/github.com/klauspost/compress/flate?tab=doc) + +* Optimized [deflate](https://godoc.org/github.com/klauspost/compress/flate) packages which can be used as a dropin replacement for [gzip](https://godoc.org/github.com/klauspost/compress/gzip), [zip](https://godoc.org/github.com/klauspost/compress/zip) and [zlib](https://godoc.org/github.com/klauspost/compress/zlib). + +You may also be interested in [pgzip](https://github.com/klauspost/pgzip), which is a drop in replacement for gzip, which support multithreaded compression on big files and the optimized [crc32](https://github.com/klauspost/crc32) package used by these packages. + +The packages contains the same as the standard library, so you can use the godoc for that: [gzip](http://golang.org/pkg/compress/gzip/), [zip](http://golang.org/pkg/archive/zip/), [zlib](http://golang.org/pkg/compress/zlib/), [flate](http://golang.org/pkg/compress/flate/). + +Currently there is only minor speedup on decompression (mostly CRC32 calculation). + +# Stateless compression + +This package offers stateless compression as a special option for gzip/deflate. +It will do compression but without maintaining any state between Write calls. + +This means there will be no memory kept between Write calls, but compression and speed will be suboptimal. + +This is only relevant in cases where you expect to run many thousands of compressors concurrently, +but with very little activity. This is *not* intended for regular web servers serving individual requests. + +Because of this, the size of actual Write calls will affect output size. + +In gzip, specify level `-3` / `gzip.StatelessCompression` to enable. + +For direct deflate use, NewStatelessWriter and StatelessDeflate are available. See [documentation](https://godoc.org/github.com/klauspost/compress/flate#NewStatelessWriter) + +A `bufio.Writer` can of course be used to control write sizes. For example, to use a 4KB buffer: + +``` + // replace 'ioutil.Discard' with your output. + gzw, err := gzip.NewWriterLevel(ioutil.Discard, gzip.StatelessCompression) + if err != nil { + return err + } + defer gzw.Close() + + w := bufio.NewWriterSize(gzw, 4096) + defer w.Flush() + + // Write to 'w' +``` + +This will only use up to 4KB in memory when the writer is idle. + +Compression is almost always worse than the fastest compression level +and each write will allocate (a little) memory. + +# Performance Update 2018 + +It has been a while since we have been looking at the speed of this package compared to the standard library, so I thought I would re-do my tests and give some overall recommendations based on the current state. All benchmarks have been performed with Go 1.10 on my Desktop Intel(R) Core(TM) i7-2600 CPU @3.40GHz. Since I last ran the tests, I have gotten more RAM, which means tests with big files are no longer limited by my SSD. + +The raw results are in my [updated spreadsheet](https://docs.google.com/spreadsheets/d/1nuNE2nPfuINCZJRMt6wFWhKpToF95I47XjSsc-1rbPQ/edit?usp=sharing). Due to cgo changes and upstream updates i could not get the cgo version of gzip to compile. Instead I included the [zstd](https://github.com/datadog/zstd) cgo implementation. If I get cgo gzip to work again, I might replace the results in the sheet. + +The columns to take note of are: *MB/s* - the throughput. *Reduction* - the data size reduction in percent of the original. *Rel Speed* relative speed compared to the standard library at the same level. *Smaller* - how many percent smaller is the compressed output compared to stdlib. Negative means the output was bigger. *Loss* means the loss (or gain) in compression as a percentage difference of the input. + +The `gzstd` (standard library gzip) and `gzkp` (this package gzip) only uses one CPU core. [`pgzip`](https://github.com/klauspost/pgzip), [`bgzf`](https://github.com/biogo/hts/tree/master/bgzf) uses all 4 cores. [`zstd`](https://github.com/DataDog/zstd) uses one core, and is a beast (but not Go, yet). + + +## Overall differences. + +There appears to be a roughly 5-10% speed advantage over the standard library when comparing at similar compression levels. + +The biggest difference you will see is the result of [re-balancing](https://blog.klauspost.com/rebalancing-deflate-compression-levels/) the compression levels. I wanted by library to give a smoother transition between the compression levels than the standard library. + +This package attempts to provide a more smooth transition, where "1" is taking a lot of shortcuts, "5" is the reasonable trade-off and "9" is the "give me the best compression", and the values in between gives something reasonable in between. The standard library has big differences in levels 1-4, but levels 5-9 having no significant gains - often spending a lot more time than can be justified by the achieved compression. + +There are links to all the test data in the [spreadsheet](https://docs.google.com/spreadsheets/d/1nuNE2nPfuINCZJRMt6wFWhKpToF95I47XjSsc-1rbPQ/edit?usp=sharing) in the top left field on each tab. + +## Web Content + +This test set aims to emulate typical use in a web server. The test-set is 4GB data in 53k files, and is a mixture of (mostly) HTML, JS, CSS. + +Since level 1 and 9 are close to being the same code, they are quite close. But looking at the levels in-between the differences are quite big. + +Looking at level 6, this package is 88% faster, but will output about 6% more data. For a web server, this means you can serve 88% more data, but have to pay for 6% more bandwidth. You can draw your own conclusions on what would be the most expensive for your case. + +## Object files + +This test is for typical data files stored on a server. In this case it is a collection of Go precompiled objects. They are very compressible. + +The picture is similar to the web content, but with small differences since this is very compressible. Levels 2-3 offer good speed, but is sacrificing quite a bit of compression. + +The standard library seems suboptimal on level 3 and 4 - offering both worse compression and speed than level 6 & 7 of this package respectively. + +## Highly Compressible File + +This is a JSON file with very high redundancy. The reduction starts at 95% on level 1, so in real life terms we are dealing with something like a highly redundant stream of data, etc. + +It is definitely visible that we are dealing with specialized content here, so the results are very scattered. This package does not do very well at levels 1-4, but picks up significantly at level 5 and levels 7 and 8 offering great speed for the achieved compression. + +So if you know you content is extremely compressible you might want to go slightly higher than the defaults. The standard library has a huge gap between levels 3 and 4 in terms of speed (2.75x slowdown), so it offers little "middle ground". + +## Medium-High Compressible + +This is a pretty common test corpus: [enwik9](http://mattmahoney.net/dc/textdata.html). It contains the first 10^9 bytes of the English Wikipedia dump on Mar. 3, 2006. This is a very good test of typical text based compression and more data heavy streams. + +We see a similar picture here as in "Web Content". On equal levels some compression is sacrificed for more speed. Level 5 seems to be the best trade-off between speed and size, beating stdlib level 3 in both. + +## Medium Compressible + +I will combine two test sets, one [10GB file set](http://mattmahoney.net/dc/10gb.html) and a VM disk image (~8GB). Both contain different data types and represent a typical backup scenario. + +The most notable thing is how quickly the standard library drops to very low compression speeds around level 5-6 without any big gains in compression. Since this type of data is fairly common, this does not seem like good behavior. + + +## Un-compressible Content + +This is mainly a test of how good the algorithms are at detecting un-compressible input. The standard library only offers this feature with very conservative settings at level 1. Obviously there is no reason for the algorithms to try to compress input that cannot be compressed. The only downside is that it might skip some compressible data on false detections. + + +# linear time compression (huffman only) + +This compression library adds a special compression level, named `HuffmanOnly`, which allows near linear time compression. This is done by completely disabling matching of previous data, and only reduce the number of bits to represent each character. + +This means that often used characters, like 'e' and ' ' (space) in text use the fewest bits to represent, and rare characters like '¤' takes more bits to represent. For more information see [wikipedia](https://en.wikipedia.org/wiki/Huffman_coding) or this nice [video](https://youtu.be/ZdooBTdW5bM). + +Since this type of compression has much less variance, the compression speed is mostly unaffected by the input data, and is usually more than *180MB/s* for a single core. + +The downside is that the compression ratio is usually considerably worse than even the fastest conventional compression. The compression ratio can never be better than 8:1 (12.5%). + +The linear time compression can be used as a "better than nothing" mode, where you cannot risk the encoder to slow down on some content. For comparison, the size of the "Twain" text is *233460 bytes* (+29% vs. level 1) and encode speed is 144MB/s (4.5x level 1). So in this case you trade a 30% size increase for a 4 times speedup. + +For more information see my blog post on [Fast Linear Time Compression](http://blog.klauspost.com/constant-time-gzipzip-compression/). + +This is implemented on Go 1.7 as "Huffman Only" mode, though not exposed for gzip. + + +# snappy package + +The standard snappy package has now been improved. This repo contains a copy of the snappy repo. + +I would advise to use the standard package: https://github.com/golang/snappy + + +# license + +This code is licensed under the same conditions as the original Go code. See LICENSE file. diff --git a/github.com/klauspost/compress/compressible.go b/github.com/klauspost/compress/compressible.go new file mode 100644 index 0000000..ea5a692 --- /dev/null +++ b/github.com/klauspost/compress/compressible.go @@ -0,0 +1,85 @@ +package compress + +import "math" + +// Estimate returns a normalized compressibility estimate of block b. +// Values close to zero are likely uncompressible. +// Values above 0.1 are likely to be compressible. +// Values above 0.5 are very compressible. +// Very small lengths will return 0. +func Estimate(b []byte) float64 { + if len(b) < 16 { + return 0 + } + + // Correctly predicted order 1 + hits := 0 + lastMatch := false + var o1 [256]byte + var hist [256]int + c1 := byte(0) + for _, c := range b { + if c == o1[c1] { + // We only count a hit if there was two correct predictions in a row. + if lastMatch { + hits++ + } + lastMatch = true + } else { + lastMatch = false + } + o1[c1] = c + c1 = c + hist[c]++ + } + + // Use x^0.6 to give better spread + prediction := math.Pow(float64(hits)/float64(len(b)), 0.6) + + // Calculate histogram distribution + variance := float64(0) + avg := float64(len(b)) / 256 + + for _, v := range hist { + Δ := float64(v) - avg + variance += Δ * Δ + } + + stddev := math.Sqrt(float64(variance)) / float64(len(b)) + exp := math.Sqrt(1 / float64(len(b))) + + // Subtract expected stddev + stddev -= exp + if stddev < 0 { + stddev = 0 + } + stddev *= 1 + exp + + // Use x^0.4 to give better spread + entropy := math.Pow(stddev, 0.4) + + // 50/50 weight between prediction and histogram distribution + return math.Pow((prediction+entropy)/2, 0.9) +} + +// ShannonEntropyBits returns the number of bits minimum required to represent +// an entropy encoding of the input bytes. +// https://en.wiktionary.org/wiki/Shannon_entropy +func ShannonEntropyBits(b []byte) int { + if len(b) == 0 { + return 0 + } + var hist [256]int + for _, c := range b { + hist[c]++ + } + shannon := float64(0) + invTotal := 1.0 / float64(len(b)) + for _, v := range hist[:] { + if v > 0 { + n := float64(v) + shannon += math.Ceil(-math.Log2(n*invTotal) * n) + } + } + return int(math.Ceil(shannon)) +} diff --git a/github.com/klauspost/compress/compressible_test.go b/github.com/klauspost/compress/compressible_test.go new file mode 100644 index 0000000..16817c6 --- /dev/null +++ b/github.com/klauspost/compress/compressible_test.go @@ -0,0 +1,302 @@ +package compress + +import ( + "crypto/rand" + "encoding/base32" + "io/ioutil" + "strconv" + "strings" + "testing" + + "github.com/klauspost/compress/flate" + "github.com/klauspost/compress/gzip" +) + +func BenchmarkEstimate(b *testing.B) { + b.ReportAllocs() + // (predictable, low entropy distibution) + b.Run("zeroes-5k", func(b *testing.B) { + var testData = make([]byte, 5000) + b.SetBytes(int64(len(testData))) + b.ResetTimer() + for i := 0; i < b.N; i++ { + Estimate(testData) + } + b.Log(Estimate(testData)) + }) + + // (predictable, high entropy distibution) + b.Run("predictable-5k", func(b *testing.B) { + var testData = make([]byte, 5000) + for i := range testData { + testData[i] = byte(float64(i) / float64(len(testData)) * 256) + } + b.SetBytes(int64(len(testData))) + b.ResetTimer() + for i := 0; i < b.N; i++ { + Estimate(testData) + } + b.Log(Estimate(testData)) + }) + + // (not predictable, high entropy distibution) + b.Run("random-500b", func(b *testing.B) { + var testData = make([]byte, 500) + rand.Read(testData) + b.SetBytes(int64(len(testData))) + b.ResetTimer() + for i := 0; i < b.N; i++ { + Estimate(testData) + } + b.Log(Estimate(testData)) + }) + + // (not predictable, high entropy distibution) + b.Run("random-5k", func(b *testing.B) { + var testData = make([]byte, 5000) + rand.Read(testData) + b.SetBytes(int64(len(testData))) + b.ResetTimer() + for i := 0; i < b.N; i++ { + Estimate(testData) + } + b.Log(Estimate(testData)) + }) + + // (not predictable, high entropy distibution) + b.Run("random-50k", func(b *testing.B) { + var testData = make([]byte, 50000) + rand.Read(testData) + b.SetBytes(int64(len(testData))) + b.ResetTimer() + for i := 0; i < b.N; i++ { + Estimate(testData) + } + b.Log(Estimate(testData)) + }) + + // (not predictable, high entropy distibution) + b.Run("random-500k", func(b *testing.B) { + var testData = make([]byte, 500000) + rand.Read(testData) + b.SetBytes(int64(len(testData))) + b.ResetTimer() + for i := 0; i < b.N; i++ { + Estimate(testData) + } + b.Log(Estimate(testData)) + }) + + // (not predictable, medium entropy distibution) + b.Run("base-32-5k", func(b *testing.B) { + var testData = make([]byte, 5000) + rand.Read(testData) + s := base32.StdEncoding.EncodeToString(testData) + testData = []byte(s) + testData = testData[:5000] + b.SetBytes(int64(len(testData))) + b.ResetTimer() + for i := 0; i < b.N; i++ { + Estimate(testData) + } + b.Log(Estimate(testData)) + }) + // (medium predictable, medium entropy distibution) + b.Run("text", func(b *testing.B) { + var testData = []byte(`If compression is done per-chunk, care should be taken that it doesn't leave restic backups open to watermarking/fingerprinting attacks. +This is essentially the same problem we discussed related to fingerprinting the CDC deduplication process: +With "naive" CDC, a "known plaintext" file can be verified to exist within the backup if the size of individual blocks can be observed by an attacker, by using CDC on the file in parallel and comparing the resulting amount of chunks and individual chunk lengths. +As discussed earlier, this can be somewhat mitigated by salting the CDC algorithm with a secret value, as done in attic. +With salted CDC, I assume compression would happen on each individual chunk, after splitting the problematic file into chunks. Restic chunks are in the range of 512 KB to 8 MB (but not evenly distributed - right?). +Attacker knows that the CDC algorithm uses a secret salt, so the attacker generates a range of chunks consisting of the first 512 KB to 8 MB of the file, one for each valid chunk length. The attacker is also able to determine the lengths of compressed chunks. +The attacker then compresses that chunk using the compression algorithm. +The attacker compares the lengths of the resulting chunks to the first chunk in the restic backup sets. +IF a matching block length is found, the attacker repeats the exercise with the next chunk, and the next chunk, and the next chunk, ... and the next chunk. +It is my belief that with sufficiently large files, and considering the fact that the CDC algorithm is "biased" (in lack of better of words) towards generating blocks of about 1 MB, this would be sufficient to ascertain whether or not a certain large file exists in the backup. +AS always, a paranoid and highly unscientific stream of consciousness. +Thoughts?`) + testData = append(testData, testData...) + testData = append(testData, testData...) + b.SetBytes(int64(len(testData))) + b.ResetTimer() + for i := 0; i < b.N; i++ { + Estimate(testData) + } + b.Log(Estimate(testData)) + }) +} + +func BenchmarkSnannonEntropyBits(b *testing.B) { + b.ReportAllocs() + // (predictable, low entropy distibution) + b.Run("zeroes-5k", func(b *testing.B) { + var testData = make([]byte, 5000) + b.SetBytes(int64(len(testData))) + b.ResetTimer() + for i := 0; i < b.N; i++ { + ShannonEntropyBits(testData) + } + b.Log(ShannonEntropyBits(testData)) + }) + + // (predictable, high entropy distibution) + b.Run("predictable-5k", func(b *testing.B) { + var testData = make([]byte, 5000) + for i := range testData { + testData[i] = byte(float64(i) / float64(len(testData)) * 256) + } + b.SetBytes(int64(len(testData))) + b.ResetTimer() + for i := 0; i < b.N; i++ { + ShannonEntropyBits(testData) + } + b.Log(ShannonEntropyBits(testData)) + }) + + // (not predictable, high entropy distibution) + b.Run("random-500b", func(b *testing.B) { + var testData = make([]byte, 500) + rand.Read(testData) + b.SetBytes(int64(len(testData))) + b.ResetTimer() + for i := 0; i < b.N; i++ { + ShannonEntropyBits(testData) + } + b.Log(ShannonEntropyBits(testData)) + }) + + // (not predictable, high entropy distibution) + b.Run("random-5k", func(b *testing.B) { + var testData = make([]byte, 5000) + rand.Read(testData) + b.SetBytes(int64(len(testData))) + b.ResetTimer() + for i := 0; i < b.N; i++ { + ShannonEntropyBits(testData) + } + b.Log(ShannonEntropyBits(testData)) + }) + + // (not predictable, high entropy distibution) + b.Run("random-50k", func(b *testing.B) { + var testData = make([]byte, 50000) + rand.Read(testData) + b.SetBytes(int64(len(testData))) + b.ResetTimer() + for i := 0; i < b.N; i++ { + ShannonEntropyBits(testData) + } + b.Log(ShannonEntropyBits(testData)) + }) + + // (not predictable, high entropy distibution) + b.Run("random-500k", func(b *testing.B) { + var testData = make([]byte, 500000) + rand.Read(testData) + b.SetBytes(int64(len(testData))) + b.ResetTimer() + for i := 0; i < b.N; i++ { + ShannonEntropyBits(testData) + } + b.Log(ShannonEntropyBits(testData)) + }) + + // (not predictable, medium entropy distibution) + b.Run("base-32-5k", func(b *testing.B) { + var testData = make([]byte, 5000) + rand.Read(testData) + s := base32.StdEncoding.EncodeToString(testData) + testData = []byte(s) + testData = testData[:5000] + b.SetBytes(int64(len(testData))) + b.ResetTimer() + for i := 0; i < b.N; i++ { + ShannonEntropyBits(testData) + } + b.Log(ShannonEntropyBits(testData)) + }) + // (medium predictable, medium entropy distibution) + b.Run("text", func(b *testing.B) { + var testData = []byte(`If compression is done per-chunk, care should be taken that it doesn't leave restic backups open to watermarking/fingerprinting attacks. +This is essentially the same problem we discussed related to fingerprinting the CDC deduplication process: +With "naive" CDC, a "known plaintext" file can be verified to exist within the backup if the size of individual blocks can be observed by an attacker, by using CDC on the file in parallel and comparing the resulting amount of chunks and individual chunk lengths. +As discussed earlier, this can be somewhat mitigated by salting the CDC algorithm with a secret value, as done in attic. +With salted CDC, I assume compression would happen on each individual chunk, after splitting the problematic file into chunks. Restic chunks are in the range of 512 KB to 8 MB (but not evenly distributed - right?). +Attacker knows that the CDC algorithm uses a secret salt, so the attacker generates a range of chunks consisting of the first 512 KB to 8 MB of the file, one for each valid chunk length. The attacker is also able to determine the lengths of compressed chunks. +The attacker then compresses that chunk using the compression algorithm. +The attacker compares the lengths of the resulting chunks to the first chunk in the restic backup sets. +IF a matching block length is found, the attacker repeats the exercise with the next chunk, and the next chunk, and the next chunk, ... and the next chunk. +It is my belief that with sufficiently large files, and considering the fact that the CDC algorithm is "biased" (in lack of better of words) towards generating blocks of about 1 MB, this would be sufficient to ascertain whether or not a certain large file exists in the backup. +AS always, a paranoid and highly unscientific stream of consciousness. +Thoughts?`) + testData = append(testData, testData...) + testData = append(testData, testData...) + b.SetBytes(int64(len(testData))) + b.ResetTimer() + for i := 0; i < b.N; i++ { + ShannonEntropyBits(testData) + } + b.Log(ShannonEntropyBits(testData)) + }) +} + +func BenchmarkCompressAllocations(b *testing.B) { + payload := []byte(strings.Repeat("Tiny payload", 20)) + for j := -2; j <= 9; j++ { + b.Run("level("+strconv.Itoa(j)+")", func(b *testing.B) { + b.Run("flate", func(b *testing.B) { + b.ReportAllocs() + + for i := 0; i < b.N; i++ { + w, err := flate.NewWriter(ioutil.Discard, j) + if err != nil { + b.Fatal(err) + } + w.Write(payload) + w.Close() + } + }) + b.Run("gzip", func(b *testing.B) { + b.ReportAllocs() + + for i := 0; i < b.N; i++ { + w, err := gzip.NewWriterLevel(ioutil.Discard, j) + if err != nil { + b.Fatal(err) + } + w.Write(payload) + w.Close() + } + }) + }) + } +} + +func BenchmarkCompressAllocationsSingle(b *testing.B) { + payload := []byte(strings.Repeat("Tiny payload", 20)) + const level = 2 + b.Run("flate", func(b *testing.B) { + b.ReportAllocs() + + for i := 0; i < b.N; i++ { + w, err := flate.NewWriter(ioutil.Discard, level) + if err != nil { + b.Fatal(err) + } + w.Write(payload) + w.Close() + } + }) + b.Run("gzip", func(b *testing.B) { + b.ReportAllocs() + + for i := 0; i < b.N; i++ { + w, err := gzip.NewWriterLevel(ioutil.Discard, level) + if err != nil { + b.Fatal(err) + } + w.Write(payload) + w.Close() + } + }) +} diff --git a/github.com/klauspost/compress/flate/deflate.go b/github.com/klauspost/compress/flate/deflate.go new file mode 100644 index 0000000..25dbe3e --- /dev/null +++ b/github.com/klauspost/compress/flate/deflate.go @@ -0,0 +1,821 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Copyright (c) 2015 Klaus Post +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package flate + +import ( + "fmt" + "io" + "math" +) + +const ( + NoCompression = 0 + BestSpeed = 1 + BestCompression = 9 + DefaultCompression = -1 + + // HuffmanOnly disables Lempel-Ziv match searching and only performs Huffman + // entropy encoding. This mode is useful in compressing data that has + // already been compressed with an LZ style algorithm (e.g. Snappy or LZ4) + // that lacks an entropy encoder. Compression gains are achieved when + // certain bytes in the input stream occur more frequently than others. + // + // Note that HuffmanOnly produces a compressed output that is + // RFC 1951 compliant. That is, any valid DEFLATE decompressor will + // continue to be able to decompress this output. + HuffmanOnly = -2 + ConstantCompression = HuffmanOnly // compatibility alias. + + logWindowSize = 15 + windowSize = 1 << logWindowSize + windowMask = windowSize - 1 + logMaxOffsetSize = 15 // Standard DEFLATE + minMatchLength = 4 // The smallest match that the compressor looks for + maxMatchLength = 258 // The longest match for the compressor + minOffsetSize = 1 // The shortest offset that makes any sense + + // The maximum number of tokens we put into a single flat block, just too + // stop things from getting too large. + maxFlateBlockTokens = 1 << 14 + maxStoreBlockSize = 65535 + hashBits = 17 // After 17 performance degrades + hashSize = 1 << hashBits + hashMask = (1 << hashBits) - 1 + hashShift = (hashBits + minMatchLength - 1) / minMatchLength + maxHashOffset = 1 << 24 + + skipNever = math.MaxInt32 + + debugDeflate = false +) + +type compressionLevel struct { + good, lazy, nice, chain, fastSkipHashing, level int +} + +// Compression levels have been rebalanced from zlib deflate defaults +// to give a bigger spread in speed and compression. +// See https://blog.klauspost.com/rebalancing-deflate-compression-levels/ +var levels = []compressionLevel{ + {}, // 0 + // Level 1-6 uses specialized algorithm - values not used + {0, 0, 0, 0, 0, 1}, + {0, 0, 0, 0, 0, 2}, + {0, 0, 0, 0, 0, 3}, + {0, 0, 0, 0, 0, 4}, + {0, 0, 0, 0, 0, 5}, + {0, 0, 0, 0, 0, 6}, + // Levels 7-9 use increasingly more lazy matching + // and increasingly stringent conditions for "good enough". + {8, 8, 24, 16, skipNever, 7}, + {10, 16, 24, 64, skipNever, 8}, + {32, 258, 258, 4096, skipNever, 9}, +} + +// advancedState contains state for the advanced levels, with bigger hash tables, etc. +type advancedState struct { + // deflate state + length int + offset int + maxInsertIndex int + + // Input hash chains + // hashHead[hashValue] contains the largest inputIndex with the specified hash value + // If hashHead[hashValue] is within the current window, then + // hashPrev[hashHead[hashValue] & windowMask] contains the previous index + // with the same hash value. + chainHead int + hashHead [hashSize]uint32 + hashPrev [windowSize]uint32 + hashOffset int + + // input window: unprocessed data is window[index:windowEnd] + index int + hashMatch [maxMatchLength + minMatchLength]uint32 + + hash uint32 + ii uint16 // position of last match, intended to overflow to reset. +} + +type compressor struct { + compressionLevel + + w *huffmanBitWriter + + // compression algorithm + fill func(*compressor, []byte) int // copy data to window + step func(*compressor) // process window + + window []byte + windowEnd int + blockStart int // window index where current tokens start + err error + + // queued output tokens + tokens tokens + fast fastEnc + state *advancedState + + sync bool // requesting flush + byteAvailable bool // if true, still need to process window[index-1]. +} + +func (d *compressor) fillDeflate(b []byte) int { + s := d.state + if s.index >= 2*windowSize-(minMatchLength+maxMatchLength) { + // shift the window by windowSize + copy(d.window[:], d.window[windowSize:2*windowSize]) + s.index -= windowSize + d.windowEnd -= windowSize + if d.blockStart >= windowSize { + d.blockStart -= windowSize + } else { + d.blockStart = math.MaxInt32 + } + s.hashOffset += windowSize + if s.hashOffset > maxHashOffset { + delta := s.hashOffset - 1 + s.hashOffset -= delta + s.chainHead -= delta + // Iterate over slices instead of arrays to avoid copying + // the entire table onto the stack (Issue #18625). + for i, v := range s.hashPrev[:] { + if int(v) > delta { + s.hashPrev[i] = uint32(int(v) - delta) + } else { + s.hashPrev[i] = 0 + } + } + for i, v := range s.hashHead[:] { + if int(v) > delta { + s.hashHead[i] = uint32(int(v) - delta) + } else { + s.hashHead[i] = 0 + } + } + } + } + n := copy(d.window[d.windowEnd:], b) + d.windowEnd += n + return n +} + +func (d *compressor) writeBlock(tok *tokens, index int, eof bool) error { + if index > 0 || eof { + var window []byte + if d.blockStart <= index { + window = d.window[d.blockStart:index] + } + d.blockStart = index + d.w.writeBlock(tok, eof, window) + return d.w.err + } + return nil +} + +// writeBlockSkip writes the current block and uses the number of tokens +// to determine if the block should be stored on no matches, or +// only huffman encoded. +func (d *compressor) writeBlockSkip(tok *tokens, index int, eof bool) error { + if index > 0 || eof { + if d.blockStart <= index { + window := d.window[d.blockStart:index] + // If we removed less than a 64th of all literals + // we huffman compress the block. + if int(tok.n) > len(window)-int(tok.n>>6) { + d.w.writeBlockHuff(eof, window, d.sync) + } else { + // Write a dynamic huffman block. + d.w.writeBlockDynamic(tok, eof, window, d.sync) + } + } else { + d.w.writeBlock(tok, eof, nil) + } + d.blockStart = index + return d.w.err + } + return nil +} + +// fillWindow will fill the current window with the supplied +// dictionary and calculate all hashes. +// This is much faster than doing a full encode. +// Should only be used after a start/reset. +func (d *compressor) fillWindow(b []byte) { + // Do not fill window if we are in store-only or huffman mode. + if d.level <= 0 { + return + } + if d.fast != nil { + // encode the last data, but discard the result + if len(b) > maxMatchOffset { + b = b[len(b)-maxMatchOffset:] + } + d.fast.Encode(&d.tokens, b) + d.tokens.Reset() + return + } + s := d.state + // If we are given too much, cut it. + if len(b) > windowSize { + b = b[len(b)-windowSize:] + } + // Add all to window. + n := copy(d.window[d.windowEnd:], b) + + // Calculate 256 hashes at the time (more L1 cache hits) + loops := (n + 256 - minMatchLength) / 256 + for j := 0; j < loops; j++ { + startindex := j * 256 + end := startindex + 256 + minMatchLength - 1 + if end > n { + end = n + } + tocheck := d.window[startindex:end] + dstSize := len(tocheck) - minMatchLength + 1 + + if dstSize <= 0 { + continue + } + + dst := s.hashMatch[:dstSize] + bulkHash4(tocheck, dst) + var newH uint32 + for i, val := range dst { + di := i + startindex + newH = val & hashMask + // Get previous value with the same hash. + // Our chain should point to the previous value. + s.hashPrev[di&windowMask] = s.hashHead[newH] + // Set the head of the hash chain to us. + s.hashHead[newH] = uint32(di + s.hashOffset) + } + s.hash = newH + } + // Update window information. + d.windowEnd += n + s.index = n +} + +// Try to find a match starting at index whose length is greater than prevSize. +// We only look at chainCount possibilities before giving up. +// pos = s.index, prevHead = s.chainHead-s.hashOffset, prevLength=minMatchLength-1, lookahead +func (d *compressor) findMatch(pos int, prevHead int, prevLength int, lookahead int) (length, offset int, ok bool) { + minMatchLook := maxMatchLength + if lookahead < minMatchLook { + minMatchLook = lookahead + } + + win := d.window[0 : pos+minMatchLook] + + // We quit when we get a match that's at least nice long + nice := len(win) - pos + if d.nice < nice { + nice = d.nice + } + + // If we've got a match that's good enough, only look in 1/4 the chain. + tries := d.chain + length = prevLength + if length >= d.good { + tries >>= 2 + } + + wEnd := win[pos+length] + wPos := win[pos:] + minIndex := pos - windowSize + + for i := prevHead; tries > 0; tries-- { + if wEnd == win[i+length] { + n := matchLen(win[i:i+minMatchLook], wPos) + + if n > length && (n > minMatchLength || pos-i <= 4096) { + length = n + offset = pos - i + ok = true + if n >= nice { + // The match is good enough that we don't try to find a better one. + break + } + wEnd = win[pos+n] + } + } + if i == minIndex { + // hashPrev[i & windowMask] has already been overwritten, so stop now. + break + } + i = int(d.state.hashPrev[i&windowMask]) - d.state.hashOffset + if i < minIndex || i < 0 { + break + } + } + return +} + +func (d *compressor) writeStoredBlock(buf []byte) error { + if d.w.writeStoredHeader(len(buf), false); d.w.err != nil { + return d.w.err + } + d.w.writeBytes(buf) + return d.w.err +} + +// hash4 returns a hash representation of the first 4 bytes +// of the supplied slice. +// The caller must ensure that len(b) >= 4. +func hash4(b []byte) uint32 { + b = b[:4] + return hash4u(uint32(b[3])|uint32(b[2])<<8|uint32(b[1])<<16|uint32(b[0])<<24, hashBits) +} + +// bulkHash4 will compute hashes using the same +// algorithm as hash4 +func bulkHash4(b []byte, dst []uint32) { + if len(b) < 4 { + return + } + hb := uint32(b[3]) | uint32(b[2])<<8 | uint32(b[1])<<16 | uint32(b[0])<<24 + dst[0] = hash4u(hb, hashBits) + end := len(b) - 4 + 1 + for i := 1; i < end; i++ { + hb = (hb << 8) | uint32(b[i+3]) + dst[i] = hash4u(hb, hashBits) + } +} + +func (d *compressor) initDeflate() { + d.window = make([]byte, 2*windowSize) + d.byteAvailable = false + d.err = nil + if d.state == nil { + return + } + s := d.state + s.index = 0 + s.hashOffset = 1 + s.length = minMatchLength - 1 + s.offset = 0 + s.hash = 0 + s.chainHead = -1 +} + +// deflateLazy is the same as deflate, but with d.fastSkipHashing == skipNever, +// meaning it always has lazy matching on. +func (d *compressor) deflateLazy() { + s := d.state + // Sanity enables additional runtime tests. + // It's intended to be used during development + // to supplement the currently ad-hoc unit tests. + const sanity = debugDeflate + + if d.windowEnd-s.index < minMatchLength+maxMatchLength && !d.sync { + return + } + + s.maxInsertIndex = d.windowEnd - (minMatchLength - 1) + if s.index < s.maxInsertIndex { + s.hash = hash4(d.window[s.index : s.index+minMatchLength]) + } + + for { + if sanity && s.index > d.windowEnd { + panic("index > windowEnd") + } + lookahead := d.windowEnd - s.index + if lookahead < minMatchLength+maxMatchLength { + if !d.sync { + return + } + if sanity && s.index > d.windowEnd { + panic("index > windowEnd") + } + if lookahead == 0 { + // Flush current output block if any. + if d.byteAvailable { + // There is still one pending token that needs to be flushed + d.tokens.AddLiteral(d.window[s.index-1]) + d.byteAvailable = false + } + if d.tokens.n > 0 { + if d.err = d.writeBlock(&d.tokens, s.index, false); d.err != nil { + return + } + d.tokens.Reset() + } + return + } + } + if s.index < s.maxInsertIndex { + // Update the hash + s.hash = hash4(d.window[s.index : s.index+minMatchLength]) + ch := s.hashHead[s.hash&hashMask] + s.chainHead = int(ch) + s.hashPrev[s.index&windowMask] = ch + s.hashHead[s.hash&hashMask] = uint32(s.index + s.hashOffset) + } + prevLength := s.length + prevOffset := s.offset + s.length = minMatchLength - 1 + s.offset = 0 + minIndex := s.index - windowSize + if minIndex < 0 { + minIndex = 0 + } + + if s.chainHead-s.hashOffset >= minIndex && lookahead > prevLength && prevLength < d.lazy { + if newLength, newOffset, ok := d.findMatch(s.index, s.chainHead-s.hashOffset, minMatchLength-1, lookahead); ok { + s.length = newLength + s.offset = newOffset + } + } + if prevLength >= minMatchLength && s.length <= prevLength { + // There was a match at the previous step, and the current match is + // not better. Output the previous match. + d.tokens.AddMatch(uint32(prevLength-3), uint32(prevOffset-minOffsetSize)) + + // Insert in the hash table all strings up to the end of the match. + // index and index-1 are already inserted. If there is not enough + // lookahead, the last two strings are not inserted into the hash + // table. + var newIndex int + newIndex = s.index + prevLength - 1 + // Calculate missing hashes + end := newIndex + if end > s.maxInsertIndex { + end = s.maxInsertIndex + } + end += minMatchLength - 1 + startindex := s.index + 1 + if startindex > s.maxInsertIndex { + startindex = s.maxInsertIndex + } + tocheck := d.window[startindex:end] + dstSize := len(tocheck) - minMatchLength + 1 + if dstSize > 0 { + dst := s.hashMatch[:dstSize] + bulkHash4(tocheck, dst) + var newH uint32 + for i, val := range dst { + di := i + startindex + newH = val & hashMask + // Get previous value with the same hash. + // Our chain should point to the previous value. + s.hashPrev[di&windowMask] = s.hashHead[newH] + // Set the head of the hash chain to us. + s.hashHead[newH] = uint32(di + s.hashOffset) + } + s.hash = newH + } + + s.index = newIndex + d.byteAvailable = false + s.length = minMatchLength - 1 + if d.tokens.n == maxFlateBlockTokens { + // The block includes the current character + if d.err = d.writeBlock(&d.tokens, s.index, false); d.err != nil { + return + } + d.tokens.Reset() + } + } else { + // Reset, if we got a match this run. + if s.length >= minMatchLength { + s.ii = 0 + } + // We have a byte waiting. Emit it. + if d.byteAvailable { + s.ii++ + d.tokens.AddLiteral(d.window[s.index-1]) + if d.tokens.n == maxFlateBlockTokens { + if d.err = d.writeBlock(&d.tokens, s.index, false); d.err != nil { + return + } + d.tokens.Reset() + } + s.index++ + + // If we have a long run of no matches, skip additional bytes + // Resets when s.ii overflows after 64KB. + if s.ii > 31 { + n := int(s.ii >> 5) + for j := 0; j < n; j++ { + if s.index >= d.windowEnd-1 { + break + } + + d.tokens.AddLiteral(d.window[s.index-1]) + if d.tokens.n == maxFlateBlockTokens { + if d.err = d.writeBlock(&d.tokens, s.index, false); d.err != nil { + return + } + d.tokens.Reset() + } + s.index++ + } + // Flush last byte + d.tokens.AddLiteral(d.window[s.index-1]) + d.byteAvailable = false + // s.length = minMatchLength - 1 // not needed, since s.ii is reset above, so it should never be > minMatchLength + if d.tokens.n == maxFlateBlockTokens { + if d.err = d.writeBlock(&d.tokens, s.index, false); d.err != nil { + return + } + d.tokens.Reset() + } + } + } else { + s.index++ + d.byteAvailable = true + } + } + } +} + +func (d *compressor) store() { + if d.windowEnd > 0 && (d.windowEnd == maxStoreBlockSize || d.sync) { + d.err = d.writeStoredBlock(d.window[:d.windowEnd]) + d.windowEnd = 0 + } +} + +// fillWindow will fill the buffer with data for huffman-only compression. +// The number of bytes copied is returned. +func (d *compressor) fillBlock(b []byte) int { + n := copy(d.window[d.windowEnd:], b) + d.windowEnd += n + return n +} + +// storeHuff will compress and store the currently added data, +// if enough has been accumulated or we at the end of the stream. +// Any error that occurred will be in d.err +func (d *compressor) storeHuff() { + if d.windowEnd < len(d.window) && !d.sync || d.windowEnd == 0 { + return + } + d.w.writeBlockHuff(false, d.window[:d.windowEnd], d.sync) + d.err = d.w.err + d.windowEnd = 0 +} + +// storeFast will compress and store the currently added data, +// if enough has been accumulated or we at the end of the stream. +// Any error that occurred will be in d.err +func (d *compressor) storeFast() { + // We only compress if we have maxStoreBlockSize. + if d.windowEnd < len(d.window) { + if !d.sync { + return + } + // Handle extremely small sizes. + if d.windowEnd < 128 { + if d.windowEnd == 0 { + return + } + if d.windowEnd <= 32 { + d.err = d.writeStoredBlock(d.window[:d.windowEnd]) + } else { + d.w.writeBlockHuff(false, d.window[:d.windowEnd], true) + d.err = d.w.err + } + d.tokens.Reset() + d.windowEnd = 0 + d.fast.Reset() + return + } + } + + d.fast.Encode(&d.tokens, d.window[:d.windowEnd]) + // If we made zero matches, store the block as is. + if d.tokens.n == 0 { + d.err = d.writeStoredBlock(d.window[:d.windowEnd]) + // If we removed less than 1/16th, huffman compress the block. + } else if int(d.tokens.n) > d.windowEnd-(d.windowEnd>>4) { + d.w.writeBlockHuff(false, d.window[:d.windowEnd], d.sync) + d.err = d.w.err + } else { + d.w.writeBlockDynamic(&d.tokens, false, d.window[:d.windowEnd], d.sync) + d.err = d.w.err + } + d.tokens.Reset() + d.windowEnd = 0 +} + +// write will add input byte to the stream. +// Unless an error occurs all bytes will be consumed. +func (d *compressor) write(b []byte) (n int, err error) { + if d.err != nil { + return 0, d.err + } + n = len(b) + for len(b) > 0 { + d.step(d) + b = b[d.fill(d, b):] + if d.err != nil { + return 0, d.err + } + } + return n, d.err +} + +func (d *compressor) syncFlush() error { + d.sync = true + if d.err != nil { + return d.err + } + d.step(d) + if d.err == nil { + d.w.writeStoredHeader(0, false) + d.w.flush() + d.err = d.w.err + } + d.sync = false + return d.err +} + +func (d *compressor) init(w io.Writer, level int) (err error) { + d.w = newHuffmanBitWriter(w) + + switch { + case level == NoCompression: + d.window = make([]byte, maxStoreBlockSize) + d.fill = (*compressor).fillBlock + d.step = (*compressor).store + case level == ConstantCompression: + d.w.logNewTablePenalty = 4 + d.window = make([]byte, maxStoreBlockSize) + d.fill = (*compressor).fillBlock + d.step = (*compressor).storeHuff + case level == DefaultCompression: + level = 5 + fallthrough + case level >= 1 && level <= 6: + d.w.logNewTablePenalty = 6 + d.fast = newFastEnc(level) + d.window = make([]byte, maxStoreBlockSize) + d.fill = (*compressor).fillBlock + d.step = (*compressor).storeFast + case 7 <= level && level <= 9: + d.w.logNewTablePenalty = 10 + d.state = &advancedState{} + d.compressionLevel = levels[level] + d.initDeflate() + d.fill = (*compressor).fillDeflate + d.step = (*compressor).deflateLazy + default: + return fmt.Errorf("flate: invalid compression level %d: want value in range [-2, 9]", level) + } + d.level = level + return nil +} + +// reset the state of the compressor. +func (d *compressor) reset(w io.Writer) { + d.w.reset(w) + d.sync = false + d.err = nil + // We only need to reset a few things for Snappy. + if d.fast != nil { + d.fast.Reset() + d.windowEnd = 0 + d.tokens.Reset() + return + } + switch d.compressionLevel.chain { + case 0: + // level was NoCompression or ConstantCompresssion. + d.windowEnd = 0 + default: + s := d.state + s.chainHead = -1 + for i := range s.hashHead { + s.hashHead[i] = 0 + } + for i := range s.hashPrev { + s.hashPrev[i] = 0 + } + s.hashOffset = 1 + s.index, d.windowEnd = 0, 0 + d.blockStart, d.byteAvailable = 0, false + d.tokens.Reset() + s.length = minMatchLength - 1 + s.offset = 0 + s.hash = 0 + s.ii = 0 + s.maxInsertIndex = 0 + } +} + +func (d *compressor) close() error { + if d.err != nil { + return d.err + } + d.sync = true + d.step(d) + if d.err != nil { + return d.err + } + if d.w.writeStoredHeader(0, true); d.w.err != nil { + return d.w.err + } + d.w.flush() + d.w.reset(nil) + return d.w.err +} + +// NewWriter returns a new Writer compressing data at the given level. +// Following zlib, levels range from 1 (BestSpeed) to 9 (BestCompression); +// higher levels typically run slower but compress more. +// Level 0 (NoCompression) does not attempt any compression; it only adds the +// necessary DEFLATE framing. +// Level -1 (DefaultCompression) uses the default compression level. +// Level -2 (ConstantCompression) will use Huffman compression only, giving +// a very fast compression for all types of input, but sacrificing considerable +// compression efficiency. +// +// If level is in the range [-2, 9] then the error returned will be nil. +// Otherwise the error returned will be non-nil. +func NewWriter(w io.Writer, level int) (*Writer, error) { + var dw Writer + if err := dw.d.init(w, level); err != nil { + return nil, err + } + return &dw, nil +} + +// NewWriterDict is like NewWriter but initializes the new +// Writer with a preset dictionary. The returned Writer behaves +// as if the dictionary had been written to it without producing +// any compressed output. The compressed data written to w +// can only be decompressed by a Reader initialized with the +// same dictionary. +func NewWriterDict(w io.Writer, level int, dict []byte) (*Writer, error) { + zw, err := NewWriter(w, level) + if err != nil { + return nil, err + } + zw.d.fillWindow(dict) + zw.dict = append(zw.dict, dict...) // duplicate dictionary for Reset method. + return zw, err +} + +// A Writer takes data written to it and writes the compressed +// form of that data to an underlying writer (see NewWriter). +type Writer struct { + d compressor + dict []byte +} + +// Write writes data to w, which will eventually write the +// compressed form of data to its underlying writer. +func (w *Writer) Write(data []byte) (n int, err error) { + return w.d.write(data) +} + +// Flush flushes any pending data to the underlying writer. +// It is useful mainly in compressed network protocols, to ensure that +// a remote reader has enough data to reconstruct a packet. +// Flush does not return until the data has been written. +// Calling Flush when there is no pending data still causes the Writer +// to emit a sync marker of at least 4 bytes. +// If the underlying writer returns an error, Flush returns that error. +// +// In the terminology of the zlib library, Flush is equivalent to Z_SYNC_FLUSH. +func (w *Writer) Flush() error { + // For more about flushing: + // http://www.bolet.org/~pornin/deflate-flush.html + return w.d.syncFlush() +} + +// Close flushes and closes the writer. +func (w *Writer) Close() error { + return w.d.close() +} + +// Reset discards the writer's state and makes it equivalent to +// the result of NewWriter or NewWriterDict called with dst +// and w's level and dictionary. +func (w *Writer) Reset(dst io.Writer) { + if len(w.dict) > 0 { + // w was created with NewWriterDict + w.d.reset(dst) + if dst != nil { + w.d.fillWindow(w.dict) + } + } else { + // w was created with NewWriter + w.d.reset(dst) + } +} + +// ResetDict discards the writer's state and makes it equivalent to +// the result of NewWriter or NewWriterDict called with dst +// and w's level, but sets a specific dictionary. +func (w *Writer) ResetDict(dst io.Writer, dict []byte) { + w.dict = dict + w.d.reset(dst) + w.d.fillWindow(w.dict) +} diff --git a/github.com/klauspost/compress/flate/deflate_test.go b/github.com/klauspost/compress/flate/deflate_test.go new file mode 100644 index 0000000..079040e --- /dev/null +++ b/github.com/klauspost/compress/flate/deflate_test.go @@ -0,0 +1,658 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Copyright (c) 2015 Klaus Post +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package flate + +import ( + "bytes" + "fmt" + "io" + "io/ioutil" + "reflect" + "strings" + "sync" + "testing" +) + +type deflateTest struct { + in []byte + level int + out []byte +} + +type deflateInflateTest struct { + in []byte +} + +type reverseBitsTest struct { + in uint16 + bitCount uint8 + out uint16 +} + +var deflateTests = []*deflateTest{ + {[]byte{}, 0, []byte{0x3, 0x0}}, + {[]byte{0x11}, BestCompression, []byte{0x12, 0x4, 0xc, 0x0}}, + {[]byte{0x11}, BestCompression, []byte{0x12, 0x4, 0xc, 0x0}}, + {[]byte{0x11}, BestCompression, []byte{0x12, 0x4, 0xc, 0x0}}, + + {[]byte{0x11}, 0, []byte{0x0, 0x1, 0x0, 0xfe, 0xff, 0x11, 0x3, 0x0}}, + {[]byte{0x11, 0x12}, 0, []byte{0x0, 0x2, 0x0, 0xfd, 0xff, 0x11, 0x12, 0x3, 0x0}}, + {[]byte{0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11}, 0, + []byte{0x0, 0x8, 0x0, 0xf7, 0xff, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x3, 0x0}, + }, + {[]byte{}, 1, []byte{0x3, 0x0}}, + {[]byte{0x11}, BestCompression, []byte{0x12, 0x4, 0xc, 0x0}}, + {[]byte{0x11, 0x12}, BestCompression, []byte{0x12, 0x14, 0x2, 0xc, 0x0}}, + {[]byte{0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11}, BestCompression, []byte{0x12, 0x84, 0x2, 0xc0, 0x0}}, + {[]byte{}, 9, []byte{0x3, 0x0}}, + {[]byte{0x11}, 9, []byte{0x12, 0x4, 0xc, 0x0}}, + {[]byte{0x11, 0x12}, 9, []byte{0x12, 0x14, 0x2, 0xc, 0x0}}, + {[]byte{0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11}, 9, []byte{0x12, 0x84, 0x2, 0xc0, 0x0}}, +} + +var deflateInflateTests = []*deflateInflateTest{ + {[]byte{}}, + {[]byte{0x11}}, + {[]byte{0x11, 0x12}}, + {[]byte{0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11}}, + {[]byte{0x11, 0x10, 0x13, 0x41, 0x21, 0x21, 0x41, 0x13, 0x87, 0x78, 0x13}}, + {largeDataChunk()}, +} + +var reverseBitsTests = []*reverseBitsTest{ + {1, 1, 1}, + {1, 2, 2}, + {1, 3, 4}, + {1, 4, 8}, + {1, 5, 16}, + {17, 5, 17}, + {257, 9, 257}, + {29, 5, 23}, +} + +func largeDataChunk() []byte { + result := make([]byte, 100000) + for i := range result { + result[i] = byte(i * i & 0xFF) + } + return result +} + +func TestBulkHash4(t *testing.T) { + for _, x := range deflateTests { + y := x.out + if len(y) >= minMatchLength { + y = append(y, y...) + for j := 4; j < len(y); j++ { + y := y[:j] + dst := make([]uint32, len(y)-minMatchLength+1) + for i := range dst { + dst[i] = uint32(i + 100) + } + bulkHash4(y, dst) + for i, val := range dst { + got := val + expect := hash4(y[i:]) + if got != expect && got == uint32(i)+100 { + t.Errorf("Len:%d Index:%d, expected 0x%08x but not modified", len(y), i, expect) + } else if got != expect { + t.Errorf("Len:%d Index:%d, got 0x%08x expected:0x%08x", len(y), i, got, expect) + } else { + //t.Logf("Len:%d Index:%d OK (0x%08x)", len(y), i, got) + } + } + } + } + } +} + +func TestDeflate(t *testing.T) { + for i, h := range deflateTests { + var buf bytes.Buffer + w, err := NewWriter(&buf, h.level) + if err != nil { + t.Errorf("NewWriter: %v", err) + continue + } + w.Write(h.in) + w.Close() + if !bytes.Equal(buf.Bytes(), h.out) { + t.Errorf("%d: Deflate(%d, %x) = \n%#v, want \n%#v", i, h.level, h.in, buf.Bytes(), h.out) + } + } +} + +// A sparseReader returns a stream consisting of 0s followed by 1<<16 1s. +// This tests missing hash references in a very large input. +type sparseReader struct { + l int64 + cur int64 +} + +func (r *sparseReader) Read(b []byte) (n int, err error) { + if r.cur >= r.l { + return 0, io.EOF + } + n = len(b) + cur := r.cur + int64(n) + if cur > r.l { + n -= int(cur - r.l) + cur = r.l + } + for i := range b[0:n] { + if r.cur+int64(i) >= r.l-1<<16 { + b[i] = 1 + } else { + b[i] = 0 + } + } + r.cur = cur + return +} + +func TestVeryLongSparseChunk(t *testing.T) { + if testing.Short() { + t.Skip("skipping sparse chunk during short test") + } + w, err := NewWriter(ioutil.Discard, 1) + if err != nil { + t.Errorf("NewWriter: %v", err) + return + } + if _, err = io.Copy(w, &sparseReader{l: 23e8}); err != nil { + t.Errorf("Compress failed: %v", err) + return + } +} + +type syncBuffer struct { + buf bytes.Buffer + mu sync.RWMutex + closed bool + ready chan bool +} + +func newSyncBuffer() *syncBuffer { + return &syncBuffer{ready: make(chan bool, 1)} +} + +func (b *syncBuffer) Read(p []byte) (n int, err error) { + for { + b.mu.RLock() + n, err = b.buf.Read(p) + b.mu.RUnlock() + if n > 0 || b.closed { + return + } + <-b.ready + } +} + +func (b *syncBuffer) signal() { + select { + case b.ready <- true: + default: + } +} + +func (b *syncBuffer) Write(p []byte) (n int, err error) { + n, err = b.buf.Write(p) + b.signal() + return +} + +func (b *syncBuffer) WriteMode() { + b.mu.Lock() +} + +func (b *syncBuffer) ReadMode() { + b.mu.Unlock() + b.signal() +} + +func (b *syncBuffer) Close() error { + b.closed = true + b.signal() + return nil +} + +func testSync(t *testing.T, level int, input []byte, name string) { + if len(input) == 0 { + return + } + + t.Logf("--testSync %d, %d, %s", level, len(input), name) + buf := newSyncBuffer() + buf1 := new(bytes.Buffer) + buf.WriteMode() + w, err := NewWriter(io.MultiWriter(buf, buf1), level) + if err != nil { + t.Errorf("NewWriter: %v", err) + return + } + r := NewReader(buf) + + // Write half the input and read back. + for i := 0; i < 2; i++ { + var lo, hi int + if i == 0 { + lo, hi = 0, (len(input)+1)/2 + } else { + lo, hi = (len(input)+1)/2, len(input) + } + t.Logf("#%d: write %d-%d", i, lo, hi) + if _, err := w.Write(input[lo:hi]); err != nil { + t.Errorf("testSync: write: %v", err) + return + } + if i == 0 { + if err := w.Flush(); err != nil { + t.Errorf("testSync: flush: %v", err) + return + } + } else { + if err := w.Close(); err != nil { + t.Errorf("testSync: close: %v", err) + } + } + buf.ReadMode() + out := make([]byte, hi-lo+1) + m, err := io.ReadAtLeast(r, out, hi-lo) + t.Logf("#%d: read %d", i, m) + if m != hi-lo || err != nil { + t.Errorf("testSync/%d (%d, %d, %s): read %d: %d, %v (%d left)", i, level, len(input), name, hi-lo, m, err, buf.buf.Len()) + return + } + if !bytes.Equal(input[lo:hi], out[:hi-lo]) { + t.Errorf("testSync/%d: read wrong bytes: %x vs %x", i, input[lo:hi], out[:hi-lo]) + return + } + // This test originally checked that after reading + // the first half of the input, there was nothing left + // in the read buffer (buf.buf.Len() != 0) but that is + // not necessarily the case: the write Flush may emit + // some extra framing bits that are not necessary + // to process to obtain the first half of the uncompressed + // data. The test ran correctly most of the time, because + // the background goroutine had usually read even + // those extra bits by now, but it's not a useful thing to + // check. + buf.WriteMode() + } + buf.ReadMode() + out := make([]byte, 10) + if n, err := r.Read(out); n > 0 || err != io.EOF { + t.Errorf("testSync (%d, %d, %s): final Read: %d, %v (hex: %x)", level, len(input), name, n, err, out[0:n]) + } + if buf.buf.Len() != 0 { + t.Errorf("testSync (%d, %d, %s): extra data at end", level, len(input), name) + } + r.Close() + + // stream should work for ordinary reader too + r = NewReader(buf1) + out, err = ioutil.ReadAll(r) + if err != nil { + t.Errorf("testSync: read: %s", err) + return + } + r.Close() + if !bytes.Equal(input, out) { + t.Errorf("testSync: decompress(compress(data)) != data: level=%d input=%s", level, name) + } +} + +func testToFromWithLevelAndLimit(t *testing.T, level int, input []byte, name string, limit int) { + var buffer bytes.Buffer + w, err := NewWriter(&buffer, level) + if err != nil { + t.Errorf("NewWriter: %v", err) + return + } + w.Write(input) + w.Close() + if limit > 0 && buffer.Len() > limit { + t.Errorf("level: %d, len(compress(data)) = %d > limit = %d", level, buffer.Len(), limit) + return + } + if limit > 0 { + t.Logf("level: %d - Size:%.2f%%, %d b\n", level, float64(buffer.Len()*100)/float64(limit), buffer.Len()) + } + r := NewReader(&buffer) + out, err := ioutil.ReadAll(r) + if err != nil { + t.Errorf("read: %s", err) + return + } + r.Close() + if !bytes.Equal(input, out) { + t.Errorf("decompress(compress(data)) != data: level=%d input=%s", level, name) + return + } + testSync(t, level, input, name) +} + +func testToFromWithLimit(t *testing.T, input []byte, name string, limit [11]int) { + for i := 0; i < 10; i++ { + testToFromWithLevelAndLimit(t, i, input, name, limit[i]) + } + testToFromWithLevelAndLimit(t, -2, input, name, limit[10]) +} + +func TestDeflateInflate(t *testing.T) { + for i, h := range deflateInflateTests { + testToFromWithLimit(t, h.in, fmt.Sprintf("#%d", i), [11]int{}) + } +} + +func TestReverseBits(t *testing.T) { + for _, h := range reverseBitsTests { + if v := reverseBits(h.in, h.bitCount); v != h.out { + t.Errorf("reverseBits(%v,%v) = %v, want %v", + h.in, h.bitCount, v, h.out) + } + } +} + +type deflateInflateStringTest struct { + filename string + label string + limit [11]int // Number 11 is ConstantCompression +} + +var deflateInflateStringTests = []deflateInflateStringTest{ + { + "../testdata/e.txt", + "2.718281828...", + [...]int{100018, 67900, 50960, 51150, 50930, 50790, 50790, 50790, 50790, 50790, 43683 + 100}, + }, + { + "../testdata/Mark.Twain-Tom.Sawyer.txt", + "Mark.Twain-Tom.Sawyer", + [...]int{387999, 185000, 182361, 179974, 174124, 168819, 162936, 160506, 160295, 160295, 233460 + 100}, + }, +} + +func TestDeflateInflateString(t *testing.T) { + for _, test := range deflateInflateStringTests { + gold, err := ioutil.ReadFile(test.filename) + if err != nil { + t.Error(err) + } + // Remove returns that may be present on Windows + neutral := strings.Map(func(r rune) rune { + if r != '\r' { + return r + } + return -1 + }, string(gold)) + + testToFromWithLimit(t, []byte(neutral), test.label, test.limit) + + if testing.Short() { + break + } + } +} + +func TestReaderDict(t *testing.T) { + const ( + dict = "hello world" + text = "hello again world" + ) + var b bytes.Buffer + w, err := NewWriter(&b, 5) + if err != nil { + t.Fatalf("NewWriter: %v", err) + } + w.Write([]byte(dict)) + w.Flush() + b.Reset() + w.Write([]byte(text)) + w.Close() + + r := NewReaderDict(&b, []byte(dict)) + data, err := ioutil.ReadAll(r) + if err != nil { + t.Fatal(err) + } + if string(data) != "hello again world" { + t.Fatalf("read returned %q want %q", string(data), text) + } +} + +func TestWriterDict(t *testing.T) { + const ( + dict = "hello world Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua." + text = "hello world Lorem ipsum dolor sit amet" + ) + // This test is sensitive to algorithm changes that skip + // data in favour of speed. Higher levels are less prone to this + // so we test level 4-9. + for l := 4; l < 9; l++ { + var b bytes.Buffer + w, err := NewWriter(&b, l) + if err != nil { + t.Fatalf("level %d, NewWriter: %v", l, err) + } + w.Write([]byte(dict)) + w.Flush() + b.Reset() + w.Write([]byte(text)) + w.Close() + + var b1 bytes.Buffer + w, _ = NewWriterDict(&b1, l, []byte(dict)) + w.Write([]byte(text)) + w.Close() + + if !bytes.Equal(b1.Bytes(), b.Bytes()) { + t.Errorf("level %d, writer wrote\n%v\n want\n%v", l, b1.Bytes(), b.Bytes()) + } + } +} + +// See http://code.google.com/p/go/issues/detail?id=2508 +func TestRegression2508(t *testing.T) { + if testing.Short() { + t.Logf("test disabled with -short") + return + } + w, err := NewWriter(ioutil.Discard, 1) + if err != nil { + t.Fatalf("NewWriter: %v", err) + } + buf := make([]byte, 1024) + for i := 0; i < 131072; i++ { + if _, err := w.Write(buf); err != nil { + t.Fatalf("writer failed: %v", err) + } + } + w.Close() +} + +func TestWriterReset(t *testing.T) { + for level := -2; level <= 9; level++ { + if level == -1 { + level++ + } + if testing.Short() && level > 1 { + break + } + w, err := NewWriter(ioutil.Discard, level) + if err != nil { + t.Fatalf("NewWriter: %v", err) + } + buf := []byte("hello world") + for i := 0; i < 1024; i++ { + w.Write(buf) + } + w.Reset(ioutil.Discard) + + wref, err := NewWriter(ioutil.Discard, level) + if err != nil { + t.Fatalf("NewWriter: %v", err) + } + + // DeepEqual doesn't compare functions. + w.d.fill, wref.d.fill = nil, nil + w.d.step, wref.d.step = nil, nil + w.d.state, wref.d.state = nil, nil + w.d.fast, wref.d.fast = nil, nil + + // hashMatch is always overwritten when used. + if w.d.tokens.n != 0 { + t.Errorf("level %d Writer not reset after Reset. %d tokens were present", level, w.d.tokens.n) + } + // As long as the length is 0, we don't care about the content. + w.d.tokens = wref.d.tokens + + // We don't care if there are values in the window, as long as it is at d.index is 0 + w.d.window = wref.d.window + if !reflect.DeepEqual(w, wref) { + t.Errorf("level %d Writer not reset after Reset", level) + } + } + + for i := HuffmanOnly; i <= BestCompression; i++ { + testResetOutput(t, fmt.Sprint("level-", i), func(w io.Writer) (*Writer, error) { return NewWriter(w, i) }) + } + dict := []byte(strings.Repeat("we are the world - how are you?", 3)) + for i := HuffmanOnly; i <= BestCompression; i++ { + testResetOutput(t, fmt.Sprint("dict-level-", i), func(w io.Writer) (*Writer, error) { return NewWriterDict(w, i, dict) }) + } + for i := HuffmanOnly; i <= BestCompression; i++ { + testResetOutput(t, fmt.Sprint("dict-reset-level-", i), func(w io.Writer) (*Writer, error) { + w2, err := NewWriter(nil, i) + if err != nil { + return w2, err + } + w2.ResetDict(w, dict) + return w2, nil + }) + } +} + +func testResetOutput(t *testing.T, name string, newWriter func(w io.Writer) (*Writer, error)) { + t.Run(name, func(t *testing.T) { + buf := new(bytes.Buffer) + w, err := newWriter(buf) + if err != nil { + t.Fatalf("NewWriter: %v", err) + } + b := []byte("hello world - how are you doing?") + for i := 0; i < 1024; i++ { + w.Write(b) + } + w.Close() + out1 := buf.Bytes() + + buf2 := new(bytes.Buffer) + w.Reset(buf2) + for i := 0; i < 1024; i++ { + w.Write(b) + } + w.Close() + out2 := buf2.Bytes() + + if len(out1) != len(out2) { + t.Errorf("got %d, expected %d bytes", len(out2), len(out1)) + } + if bytes.Compare(out1, out2) != 0 { + mm := 0 + for i, b := range out1[:len(out2)] { + if b != out2[i] { + t.Errorf("mismatch index %d: %02x, expected %02x", i, out2[i], b) + } + mm++ + if mm == 10 { + t.Fatal("Stopping") + } + } + } + t.Logf("got %d bytes", len(out1)) + }) +} + +// TestBestSpeed tests that round-tripping through deflate and then inflate +// recovers the original input. The Write sizes are near the thresholds in the +// compressor.encSpeed method (0, 16, 128), as well as near maxStoreBlockSize +// (65535). +func TestBestSpeed(t *testing.T) { + abc := make([]byte, 128) + for i := range abc { + abc[i] = byte(i) + } + abcabc := bytes.Repeat(abc, 131072/len(abc)) + var want []byte + + testCases := [][]int{ + {65536, 0}, + {65536, 1}, + {65536, 1, 256}, + {65536, 1, 65536}, + {65536, 14}, + {65536, 15}, + {65536, 16}, + {65536, 16, 256}, + {65536, 16, 65536}, + {65536, 127}, + {65536, 128}, + {65536, 128, 256}, + {65536, 128, 65536}, + {65536, 129}, + {65536, 65536, 256}, + {65536, 65536, 65536}, + } + + for i, tc := range testCases { + for _, firstN := range []int{1, 65534, 65535, 65536, 65537, 131072} { + tc[0] = firstN + outer: + for _, flush := range []bool{false, true} { + buf := new(bytes.Buffer) + want = want[:0] + + w, err := NewWriter(buf, BestSpeed) + if err != nil { + t.Errorf("i=%d, firstN=%d, flush=%t: NewWriter: %v", i, firstN, flush, err) + continue + } + for _, n := range tc { + want = append(want, abcabc[:n]...) + if _, err := w.Write(abcabc[:n]); err != nil { + t.Errorf("i=%d, firstN=%d, flush=%t: Write: %v", i, firstN, flush, err) + continue outer + } + if !flush { + continue + } + if err := w.Flush(); err != nil { + t.Errorf("i=%d, firstN=%d, flush=%t: Flush: %v", i, firstN, flush, err) + continue outer + } + } + if err := w.Close(); err != nil { + t.Errorf("i=%d, firstN=%d, flush=%t: Close: %v", i, firstN, flush, err) + continue + } + + r := NewReader(buf) + got, err := ioutil.ReadAll(r) + if err != nil { + t.Errorf("i=%d, firstN=%d, flush=%t: ReadAll: %v", i, firstN, flush, err) + continue + } + r.Close() + + if !bytes.Equal(got, want) { + t.Errorf("i=%d, firstN=%d, flush=%t: corruption during deflate-then-inflate", i, firstN, flush) + continue + } + } + } + } +} diff --git a/github.com/klauspost/compress/flate/dict_decoder.go b/github.com/klauspost/compress/flate/dict_decoder.go new file mode 100644 index 0000000..71c75a0 --- /dev/null +++ b/github.com/klauspost/compress/flate/dict_decoder.go @@ -0,0 +1,184 @@ +// Copyright 2016 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package flate + +// dictDecoder implements the LZ77 sliding dictionary as used in decompression. +// LZ77 decompresses data through sequences of two forms of commands: +// +// * Literal insertions: Runs of one or more symbols are inserted into the data +// stream as is. This is accomplished through the writeByte method for a +// single symbol, or combinations of writeSlice/writeMark for multiple symbols. +// Any valid stream must start with a literal insertion if no preset dictionary +// is used. +// +// * Backward copies: Runs of one or more symbols are copied from previously +// emitted data. Backward copies come as the tuple (dist, length) where dist +// determines how far back in the stream to copy from and length determines how +// many bytes to copy. Note that it is valid for the length to be greater than +// the distance. Since LZ77 uses forward copies, that situation is used to +// perform a form of run-length encoding on repeated runs of symbols. +// The writeCopy and tryWriteCopy are used to implement this command. +// +// For performance reasons, this implementation performs little to no sanity +// checks about the arguments. As such, the invariants documented for each +// method call must be respected. +type dictDecoder struct { + hist []byte // Sliding window history + + // Invariant: 0 <= rdPos <= wrPos <= len(hist) + wrPos int // Current output position in buffer + rdPos int // Have emitted hist[:rdPos] already + full bool // Has a full window length been written yet? +} + +// init initializes dictDecoder to have a sliding window dictionary of the given +// size. If a preset dict is provided, it will initialize the dictionary with +// the contents of dict. +func (dd *dictDecoder) init(size int, dict []byte) { + *dd = dictDecoder{hist: dd.hist} + + if cap(dd.hist) < size { + dd.hist = make([]byte, size) + } + dd.hist = dd.hist[:size] + + if len(dict) > len(dd.hist) { + dict = dict[len(dict)-len(dd.hist):] + } + dd.wrPos = copy(dd.hist, dict) + if dd.wrPos == len(dd.hist) { + dd.wrPos = 0 + dd.full = true + } + dd.rdPos = dd.wrPos +} + +// histSize reports the total amount of historical data in the dictionary. +func (dd *dictDecoder) histSize() int { + if dd.full { + return len(dd.hist) + } + return dd.wrPos +} + +// availRead reports the number of bytes that can be flushed by readFlush. +func (dd *dictDecoder) availRead() int { + return dd.wrPos - dd.rdPos +} + +// availWrite reports the available amount of output buffer space. +func (dd *dictDecoder) availWrite() int { + return len(dd.hist) - dd.wrPos +} + +// writeSlice returns a slice of the available buffer to write data to. +// +// This invariant will be kept: len(s) <= availWrite() +func (dd *dictDecoder) writeSlice() []byte { + return dd.hist[dd.wrPos:] +} + +// writeMark advances the writer pointer by cnt. +// +// This invariant must be kept: 0 <= cnt <= availWrite() +func (dd *dictDecoder) writeMark(cnt int) { + dd.wrPos += cnt +} + +// writeByte writes a single byte to the dictionary. +// +// This invariant must be kept: 0 < availWrite() +func (dd *dictDecoder) writeByte(c byte) { + dd.hist[dd.wrPos] = c + dd.wrPos++ +} + +// writeCopy copies a string at a given (dist, length) to the output. +// This returns the number of bytes copied and may be less than the requested +// length if the available space in the output buffer is too small. +// +// This invariant must be kept: 0 < dist <= histSize() +func (dd *dictDecoder) writeCopy(dist, length int) int { + dstBase := dd.wrPos + dstPos := dstBase + srcPos := dstPos - dist + endPos := dstPos + length + if endPos > len(dd.hist) { + endPos = len(dd.hist) + } + + // Copy non-overlapping section after destination position. + // + // This section is non-overlapping in that the copy length for this section + // is always less than or equal to the backwards distance. This can occur + // if a distance refers to data that wraps-around in the buffer. + // Thus, a backwards copy is performed here; that is, the exact bytes in + // the source prior to the copy is placed in the destination. + if srcPos < 0 { + srcPos += len(dd.hist) + dstPos += copy(dd.hist[dstPos:endPos], dd.hist[srcPos:]) + srcPos = 0 + } + + // Copy possibly overlapping section before destination position. + // + // This section can overlap if the copy length for this section is larger + // than the backwards distance. This is allowed by LZ77 so that repeated + // strings can be succinctly represented using (dist, length) pairs. + // Thus, a forwards copy is performed here; that is, the bytes copied is + // possibly dependent on the resulting bytes in the destination as the copy + // progresses along. This is functionally equivalent to the following: + // + // for i := 0; i < endPos-dstPos; i++ { + // dd.hist[dstPos+i] = dd.hist[srcPos+i] + // } + // dstPos = endPos + // + for dstPos < endPos { + dstPos += copy(dd.hist[dstPos:endPos], dd.hist[srcPos:dstPos]) + } + + dd.wrPos = dstPos + return dstPos - dstBase +} + +// tryWriteCopy tries to copy a string at a given (distance, length) to the +// output. This specialized version is optimized for short distances. +// +// This method is designed to be inlined for performance reasons. +// +// This invariant must be kept: 0 < dist <= histSize() +func (dd *dictDecoder) tryWriteCopy(dist, length int) int { + dstPos := dd.wrPos + endPos := dstPos + length + if dstPos < dist || endPos > len(dd.hist) { + return 0 + } + dstBase := dstPos + srcPos := dstPos - dist + + // Copy possibly overlapping section before destination position. +loop: + dstPos += copy(dd.hist[dstPos:endPos], dd.hist[srcPos:dstPos]) + if dstPos < endPos { + goto loop // Avoid for-loop so that this function can be inlined + } + + dd.wrPos = dstPos + return dstPos - dstBase +} + +// readFlush returns a slice of the historical buffer that is ready to be +// emitted to the user. The data returned by readFlush must be fully consumed +// before calling any other dictDecoder methods. +func (dd *dictDecoder) readFlush() []byte { + toRead := dd.hist[dd.rdPos:dd.wrPos] + dd.rdPos = dd.wrPos + if dd.wrPos == len(dd.hist) { + dd.wrPos, dd.rdPos = 0, 0 + dd.full = true + } + return toRead +} diff --git a/github.com/klauspost/compress/flate/dict_decoder_test.go b/github.com/klauspost/compress/flate/dict_decoder_test.go new file mode 100644 index 0000000..9275cff --- /dev/null +++ b/github.com/klauspost/compress/flate/dict_decoder_test.go @@ -0,0 +1,139 @@ +// Copyright 2016 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package flate + +import ( + "bytes" + "strings" + "testing" +) + +func TestDictDecoder(t *testing.T) { + const ( + abc = "ABC\n" + fox = "The quick brown fox jumped over the lazy dog!\n" + poem = "The Road Not Taken\nRobert Frost\n" + + "\n" + + "Two roads diverged in a yellow wood,\n" + + "And sorry I could not travel both\n" + + "And be one traveler, long I stood\n" + + "And looked down one as far as I could\n" + + "To where it bent in the undergrowth;\n" + + "\n" + + "Then took the other, as just as fair,\n" + + "And having perhaps the better claim,\n" + + "Because it was grassy and wanted wear;\n" + + "Though as for that the passing there\n" + + "Had worn them really about the same,\n" + + "\n" + + "And both that morning equally lay\n" + + "In leaves no step had trodden black.\n" + + "Oh, I kept the first for another day!\n" + + "Yet knowing how way leads on to way,\n" + + "I doubted if I should ever come back.\n" + + "\n" + + "I shall be telling this with a sigh\n" + + "Somewhere ages and ages hence:\n" + + "Two roads diverged in a wood, and I-\n" + + "I took the one less traveled by,\n" + + "And that has made all the difference.\n" + ) + + var poemRefs = []struct { + dist int // Backward distance (0 if this is an insertion) + length int // Length of copy or insertion + }{ + {0, 38}, {33, 3}, {0, 48}, {79, 3}, {0, 11}, {34, 5}, {0, 6}, {23, 7}, + {0, 8}, {50, 3}, {0, 2}, {69, 3}, {34, 5}, {0, 4}, {97, 3}, {0, 4}, + {43, 5}, {0, 6}, {7, 4}, {88, 7}, {0, 12}, {80, 3}, {0, 2}, {141, 4}, + {0, 1}, {196, 3}, {0, 3}, {157, 3}, {0, 6}, {181, 3}, {0, 2}, {23, 3}, + {77, 3}, {28, 5}, {128, 3}, {110, 4}, {70, 3}, {0, 4}, {85, 6}, {0, 2}, + {182, 6}, {0, 4}, {133, 3}, {0, 7}, {47, 5}, {0, 20}, {112, 5}, {0, 1}, + {58, 3}, {0, 8}, {59, 3}, {0, 4}, {173, 3}, {0, 5}, {114, 3}, {0, 4}, + {92, 5}, {0, 2}, {71, 3}, {0, 2}, {76, 5}, {0, 1}, {46, 3}, {96, 4}, + {130, 4}, {0, 3}, {360, 3}, {0, 3}, {178, 5}, {0, 7}, {75, 3}, {0, 3}, + {45, 6}, {0, 6}, {299, 6}, {180, 3}, {70, 6}, {0, 1}, {48, 3}, {66, 4}, + {0, 3}, {47, 5}, {0, 9}, {325, 3}, {0, 1}, {359, 3}, {318, 3}, {0, 2}, + {199, 3}, {0, 1}, {344, 3}, {0, 3}, {248, 3}, {0, 10}, {310, 3}, {0, 3}, + {93, 6}, {0, 3}, {252, 3}, {157, 4}, {0, 2}, {273, 5}, {0, 14}, {99, 4}, + {0, 1}, {464, 4}, {0, 2}, {92, 4}, {495, 3}, {0, 1}, {322, 4}, {16, 4}, + {0, 3}, {402, 3}, {0, 2}, {237, 4}, {0, 2}, {432, 4}, {0, 1}, {483, 5}, + {0, 2}, {294, 4}, {0, 2}, {306, 3}, {113, 5}, {0, 1}, {26, 4}, {164, 3}, + {488, 4}, {0, 1}, {542, 3}, {248, 6}, {0, 5}, {205, 3}, {0, 8}, {48, 3}, + {449, 6}, {0, 2}, {192, 3}, {328, 4}, {9, 5}, {433, 3}, {0, 3}, {622, 25}, + {615, 5}, {46, 5}, {0, 2}, {104, 3}, {475, 10}, {549, 3}, {0, 4}, {597, 8}, + {314, 3}, {0, 1}, {473, 6}, {317, 5}, {0, 1}, {400, 3}, {0, 3}, {109, 3}, + {151, 3}, {48, 4}, {0, 4}, {125, 3}, {108, 3}, {0, 2}, + } + + var got, want bytes.Buffer + var dd dictDecoder + dd.init(1<<11, nil) + + var writeCopy = func(dist, length int) { + for length > 0 { + cnt := dd.tryWriteCopy(dist, length) + if cnt == 0 { + cnt = dd.writeCopy(dist, length) + } + + length -= cnt + if dd.availWrite() == 0 { + got.Write(dd.readFlush()) + } + } + } + var writeString = func(str string) { + for len(str) > 0 { + cnt := copy(dd.writeSlice(), str) + str = str[cnt:] + dd.writeMark(cnt) + if dd.availWrite() == 0 { + got.Write(dd.readFlush()) + } + } + } + + writeString(".") + want.WriteByte('.') + + str := poem + for _, ref := range poemRefs { + if ref.dist == 0 { + writeString(str[:ref.length]) + } else { + writeCopy(ref.dist, ref.length) + } + str = str[ref.length:] + } + want.WriteString(poem) + + writeCopy(dd.histSize(), 33) + want.Write(want.Bytes()[:33]) + + writeString(abc) + writeCopy(len(abc), 59*len(abc)) + want.WriteString(strings.Repeat(abc, 60)) + + writeString(fox) + writeCopy(len(fox), 9*len(fox)) + want.WriteString(strings.Repeat(fox, 10)) + + writeString(".") + writeCopy(1, 9) + want.WriteString(strings.Repeat(".", 10)) + + writeString(strings.ToUpper(poem)) + writeCopy(len(poem), 7*len(poem)) + want.WriteString(strings.Repeat(strings.ToUpper(poem), 8)) + + writeCopy(dd.histSize(), 10) + want.Write(want.Bytes()[want.Len()-dd.histSize():][:10]) + + got.Write(dd.readFlush()) + if got.String() != want.String() { + t.Errorf("final string mismatch:\ngot %q\nwant %q", got.String(), want.String()) + } +} diff --git a/github.com/klauspost/compress/flate/fast_encoder.go b/github.com/klauspost/compress/flate/fast_encoder.go new file mode 100644 index 0000000..6d4c1e9 --- /dev/null +++ b/github.com/klauspost/compress/flate/fast_encoder.go @@ -0,0 +1,254 @@ +// Copyright 2011 The Snappy-Go Authors. All rights reserved. +// Modified for deflate by Klaus Post (c) 2015. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package flate + +import ( + "fmt" + "math/bits" +) + +type fastEnc interface { + Encode(dst *tokens, src []byte) + Reset() +} + +func newFastEnc(level int) fastEnc { + switch level { + case 1: + return &fastEncL1{fastGen: fastGen{cur: maxStoreBlockSize}} + case 2: + return &fastEncL2{fastGen: fastGen{cur: maxStoreBlockSize}} + case 3: + return &fastEncL3{fastGen: fastGen{cur: maxStoreBlockSize}} + case 4: + return &fastEncL4{fastGen: fastGen{cur: maxStoreBlockSize}} + case 5: + return &fastEncL5{fastGen: fastGen{cur: maxStoreBlockSize}} + case 6: + return &fastEncL6{fastGen: fastGen{cur: maxStoreBlockSize}} + default: + panic("invalid level specified") + } +} + +const ( + tableBits = 15 // Bits used in the table + tableSize = 1 << tableBits // Size of the table + tableShift = 32 - tableBits // Right-shift to get the tableBits most significant bits of a uint32. + baseMatchOffset = 1 // The smallest match offset + baseMatchLength = 3 // The smallest match length per the RFC section 3.2.5 + maxMatchOffset = 1 << 15 // The largest match offset + + bTableBits = 17 // Bits used in the big tables + bTableSize = 1 << bTableBits // Size of the table + allocHistory = maxStoreBlockSize * 10 // Size to preallocate for history. + bufferReset = (1 << 31) - allocHistory - maxStoreBlockSize - 1 // Reset the buffer offset when reaching this. +) + +const ( + prime3bytes = 506832829 + prime4bytes = 2654435761 + prime5bytes = 889523592379 + prime6bytes = 227718039650203 + prime7bytes = 58295818150454627 + prime8bytes = 0xcf1bbcdcb7a56463 +) + +func load32(b []byte, i int) uint32 { + // Help the compiler eliminate bounds checks on the read so it can be done in a single read. + b = b[i:] + b = b[:4] + return uint32(b[0]) | uint32(b[1])<<8 | uint32(b[2])<<16 | uint32(b[3])<<24 +} + +func load64(b []byte, i int) uint64 { + // Help the compiler eliminate bounds checks on the read so it can be done in a single read. + b = b[i:] + b = b[:8] + return uint64(b[0]) | uint64(b[1])<<8 | uint64(b[2])<<16 | uint64(b[3])<<24 | + uint64(b[4])<<32 | uint64(b[5])<<40 | uint64(b[6])<<48 | uint64(b[7])<<56 +} + +func load3232(b []byte, i int32) uint32 { + // Help the compiler eliminate bounds checks on the read so it can be done in a single read. + b = b[i:] + b = b[:4] + return uint32(b[0]) | uint32(b[1])<<8 | uint32(b[2])<<16 | uint32(b[3])<<24 +} + +func load6432(b []byte, i int32) uint64 { + // Help the compiler eliminate bounds checks on the read so it can be done in a single read. + b = b[i:] + b = b[:8] + return uint64(b[0]) | uint64(b[1])<<8 | uint64(b[2])<<16 | uint64(b[3])<<24 | + uint64(b[4])<<32 | uint64(b[5])<<40 | uint64(b[6])<<48 | uint64(b[7])<<56 +} + +func hash(u uint32) uint32 { + return (u * 0x1e35a7bd) >> tableShift +} + +type tableEntry struct { + offset int32 +} + +// fastGen maintains the table for matches, +// and the previous byte block for level 2. +// This is the generic implementation. +type fastGen struct { + hist []byte + cur int32 +} + +func (e *fastGen) addBlock(src []byte) int32 { + // check if we have space already + if len(e.hist)+len(src) > cap(e.hist) { + if cap(e.hist) == 0 { + e.hist = make([]byte, 0, allocHistory) + } else { + if cap(e.hist) < maxMatchOffset*2 { + panic("unexpected buffer size") + } + // Move down + offset := int32(len(e.hist)) - maxMatchOffset + copy(e.hist[0:maxMatchOffset], e.hist[offset:]) + e.cur += offset + e.hist = e.hist[:maxMatchOffset] + } + } + s := int32(len(e.hist)) + e.hist = append(e.hist, src...) + return s +} + +// hash4 returns the hash of u to fit in a hash table with h bits. +// Preferably h should be a constant and should always be <32. +func hash4u(u uint32, h uint8) uint32 { + return (u * prime4bytes) >> ((32 - h) & 31) +} + +type tableEntryPrev struct { + Cur tableEntry + Prev tableEntry +} + +// hash4x64 returns the hash of the lowest 4 bytes of u to fit in a hash table with h bits. +// Preferably h should be a constant and should always be <32. +func hash4x64(u uint64, h uint8) uint32 { + return (uint32(u) * prime4bytes) >> ((32 - h) & 31) +} + +// hash7 returns the hash of the lowest 7 bytes of u to fit in a hash table with h bits. +// Preferably h should be a constant and should always be <64. +func hash7(u uint64, h uint8) uint32 { + return uint32(((u << (64 - 56)) * prime7bytes) >> ((64 - h) & 63)) +} + +// hash8 returns the hash of u to fit in a hash table with h bits. +// Preferably h should be a constant and should always be <64. +func hash8(u uint64, h uint8) uint32 { + return uint32((u * prime8bytes) >> ((64 - h) & 63)) +} + +// hash6 returns the hash of the lowest 6 bytes of u to fit in a hash table with h bits. +// Preferably h should be a constant and should always be <64. +func hash6(u uint64, h uint8) uint32 { + return uint32(((u << (64 - 48)) * prime6bytes) >> ((64 - h) & 63)) +} + +// matchlen will return the match length between offsets and t in src. +// The maximum length returned is maxMatchLength - 4. +// It is assumed that s > t, that t >=0 and s < len(src). +func (e *fastGen) matchlen(s, t int32, src []byte) int32 { + if debugDecode { + if t >= s { + panic(fmt.Sprint("t >=s:", t, s)) + } + if int(s) >= len(src) { + panic(fmt.Sprint("s >= len(src):", s, len(src))) + } + if t < 0 { + panic(fmt.Sprint("t < 0:", t)) + } + if s-t > maxMatchOffset { + panic(fmt.Sprint(s, "-", t, "(", s-t, ") > maxMatchLength (", maxMatchOffset, ")")) + } + } + s1 := int(s) + maxMatchLength - 4 + if s1 > len(src) { + s1 = len(src) + } + + // Extend the match to be as long as possible. + return int32(matchLen(src[s:s1], src[t:])) +} + +// matchlenLong will return the match length between offsets and t in src. +// It is assumed that s > t, that t >=0 and s < len(src). +func (e *fastGen) matchlenLong(s, t int32, src []byte) int32 { + if debugDecode { + if t >= s { + panic(fmt.Sprint("t >=s:", t, s)) + } + if int(s) >= len(src) { + panic(fmt.Sprint("s >= len(src):", s, len(src))) + } + if t < 0 { + panic(fmt.Sprint("t < 0:", t)) + } + if s-t > maxMatchOffset { + panic(fmt.Sprint(s, "-", t, "(", s-t, ") > maxMatchLength (", maxMatchOffset, ")")) + } + } + // Extend the match to be as long as possible. + return int32(matchLen(src[s:], src[t:])) +} + +// Reset the encoding table. +func (e *fastGen) Reset() { + if cap(e.hist) < allocHistory { + e.hist = make([]byte, 0, allocHistory) + } + // We offset current position so everything will be out of reach. + // If we are above the buffer reset it will be cleared anyway since len(hist) == 0. + if e.cur <= bufferReset { + e.cur += maxMatchOffset + int32(len(e.hist)) + } + e.hist = e.hist[:0] +} + +// matchLen returns the maximum length. +// 'a' must be the shortest of the two. +func matchLen(a, b []byte) int { + b = b[:len(a)] + var checked int + if len(a) > 4 { + // Try 4 bytes first + if diff := load32(a, 0) ^ load32(b, 0); diff != 0 { + return bits.TrailingZeros32(diff) >> 3 + } + // Switch to 8 byte matching. + checked = 4 + a = a[4:] + b = b[4:] + for len(a) >= 8 { + b = b[:len(a)] + if diff := load64(a, 0) ^ load64(b, 0); diff != 0 { + return checked + (bits.TrailingZeros64(diff) >> 3) + } + checked += 8 + a = a[8:] + b = b[8:] + } + } + b = b[:len(a)] + for i := range a { + if a[i] != b[i] { + return int(i) + checked + } + } + return len(a) + checked +} diff --git a/github.com/klauspost/compress/flate/flate_test.go b/github.com/klauspost/compress/flate/flate_test.go new file mode 100644 index 0000000..52517d8 --- /dev/null +++ b/github.com/klauspost/compress/flate/flate_test.go @@ -0,0 +1,360 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// This test tests some internals of the flate package. +// The tests in package compress/gzip serve as the +// end-to-end test of the decompressor. + +package flate + +import ( + "archive/zip" + "bytes" + "compress/flate" + "encoding/hex" + "fmt" + "io/ioutil" + "testing" +) + +// The following test should not panic. +func TestIssue5915(t *testing.T) { + bits := []int{4, 0, 0, 6, 4, 3, 2, 3, 3, 4, 4, 5, 0, 0, 0, 0, 5, 5, 6, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 8, 6, 0, 11, 0, 8, 0, 6, 6, 10, 8} + var h huffmanDecoder + if h.init(bits) { + t.Fatalf("Given sequence of bits is bad, and should not succeed.") + } +} + +// The following test should not panic. +func TestIssue5962(t *testing.T) { + bits := []int{4, 0, 0, 6, 4, 3, 2, 3, 3, 4, 4, 5, 0, 0, 0, 0, + 5, 5, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11} + var h huffmanDecoder + if h.init(bits) { + t.Fatalf("Given sequence of bits is bad, and should not succeed.") + } +} + +// The following test should not panic. +func TestIssue6255(t *testing.T) { + bits1 := []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 11} + bits2 := []int{11, 13} + var h huffmanDecoder + if !h.init(bits1) { + t.Fatalf("Given sequence of bits is good and should succeed.") + } + if h.init(bits2) { + t.Fatalf("Given sequence of bits is bad and should not succeed.") + } +} + +func TestInvalidEncoding(t *testing.T) { + // Initialize Huffman decoder to recognize "0". + var h huffmanDecoder + if !h.init([]int{1}) { + t.Fatal("Failed to initialize Huffman decoder") + } + + // Initialize decompressor with invalid Huffman coding. + var f decompressor + f.r = bytes.NewReader([]byte{0xff}) + + _, err := f.huffSym(&h) + if err == nil { + t.Fatal("Should have rejected invalid bit sequence") + } +} + +func TestRegressions(t *testing.T) { + // Test fuzzer regressions + data, err := ioutil.ReadFile("testdata/regression.zip") + if err != nil { + t.Fatal(err) + } + zr, err := zip.NewReader(bytes.NewReader(data), int64(len(data))) + if err != nil { + t.Fatal(err) + } + for _, tt := range zr.File { + data, err := tt.Open() + if err != nil { + t.Fatal(err) + } + data1, err := ioutil.ReadAll(data) + if err != nil { + t.Fatal(err) + } + for level := 0; level <= 9; level++ { + t.Run(fmt.Sprint(tt.Name+"-level", 1), func(t *testing.T) { + buf := new(bytes.Buffer) + fw, err := NewWriter(buf, level) + if err != nil { + t.Error(err) + } + n, err := fw.Write(data1) + if n != len(data1) { + t.Error("short write") + } + if err != nil { + t.Error(err) + } + err = fw.Close() + if err != nil { + t.Error(err) + } + fr1 := NewReader(buf) + data2, err := ioutil.ReadAll(fr1) + if err != nil { + t.Error(err) + } + if bytes.Compare(data1, data2) != 0 { + t.Error("not equal") + } + // Do it again... + buf.Reset() + fw.Reset(buf) + n, err = fw.Write(data1) + if n != len(data1) { + t.Error("short write") + } + if err != nil { + t.Error(err) + } + err = fw.Close() + if err != nil { + t.Error(err) + } + fr1 = flate.NewReader(buf) + data2, err = ioutil.ReadAll(fr1) + if err != nil { + t.Error(err) + } + if bytes.Compare(data1, data2) != 0 { + t.Error("not equal") + } + }) + } + t.Run(tt.Name+"stateless", func(t *testing.T) { + // Split into two and use history... + buf := new(bytes.Buffer) + err = StatelessDeflate(buf, data1[:len(data1)/2], false, nil) + if err != nil { + t.Error(err) + } + + // Use top half as dictionary... + dict := data1[:len(data1)/2] + err = StatelessDeflate(buf, data1[len(data1)/2:], true, dict) + if err != nil { + t.Error(err) + } + t.Log(buf.Len()) + fr1 := NewReader(buf) + data2, err := ioutil.ReadAll(fr1) + if err != nil { + t.Error(err) + } + if bytes.Compare(data1, data2) != 0 { + fmt.Printf("want:%x\ngot: %x\n", data1, data2) + t.Error("not equal") + } + }) + } +} + +func TestInvalidBits(t *testing.T) { + oversubscribed := []int{1, 2, 3, 4, 4, 5} + incomplete := []int{1, 2, 4, 4} + var h huffmanDecoder + if h.init(oversubscribed) { + t.Fatal("Should reject oversubscribed bit-length set") + } + if h.init(incomplete) { + t.Fatal("Should reject incomplete bit-length set") + } +} + +func TestStreams(t *testing.T) { + // To verify any of these hexstrings as valid or invalid flate streams + // according to the C zlib library, you can use the Python wrapper library: + // >>> hex_string = "010100feff11" + // >>> import zlib + // >>> zlib.decompress(hex_string.decode("hex"), -15) # Negative means raw DEFLATE + // '\x11' + + testCases := []struct { + desc string // Description of the stream + stream string // Hexstring of the input DEFLATE stream + want string // Expected result. Use "fail" to expect failure + }{{ + "degenerate HCLenTree", + "05e0010000000000100000000000000000000000000000000000000000000000" + + "00000000000000000004", + "fail", + }, { + "complete HCLenTree, empty HLitTree, empty HDistTree", + "05e0010400000000000000000000000000000000000000000000000000000000" + + "00000000000000000010", + "fail", + }, { + "empty HCLenTree", + "05e0010000000000000000000000000000000000000000000000000000000000" + + "00000000000000000010", + "fail", + }, { + "complete HCLenTree, complete HLitTree, empty HDistTree, use missing HDist symbol", + "000100feff000de0010400000000100000000000000000000000000000000000" + + "0000000000000000000000000000002c", + "fail", + }, { + "complete HCLenTree, complete HLitTree, degenerate HDistTree, use missing HDist symbol", + "000100feff000de0010000000000000000000000000000000000000000000000" + + "00000000000000000610000000004070", + "fail", + }, { + "complete HCLenTree, empty HLitTree, empty HDistTree", + "05e0010400000000100400000000000000000000000000000000000000000000" + + "0000000000000000000000000008", + "fail", + }, { + "complete HCLenTree, empty HLitTree, degenerate HDistTree", + "05e0010400000000100400000000000000000000000000000000000000000000" + + "0000000000000000000800000008", + "fail", + }, { + "complete HCLenTree, degenerate HLitTree, degenerate HDistTree, use missing HLit symbol", + "05e0010400000000100000000000000000000000000000000000000000000000" + + "0000000000000000001c", + "fail", + }, { + "complete HCLenTree, complete HLitTree, too large HDistTree", + "edff870500000000200400000000000000000000000000000000000000000000" + + "000000000000000000080000000000000004", + "fail", + }, { + "complete HCLenTree, complete HLitTree, empty HDistTree, excessive repeater code", + "edfd870500000000200400000000000000000000000000000000000000000000" + + "000000000000000000e8b100", + "fail", + }, { + "complete HCLenTree, complete HLitTree, empty HDistTree of normal length 30", + "05fd01240000000000f8ffffffffffffffffffffffffffffffffffffffffffff" + + "ffffffffffffffffff07000000fe01", + "", + }, { + "complete HCLenTree, complete HLitTree, empty HDistTree of excessive length 31", + "05fe01240000000000f8ffffffffffffffffffffffffffffffffffffffffffff" + + "ffffffffffffffffff07000000fc03", + "fail", + }, { + "complete HCLenTree, over-subscribed HLitTree, empty HDistTree", + "05e001240000000000fcffffffffffffffffffffffffffffffffffffffffffff" + + "ffffffffffffffffff07f00f", + "fail", + }, { + "complete HCLenTree, under-subscribed HLitTree, empty HDistTree", + "05e001240000000000fcffffffffffffffffffffffffffffffffffffffffffff" + + "fffffffffcffffffff07f00f", + "fail", + }, { + "complete HCLenTree, complete HLitTree with single code, empty HDistTree", + "05e001240000000000f8ffffffffffffffffffffffffffffffffffffffffffff" + + "ffffffffffffffffff07f00f", + "01", + }, { + "complete HCLenTree, complete HLitTree with multiple codes, empty HDistTree", + "05e301240000000000f8ffffffffffffffffffffffffffffffffffffffffffff" + + "ffffffffffffffffff07807f", + "01", + }, { + "complete HCLenTree, complete HLitTree, degenerate HDistTree, use valid HDist symbol", + "000100feff000de0010400000000100000000000000000000000000000000000" + + "0000000000000000000000000000003c", + "00000000", + }, { + "complete HCLenTree, degenerate HLitTree, degenerate HDistTree", + "05e0010400000000100000000000000000000000000000000000000000000000" + + "0000000000000000000c", + "", + }, { + "complete HCLenTree, degenerate HLitTree, empty HDistTree", + "05e0010400000000100000000000000000000000000000000000000000000000" + + "00000000000000000004", + "", + }, { + "complete HCLenTree, complete HLitTree, empty HDistTree, spanning repeater code", + "edfd870500000000200400000000000000000000000000000000000000000000" + + "000000000000000000e8b000", + "", + }, { + "complete HCLenTree with length codes, complete HLitTree, empty HDistTree", + "ede0010400000000100000000000000000000000000000000000000000000000" + + "0000000000000000000400004000", + "", + }, { + "complete HCLenTree, complete HLitTree, degenerate HDistTree, use valid HLit symbol 284 with count 31", + "000100feff00ede0010400000000100000000000000000000000000000000000" + + "000000000000000000000000000000040000407f00", + "0000000000000000000000000000000000000000000000000000000000000000" + + "0000000000000000000000000000000000000000000000000000000000000000" + + "0000000000000000000000000000000000000000000000000000000000000000" + + "0000000000000000000000000000000000000000000000000000000000000000" + + "0000000000000000000000000000000000000000000000000000000000000000" + + "0000000000000000000000000000000000000000000000000000000000000000" + + "0000000000000000000000000000000000000000000000000000000000000000" + + "0000000000000000000000000000000000000000000000000000000000000000" + + "000000", + }, { + "complete HCLenTree, complete HLitTree, degenerate HDistTree, use valid HLit and HDist symbols", + "0cc2010d00000082b0ac4aff0eb07d27060000ffff", + "616263616263", + }, { + "fixed block, use reserved symbol 287", + "33180700", + "fail", + }, { + "raw block", + "010100feff11", + "11", + }, { + "issue 10426 - over-subscribed HCLenTree causes a hang", + "344c4a4e494d4b070000ff2e2eff2e2e2e2e2eff", + "fail", + }, { + "issue 11030 - empty HDistTree unexpectedly leads to error", + "05c0070600000080400fff37a0ca", + "", + }, { + "issue 11033 - empty HDistTree unexpectedly leads to error", + "050fb109c020cca5d017dcbca044881ee1034ec149c8980bbc413c2ab35be9dc" + + "b1473449922449922411202306ee97b0383a521b4ffdcf3217f9f7d3adb701", + "3130303634342068652e706870005d05355f7ed957ff084a90925d19e3ebc6d0" + + "c6d7", + }} + + for i, tc := range testCases { + data, err := hex.DecodeString(tc.stream) + if err != nil { + t.Fatal(err) + } + data, err = ioutil.ReadAll(NewReader(bytes.NewReader(data))) + if tc.want == "fail" { + if err == nil { + t.Errorf("#%d (%s): got nil error, want non-nil", i, tc.desc) + } + } else { + if err != nil { + t.Errorf("#%d (%s): %v", i, tc.desc, err) + continue + } + if got := hex.EncodeToString(data); got != tc.want { + t.Errorf("#%d (%s):\ngot %q\nwant %q", i, tc.desc, got, tc.want) + } + + } + } +} diff --git a/github.com/klauspost/compress/flate/gen.go b/github.com/klauspost/compress/flate/gen.go new file mode 100644 index 0000000..154c89a --- /dev/null +++ b/github.com/klauspost/compress/flate/gen.go @@ -0,0 +1,265 @@ +// Copyright 2012 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build ignore + +// This program generates fixedhuff.go +// Invoke as +// +// go run gen.go -output fixedhuff.go + +package main + +import ( + "bytes" + "flag" + "fmt" + "go/format" + "io/ioutil" + "log" +) + +var filename = flag.String("output", "fixedhuff.go", "output file name") + +const maxCodeLen = 16 + +// Note: the definition of the huffmanDecoder struct is copied from +// inflate.go, as it is private to the implementation. + +// chunk & 15 is number of bits +// chunk >> 4 is value, including table link + +const ( + huffmanChunkBits = 9 + huffmanNumChunks = 1 << huffmanChunkBits + huffmanCountMask = 15 + huffmanValueShift = 4 +) + +type huffmanDecoder struct { + min int // the minimum code length + chunks [huffmanNumChunks]uint32 // chunks as described above + links [][]uint32 // overflow links + linkMask uint32 // mask the width of the link table +} + +// Initialize Huffman decoding tables from array of code lengths. +// Following this function, h is guaranteed to be initialized into a complete +// tree (i.e., neither over-subscribed nor under-subscribed). The exception is a +// degenerate case where the tree has only a single symbol with length 1. Empty +// trees are permitted. +func (h *huffmanDecoder) init(bits []int) bool { + // Sanity enables additional runtime tests during Huffman + // table construction. It's intended to be used during + // development to supplement the currently ad-hoc unit tests. + const sanity = false + + if h.min != 0 { + *h = huffmanDecoder{} + } + + // Count number of codes of each length, + // compute min and max length. + var count [maxCodeLen]int + var min, max int + for _, n := range bits { + if n == 0 { + continue + } + if min == 0 || n < min { + min = n + } + if n > max { + max = n + } + count[n]++ + } + + // Empty tree. The decompressor.huffSym function will fail later if the tree + // is used. Technically, an empty tree is only valid for the HDIST tree and + // not the HCLEN and HLIT tree. However, a stream with an empty HCLEN tree + // is guaranteed to fail since it will attempt to use the tree to decode the + // codes for the HLIT and HDIST trees. Similarly, an empty HLIT tree is + // guaranteed to fail later since the compressed data section must be + // composed of at least one symbol (the end-of-block marker). + if max == 0 { + return true + } + + code := 0 + var nextcode [maxCodeLen]int + for i := min; i <= max; i++ { + code <<= 1 + nextcode[i] = code + code += count[i] + } + + // Check that the coding is complete (i.e., that we've + // assigned all 2-to-the-max possible bit sequences). + // Exception: To be compatible with zlib, we also need to + // accept degenerate single-code codings. See also + // TestDegenerateHuffmanCoding. + if code != 1< huffmanChunkBits { + numLinks := 1 << (uint(max) - huffmanChunkBits) + h.linkMask = uint32(numLinks - 1) + + // create link tables + link := nextcode[huffmanChunkBits+1] >> 1 + h.links = make([][]uint32, huffmanNumChunks-link) + for j := uint(link); j < huffmanNumChunks; j++ { + reverse := int(reverseByte[j>>8]) | int(reverseByte[j&0xff])<<8 + reverse >>= uint(16 - huffmanChunkBits) + off := j - uint(link) + if sanity && h.chunks[reverse] != 0 { + panic("impossible: overwriting existing chunk") + } + h.chunks[reverse] = uint32(off<>8]) | int(reverseByte[code&0xff])<<8 + reverse >>= uint(16 - n) + if n <= huffmanChunkBits { + for off := reverse; off < len(h.chunks); off += 1 << uint(n) { + // We should never need to overwrite + // an existing chunk. Also, 0 is + // never a valid chunk, because the + // lower 4 "count" bits should be + // between 1 and 15. + if sanity && h.chunks[off] != 0 { + panic("impossible: overwriting existing chunk") + } + h.chunks[off] = chunk + } + } else { + j := reverse & (huffmanNumChunks - 1) + if sanity && h.chunks[j]&huffmanCountMask != huffmanChunkBits+1 { + // Longer codes should have been + // associated with a link table above. + panic("impossible: not an indirect chunk") + } + value := h.chunks[j] >> huffmanValueShift + linktab := h.links[value] + reverse >>= huffmanChunkBits + for off := reverse; off < len(linktab); off += 1 << uint(n-huffmanChunkBits) { + if sanity && linktab[off] != 0 { + panic("impossible: overwriting existing chunk") + } + linktab[off] = chunk + } + } + } + + if sanity { + // Above we've sanity checked that we never overwrote + // an existing entry. Here we additionally check that + // we filled the tables completely. + for i, chunk := range h.chunks { + if chunk == 0 { + // As an exception, in the degenerate + // single-code case, we allow odd + // chunks to be missing. + if code == 1 && i%2 == 1 { + continue + } + panic("impossible: missing chunk") + } + } + for _, linktab := range h.links { + for _, chunk := range linktab { + if chunk == 0 { + panic("impossible: missing chunk") + } + } + } + } + + return true +} + +func main() { + flag.Parse() + + var h huffmanDecoder + var bits [288]int + initReverseByte() + for i := 0; i < 144; i++ { + bits[i] = 8 + } + for i := 144; i < 256; i++ { + bits[i] = 9 + } + for i := 256; i < 280; i++ { + bits[i] = 7 + } + for i := 280; i < 288; i++ { + bits[i] = 8 + } + h.init(bits[:]) + if h.links != nil { + log.Fatal("Unexpected links table in fixed Huffman decoder") + } + + var buf bytes.Buffer + + fmt.Fprintf(&buf, `// Copyright 2013 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file.`+"\n\n") + + fmt.Fprintln(&buf, "package flate") + fmt.Fprintln(&buf) + fmt.Fprintln(&buf, "// autogenerated by go run gen.go -output fixedhuff.go, DO NOT EDIT") + fmt.Fprintln(&buf) + fmt.Fprintln(&buf, "var fixedHuffmanDecoder = huffmanDecoder{") + fmt.Fprintf(&buf, "\t%d,\n", h.min) + fmt.Fprintln(&buf, "\t[huffmanNumChunks]uint32{") + for i := 0; i < huffmanNumChunks; i++ { + if i&7 == 0 { + fmt.Fprintf(&buf, "\t\t") + } else { + fmt.Fprintf(&buf, " ") + } + fmt.Fprintf(&buf, "0x%04x,", h.chunks[i]) + if i&7 == 7 { + fmt.Fprintln(&buf) + } + } + fmt.Fprintln(&buf, "\t},") + fmt.Fprintln(&buf, "\tnil, 0,") + fmt.Fprintln(&buf, "}") + + data, err := format.Source(buf.Bytes()) + if err != nil { + log.Fatal(err) + } + err = ioutil.WriteFile(*filename, data, 0644) + if err != nil { + log.Fatal(err) + } +} + +var reverseByte [256]byte + +func initReverseByte() { + for x := 0; x < 256; x++ { + var result byte + for i := uint(0); i < 8; i++ { + result |= byte(((x >> i) & 1) << (7 - i)) + } + reverseByte[x] = result + } +} diff --git a/github.com/klauspost/compress/flate/gen_inflate.go b/github.com/klauspost/compress/flate/gen_inflate.go new file mode 100644 index 0000000..c74a95f --- /dev/null +++ b/github.com/klauspost/compress/flate/gen_inflate.go @@ -0,0 +1,274 @@ +// +build generate + +//go:generate go run $GOFILE && gofmt -w inflate_gen.go + +package main + +import ( + "os" + "strings" +) + +func main() { + f, err := os.Create("inflate_gen.go") + if err != nil { + panic(err) + } + defer f.Close() + types := []string{"*bytes.Buffer", "*bytes.Reader", "*bufio.Reader", "*strings.Reader"} + names := []string{"BytesBuffer", "BytesReader", "BufioReader", "StringsReader"} + imports := []string{"bytes", "bufio", "io", "strings", "math/bits"} + f.WriteString(`// Code generated by go generate gen_inflate.go. DO NOT EDIT. + +package flate + +import ( +`) + + for _, imp := range imports { + f.WriteString("\t\"" + imp + "\"\n") + } + f.WriteString(")\n\n") + + template := ` + +// Decode a single Huffman block from f. +// hl and hd are the Huffman states for the lit/length values +// and the distance values, respectively. If hd == nil, using the +// fixed distance encoding associated with fixed Huffman blocks. +func (f *decompressor) $FUNCNAME$() { + const ( + stateInit = iota // Zero value must be stateInit + stateDict + ) + fr := f.r.($TYPE$) + moreBits := func() error { + c, err := fr.ReadByte() + if err != nil { + return noEOF(err) + } + f.roffset++ + f.b |= uint32(c) << f.nb + f.nb += 8 + return nil + } + + switch f.stepState { + case stateInit: + goto readLiteral + case stateDict: + goto copyHistory + } + +readLiteral: + // Read literal and/or (length, distance) according to RFC section 3.2.3. + { + var v int + { + // Inlined v, err := f.huffSym(f.hl) + // Since a huffmanDecoder can be empty or be composed of a degenerate tree + // with single element, huffSym must error on these two edge cases. In both + // cases, the chunks slice will be 0 for the invalid sequence, leading it + // satisfy the n == 0 check below. + n := uint(f.hl.maxRead) + // Optimization. Compiler isn't smart enough to keep f.b,f.nb in registers, + // but is smart enough to keep local variables in registers, so use nb and b, + // inline call to moreBits and reassign b,nb back to f on return. + nb, b := f.nb, f.b + for { + for nb < n { + c, err := fr.ReadByte() + if err != nil { + f.b = b + f.nb = nb + f.err = noEOF(err) + return + } + f.roffset++ + b |= uint32(c) << (nb & 31) + nb += 8 + } + chunk := f.hl.chunks[b&(huffmanNumChunks-1)] + n = uint(chunk & huffmanCountMask) + if n > huffmanChunkBits { + chunk = f.hl.links[chunk>>huffmanValueShift][(b>>huffmanChunkBits)&f.hl.linkMask] + n = uint(chunk & huffmanCountMask) + } + if n <= nb { + if n == 0 { + f.b = b + f.nb = nb + if debugDecode { + fmt.Println("huffsym: n==0") + } + f.err = CorruptInputError(f.roffset) + return + } + f.b = b >> (n & 31) + f.nb = nb - n + v = int(chunk >> huffmanValueShift) + break + } + } + } + + var n uint // number of bits extra + var length int + var err error + switch { + case v < 256: + f.dict.writeByte(byte(v)) + if f.dict.availWrite() == 0 { + f.toRead = f.dict.readFlush() + f.step = (*decompressor).$FUNCNAME$ + f.stepState = stateInit + return + } + goto readLiteral + case v == 256: + f.finishBlock() + return + // otherwise, reference to older data + case v < 265: + length = v - (257 - 3) + n = 0 + case v < 269: + length = v*2 - (265*2 - 11) + n = 1 + case v < 273: + length = v*4 - (269*4 - 19) + n = 2 + case v < 277: + length = v*8 - (273*8 - 35) + n = 3 + case v < 281: + length = v*16 - (277*16 - 67) + n = 4 + case v < 285: + length = v*32 - (281*32 - 131) + n = 5 + case v < maxNumLit: + length = 258 + n = 0 + default: + if debugDecode { + fmt.Println(v, ">= maxNumLit") + } + f.err = CorruptInputError(f.roffset) + return + } + if n > 0 { + for f.nb < n { + if err = moreBits(); err != nil { + if debugDecode { + fmt.Println("morebits n>0:", err) + } + f.err = err + return + } + } + length += int(f.b & uint32(1<>= n + f.nb -= n + } + + var dist int + if f.hd == nil { + for f.nb < 5 { + if err = moreBits(); err != nil { + if debugDecode { + fmt.Println("morebits f.nb<5:", err) + } + f.err = err + return + } + } + dist = int(bits.Reverse8(uint8(f.b & 0x1F << 3))) + f.b >>= 5 + f.nb -= 5 + } else { + if dist, err = f.huffSym(f.hd); err != nil { + if debugDecode { + fmt.Println("huffsym:", err) + } + f.err = err + return + } + } + + switch { + case dist < 4: + dist++ + case dist < maxNumDist: + nb := uint(dist-2) >> 1 + // have 1 bit in bottom of dist, need nb more. + extra := (dist & 1) << nb + for f.nb < nb { + if err = moreBits(); err != nil { + if debugDecode { + fmt.Println("morebits f.nb>= nb + f.nb -= nb + dist = 1<<(nb+1) + 1 + extra + default: + if debugDecode { + fmt.Println("dist too big:", dist, maxNumDist) + } + f.err = CorruptInputError(f.roffset) + return + } + + // No check on length; encoding can be prescient. + if dist > f.dict.histSize() { + if debugDecode { + fmt.Println("dist > f.dict.histSize():", dist, f.dict.histSize()) + } + f.err = CorruptInputError(f.roffset) + return + } + + f.copyLen, f.copyDist = length, dist + goto copyHistory + } + +copyHistory: + // Perform a backwards copy according to RFC section 3.2.3. + { + cnt := f.dict.tryWriteCopy(f.copyDist, f.copyLen) + if cnt == 0 { + cnt = f.dict.writeCopy(f.copyDist, f.copyLen) + } + f.copyLen -= cnt + + if f.dict.availWrite() == 0 || f.copyLen > 0 { + f.toRead = f.dict.readFlush() + f.step = (*decompressor).$FUNCNAME$ // We need to continue this work + f.stepState = stateDict + return + } + goto readLiteral + } +} + +` + for i, t := range types { + s := strings.Replace(template, "$FUNCNAME$", "huffman"+names[i], -1) + s = strings.Replace(s, "$TYPE$", t, -1) + f.WriteString(s) + } + f.WriteString("func (f *decompressor) huffmanBlockDecoder() func() {\n") + f.WriteString("\tswitch f.r.(type) {\n") + for i, t := range types { + f.WriteString("\t\tcase " + t + ":\n") + f.WriteString("\t\t\treturn f.huffman" + names[i] + "\n") + } + f.WriteString("\t\tdefault:\n") + f.WriteString("\t\t\treturn f.huffmanBlockGeneric") + f.WriteString("\t}\n}\n") +} diff --git a/github.com/klauspost/compress/flate/huffman_bit_writer.go b/github.com/klauspost/compress/flate/huffman_bit_writer.go new file mode 100644 index 0000000..53fe1d0 --- /dev/null +++ b/github.com/klauspost/compress/flate/huffman_bit_writer.go @@ -0,0 +1,911 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package flate + +import ( + "io" +) + +const ( + // The largest offset code. + offsetCodeCount = 30 + + // The special code used to mark the end of a block. + endBlockMarker = 256 + + // The first length code. + lengthCodesStart = 257 + + // The number of codegen codes. + codegenCodeCount = 19 + badCode = 255 + + // bufferFlushSize indicates the buffer size + // after which bytes are flushed to the writer. + // Should preferably be a multiple of 6, since + // we accumulate 6 bytes between writes to the buffer. + bufferFlushSize = 240 + + // bufferSize is the actual output byte buffer size. + // It must have additional headroom for a flush + // which can contain up to 8 bytes. + bufferSize = bufferFlushSize + 8 +) + +// The number of extra bits needed by length code X - LENGTH_CODES_START. +var lengthExtraBits = [32]int8{ + /* 257 */ 0, 0, 0, + /* 260 */ 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, + /* 270 */ 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, + /* 280 */ 4, 5, 5, 5, 5, 0, +} + +// The length indicated by length code X - LENGTH_CODES_START. +var lengthBase = [32]uint8{ + 0, 1, 2, 3, 4, 5, 6, 7, 8, 10, + 12, 14, 16, 20, 24, 28, 32, 40, 48, 56, + 64, 80, 96, 112, 128, 160, 192, 224, 255, +} + +// offset code word extra bits. +var offsetExtraBits = [64]int8{ + 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, + 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, + 9, 9, 10, 10, 11, 11, 12, 12, 13, 13, + /* extended window */ + 14, 14, 15, 15, 16, 16, 17, 17, 18, 18, 19, 19, 20, 20, +} + +var offsetBase = [64]uint32{ + /* normal deflate */ + 0x000000, 0x000001, 0x000002, 0x000003, 0x000004, + 0x000006, 0x000008, 0x00000c, 0x000010, 0x000018, + 0x000020, 0x000030, 0x000040, 0x000060, 0x000080, + 0x0000c0, 0x000100, 0x000180, 0x000200, 0x000300, + 0x000400, 0x000600, 0x000800, 0x000c00, 0x001000, + 0x001800, 0x002000, 0x003000, 0x004000, 0x006000, + + /* extended window */ + 0x008000, 0x00c000, 0x010000, 0x018000, 0x020000, + 0x030000, 0x040000, 0x060000, 0x080000, 0x0c0000, + 0x100000, 0x180000, 0x200000, 0x300000, +} + +// The odd order in which the codegen code sizes are written. +var codegenOrder = []uint32{16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15} + +type huffmanBitWriter struct { + // writer is the underlying writer. + // Do not use it directly; use the write method, which ensures + // that Write errors are sticky. + writer io.Writer + + // Data waiting to be written is bytes[0:nbytes] + // and then the low nbits of bits. + bits uint64 + nbits uint16 + nbytes uint8 + literalEncoding *huffmanEncoder + offsetEncoding *huffmanEncoder + codegenEncoding *huffmanEncoder + err error + lastHeader int + // Set between 0 (reused block can be up to 2x the size) + logNewTablePenalty uint + lastHuffMan bool + bytes [256]byte + literalFreq [lengthCodesStart + 32]uint16 + offsetFreq [32]uint16 + codegenFreq [codegenCodeCount]uint16 + + // codegen must have an extra space for the final symbol. + codegen [literalCount + offsetCodeCount + 1]uint8 +} + +// Huffman reuse. +// +// The huffmanBitWriter supports reusing huffman tables and thereby combining block sections. +// +// This is controlled by several variables: +// +// If lastHeader is non-zero the Huffman table can be reused. +// This also indicates that a Huffman table has been generated that can output all +// possible symbols. +// It also indicates that an EOB has not yet been emitted, so if a new tabel is generated +// an EOB with the previous table must be written. +// +// If lastHuffMan is set, a table for outputting literals has been generated and offsets are invalid. +// +// An incoming block estimates the output size of a new table using a 'fresh' by calculating the +// optimal size and adding a penalty in 'logNewTablePenalty'. +// A Huffman table is not optimal, which is why we add a penalty, and generating a new table +// is slower both for compression and decompression. + +func newHuffmanBitWriter(w io.Writer) *huffmanBitWriter { + return &huffmanBitWriter{ + writer: w, + literalEncoding: newHuffmanEncoder(literalCount), + codegenEncoding: newHuffmanEncoder(codegenCodeCount), + offsetEncoding: newHuffmanEncoder(offsetCodeCount), + } +} + +func (w *huffmanBitWriter) reset(writer io.Writer) { + w.writer = writer + w.bits, w.nbits, w.nbytes, w.err = 0, 0, 0, nil + w.lastHeader = 0 + w.lastHuffMan = false +} + +func (w *huffmanBitWriter) canReuse(t *tokens) (offsets, lits bool) { + offsets, lits = true, true + a := t.offHist[:offsetCodeCount] + b := w.offsetFreq[:len(a)] + for i := range a { + if b[i] == 0 && a[i] != 0 { + offsets = false + break + } + } + + a = t.extraHist[:literalCount-256] + b = w.literalFreq[256:literalCount] + b = b[:len(a)] + for i := range a { + if b[i] == 0 && a[i] != 0 { + lits = false + break + } + } + if lits { + a = t.litHist[:] + b = w.literalFreq[:len(a)] + for i := range a { + if b[i] == 0 && a[i] != 0 { + lits = false + break + } + } + } + return +} + +func (w *huffmanBitWriter) flush() { + if w.err != nil { + w.nbits = 0 + return + } + if w.lastHeader > 0 { + // We owe an EOB + w.writeCode(w.literalEncoding.codes[endBlockMarker]) + w.lastHeader = 0 + } + n := w.nbytes + for w.nbits != 0 { + w.bytes[n] = byte(w.bits) + w.bits >>= 8 + if w.nbits > 8 { // Avoid underflow + w.nbits -= 8 + } else { + w.nbits = 0 + } + n++ + } + w.bits = 0 + w.write(w.bytes[:n]) + w.nbytes = 0 +} + +func (w *huffmanBitWriter) write(b []byte) { + if w.err != nil { + return + } + _, w.err = w.writer.Write(b) +} + +func (w *huffmanBitWriter) writeBits(b int32, nb uint16) { + w.bits |= uint64(b) << (w.nbits & 63) + w.nbits += nb + if w.nbits >= 48 { + w.writeOutBits() + } +} + +func (w *huffmanBitWriter) writeBytes(bytes []byte) { + if w.err != nil { + return + } + n := w.nbytes + if w.nbits&7 != 0 { + w.err = InternalError("writeBytes with unfinished bits") + return + } + for w.nbits != 0 { + w.bytes[n] = byte(w.bits) + w.bits >>= 8 + w.nbits -= 8 + n++ + } + if n != 0 { + w.write(w.bytes[:n]) + } + w.nbytes = 0 + w.write(bytes) +} + +// RFC 1951 3.2.7 specifies a special run-length encoding for specifying +// the literal and offset lengths arrays (which are concatenated into a single +// array). This method generates that run-length encoding. +// +// The result is written into the codegen array, and the frequencies +// of each code is written into the codegenFreq array. +// Codes 0-15 are single byte codes. Codes 16-18 are followed by additional +// information. Code badCode is an end marker +// +// numLiterals The number of literals in literalEncoding +// numOffsets The number of offsets in offsetEncoding +// litenc, offenc The literal and offset encoder to use +func (w *huffmanBitWriter) generateCodegen(numLiterals int, numOffsets int, litEnc, offEnc *huffmanEncoder) { + for i := range w.codegenFreq { + w.codegenFreq[i] = 0 + } + // Note that we are using codegen both as a temporary variable for holding + // a copy of the frequencies, and as the place where we put the result. + // This is fine because the output is always shorter than the input used + // so far. + codegen := w.codegen[:] // cache + // Copy the concatenated code sizes to codegen. Put a marker at the end. + cgnl := codegen[:numLiterals] + for i := range cgnl { + cgnl[i] = uint8(litEnc.codes[i].len) + } + + cgnl = codegen[numLiterals : numLiterals+numOffsets] + for i := range cgnl { + cgnl[i] = uint8(offEnc.codes[i].len) + } + codegen[numLiterals+numOffsets] = badCode + + size := codegen[0] + count := 1 + outIndex := 0 + for inIndex := 1; size != badCode; inIndex++ { + // INVARIANT: We have seen "count" copies of size that have not yet + // had output generated for them. + nextSize := codegen[inIndex] + if nextSize == size { + count++ + continue + } + // We need to generate codegen indicating "count" of size. + if size != 0 { + codegen[outIndex] = size + outIndex++ + w.codegenFreq[size]++ + count-- + for count >= 3 { + n := 6 + if n > count { + n = count + } + codegen[outIndex] = 16 + outIndex++ + codegen[outIndex] = uint8(n - 3) + outIndex++ + w.codegenFreq[16]++ + count -= n + } + } else { + for count >= 11 { + n := 138 + if n > count { + n = count + } + codegen[outIndex] = 18 + outIndex++ + codegen[outIndex] = uint8(n - 11) + outIndex++ + w.codegenFreq[18]++ + count -= n + } + if count >= 3 { + // count >= 3 && count <= 10 + codegen[outIndex] = 17 + outIndex++ + codegen[outIndex] = uint8(count - 3) + outIndex++ + w.codegenFreq[17]++ + count = 0 + } + } + count-- + for ; count >= 0; count-- { + codegen[outIndex] = size + outIndex++ + w.codegenFreq[size]++ + } + // Set up invariant for next time through the loop. + size = nextSize + count = 1 + } + // Marker indicating the end of the codegen. + codegen[outIndex] = badCode +} + +func (w *huffmanBitWriter) codegens() int { + numCodegens := len(w.codegenFreq) + for numCodegens > 4 && w.codegenFreq[codegenOrder[numCodegens-1]] == 0 { + numCodegens-- + } + return numCodegens +} + +func (w *huffmanBitWriter) headerSize() (size, numCodegens int) { + numCodegens = len(w.codegenFreq) + for numCodegens > 4 && w.codegenFreq[codegenOrder[numCodegens-1]] == 0 { + numCodegens-- + } + return 3 + 5 + 5 + 4 + (3 * numCodegens) + + w.codegenEncoding.bitLength(w.codegenFreq[:]) + + int(w.codegenFreq[16])*2 + + int(w.codegenFreq[17])*3 + + int(w.codegenFreq[18])*7, numCodegens +} + +// dynamicSize returns the size of dynamically encoded data in bits. +func (w *huffmanBitWriter) dynamicReuseSize(litEnc, offEnc *huffmanEncoder) (size int) { + size = litEnc.bitLength(w.literalFreq[:]) + + offEnc.bitLength(w.offsetFreq[:]) + return size +} + +// dynamicSize returns the size of dynamically encoded data in bits. +func (w *huffmanBitWriter) dynamicSize(litEnc, offEnc *huffmanEncoder, extraBits int) (size, numCodegens int) { + header, numCodegens := w.headerSize() + size = header + + litEnc.bitLength(w.literalFreq[:]) + + offEnc.bitLength(w.offsetFreq[:]) + + extraBits + return size, numCodegens +} + +// extraBitSize will return the number of bits that will be written +// as "extra" bits on matches. +func (w *huffmanBitWriter) extraBitSize() int { + total := 0 + for i, n := range w.literalFreq[257:literalCount] { + total += int(n) * int(lengthExtraBits[i&31]) + } + for i, n := range w.offsetFreq[:offsetCodeCount] { + total += int(n) * int(offsetExtraBits[i&31]) + } + return total +} + +// fixedSize returns the size of dynamically encoded data in bits. +func (w *huffmanBitWriter) fixedSize(extraBits int) int { + return 3 + + fixedLiteralEncoding.bitLength(w.literalFreq[:]) + + fixedOffsetEncoding.bitLength(w.offsetFreq[:]) + + extraBits +} + +// storedSize calculates the stored size, including header. +// The function returns the size in bits and whether the block +// fits inside a single block. +func (w *huffmanBitWriter) storedSize(in []byte) (int, bool) { + if in == nil { + return 0, false + } + if len(in) <= maxStoreBlockSize { + return (len(in) + 5) * 8, true + } + return 0, false +} + +func (w *huffmanBitWriter) writeCode(c hcode) { + // The function does not get inlined if we "& 63" the shift. + w.bits |= uint64(c.code) << w.nbits + w.nbits += c.len + if w.nbits >= 48 { + w.writeOutBits() + } +} + +// writeOutBits will write bits to the buffer. +func (w *huffmanBitWriter) writeOutBits() { + bits := w.bits + w.bits >>= 48 + w.nbits -= 48 + n := w.nbytes + w.bytes[n] = byte(bits) + w.bytes[n+1] = byte(bits >> 8) + w.bytes[n+2] = byte(bits >> 16) + w.bytes[n+3] = byte(bits >> 24) + w.bytes[n+4] = byte(bits >> 32) + w.bytes[n+5] = byte(bits >> 40) + n += 6 + if n >= bufferFlushSize { + if w.err != nil { + n = 0 + return + } + w.write(w.bytes[:n]) + n = 0 + } + w.nbytes = n +} + +// Write the header of a dynamic Huffman block to the output stream. +// +// numLiterals The number of literals specified in codegen +// numOffsets The number of offsets specified in codegen +// numCodegens The number of codegens used in codegen +func (w *huffmanBitWriter) writeDynamicHeader(numLiterals int, numOffsets int, numCodegens int, isEof bool) { + if w.err != nil { + return + } + var firstBits int32 = 4 + if isEof { + firstBits = 5 + } + w.writeBits(firstBits, 3) + w.writeBits(int32(numLiterals-257), 5) + w.writeBits(int32(numOffsets-1), 5) + w.writeBits(int32(numCodegens-4), 4) + + for i := 0; i < numCodegens; i++ { + value := uint(w.codegenEncoding.codes[codegenOrder[i]].len) + w.writeBits(int32(value), 3) + } + + i := 0 + for { + var codeWord = uint32(w.codegen[i]) + i++ + if codeWord == badCode { + break + } + w.writeCode(w.codegenEncoding.codes[codeWord]) + + switch codeWord { + case 16: + w.writeBits(int32(w.codegen[i]), 2) + i++ + case 17: + w.writeBits(int32(w.codegen[i]), 3) + i++ + case 18: + w.writeBits(int32(w.codegen[i]), 7) + i++ + } + } +} + +// writeStoredHeader will write a stored header. +// If the stored block is only used for EOF, +// it is replaced with a fixed huffman block. +func (w *huffmanBitWriter) writeStoredHeader(length int, isEof bool) { + if w.err != nil { + return + } + if w.lastHeader > 0 { + // We owe an EOB + w.writeCode(w.literalEncoding.codes[endBlockMarker]) + w.lastHeader = 0 + } + + // To write EOF, use a fixed encoding block. 10 bits instead of 5 bytes. + if length == 0 && isEof { + w.writeFixedHeader(isEof) + // EOB: 7 bits, value: 0 + w.writeBits(0, 7) + w.flush() + return + } + + var flag int32 + if isEof { + flag = 1 + } + w.writeBits(flag, 3) + w.flush() + w.writeBits(int32(length), 16) + w.writeBits(int32(^uint16(length)), 16) +} + +func (w *huffmanBitWriter) writeFixedHeader(isEof bool) { + if w.err != nil { + return + } + if w.lastHeader > 0 { + // We owe an EOB + w.writeCode(w.literalEncoding.codes[endBlockMarker]) + w.lastHeader = 0 + } + + // Indicate that we are a fixed Huffman block + var value int32 = 2 + if isEof { + value = 3 + } + w.writeBits(value, 3) +} + +// writeBlock will write a block of tokens with the smallest encoding. +// The original input can be supplied, and if the huffman encoded data +// is larger than the original bytes, the data will be written as a +// stored block. +// If the input is nil, the tokens will always be Huffman encoded. +func (w *huffmanBitWriter) writeBlock(tokens *tokens, eof bool, input []byte) { + if w.err != nil { + return + } + + tokens.AddEOB() + if w.lastHeader > 0 { + // We owe an EOB + w.writeCode(w.literalEncoding.codes[endBlockMarker]) + w.lastHeader = 0 + } + numLiterals, numOffsets := w.indexTokens(tokens, false) + w.generate(tokens) + var extraBits int + storedSize, storable := w.storedSize(input) + if storable { + extraBits = w.extraBitSize() + } + + // Figure out smallest code. + // Fixed Huffman baseline. + var literalEncoding = fixedLiteralEncoding + var offsetEncoding = fixedOffsetEncoding + var size = w.fixedSize(extraBits) + + // Dynamic Huffman? + var numCodegens int + + // Generate codegen and codegenFrequencies, which indicates how to encode + // the literalEncoding and the offsetEncoding. + w.generateCodegen(numLiterals, numOffsets, w.literalEncoding, w.offsetEncoding) + w.codegenEncoding.generate(w.codegenFreq[:], 7) + dynamicSize, numCodegens := w.dynamicSize(w.literalEncoding, w.offsetEncoding, extraBits) + + if dynamicSize < size { + size = dynamicSize + literalEncoding = w.literalEncoding + offsetEncoding = w.offsetEncoding + } + + // Stored bytes? + if storable && storedSize < size { + w.writeStoredHeader(len(input), eof) + w.writeBytes(input) + return + } + + // Huffman. + if literalEncoding == fixedLiteralEncoding { + w.writeFixedHeader(eof) + } else { + w.writeDynamicHeader(numLiterals, numOffsets, numCodegens, eof) + } + + // Write the tokens. + w.writeTokens(tokens.Slice(), literalEncoding.codes, offsetEncoding.codes) +} + +// writeBlockDynamic encodes a block using a dynamic Huffman table. +// This should be used if the symbols used have a disproportionate +// histogram distribution. +// If input is supplied and the compression savings are below 1/16th of the +// input size the block is stored. +func (w *huffmanBitWriter) writeBlockDynamic(tokens *tokens, eof bool, input []byte, sync bool) { + if w.err != nil { + return + } + + sync = sync || eof + if sync { + tokens.AddEOB() + } + + // We cannot reuse pure huffman table, and must mark as EOF. + if (w.lastHuffMan || eof) && w.lastHeader > 0 { + // We will not try to reuse. + w.writeCode(w.literalEncoding.codes[endBlockMarker]) + w.lastHeader = 0 + w.lastHuffMan = false + } + if !sync { + tokens.Fill() + } + numLiterals, numOffsets := w.indexTokens(tokens, !sync) + + var size int + // Check if we should reuse. + if w.lastHeader > 0 { + // Estimate size for using a new table. + // Use the previous header size as the best estimate. + newSize := w.lastHeader + tokens.EstimatedBits() + newSize += newSize >> w.logNewTablePenalty + + // The estimated size is calculated as an optimal table. + // We add a penalty to make it more realistic and re-use a bit more. + reuseSize := w.dynamicReuseSize(w.literalEncoding, w.offsetEncoding) + w.extraBitSize() + + // Check if a new table is better. + if newSize < reuseSize { + // Write the EOB we owe. + w.writeCode(w.literalEncoding.codes[endBlockMarker]) + size = newSize + w.lastHeader = 0 + } else { + size = reuseSize + } + // Check if we get a reasonable size decrease. + if ssize, storable := w.storedSize(input); storable && ssize < (size+size>>4) { + w.writeStoredHeader(len(input), eof) + w.writeBytes(input) + w.lastHeader = 0 + return + } + } + + // We want a new block/table + if w.lastHeader == 0 { + w.generate(tokens) + // Generate codegen and codegenFrequencies, which indicates how to encode + // the literalEncoding and the offsetEncoding. + w.generateCodegen(numLiterals, numOffsets, w.literalEncoding, w.offsetEncoding) + w.codegenEncoding.generate(w.codegenFreq[:], 7) + var numCodegens int + size, numCodegens = w.dynamicSize(w.literalEncoding, w.offsetEncoding, w.extraBitSize()) + // Store bytes, if we don't get a reasonable improvement. + if ssize, storable := w.storedSize(input); storable && ssize < (size+size>>4) { + w.writeStoredHeader(len(input), eof) + w.writeBytes(input) + w.lastHeader = 0 + return + } + + // Write Huffman table. + w.writeDynamicHeader(numLiterals, numOffsets, numCodegens, eof) + w.lastHeader, _ = w.headerSize() + w.lastHuffMan = false + } + + if sync { + w.lastHeader = 0 + } + // Write the tokens. + w.writeTokens(tokens.Slice(), w.literalEncoding.codes, w.offsetEncoding.codes) +} + +// indexTokens indexes a slice of tokens, and updates +// literalFreq and offsetFreq, and generates literalEncoding +// and offsetEncoding. +// The number of literal and offset tokens is returned. +func (w *huffmanBitWriter) indexTokens(t *tokens, filled bool) (numLiterals, numOffsets int) { + copy(w.literalFreq[:], t.litHist[:]) + copy(w.literalFreq[256:], t.extraHist[:]) + copy(w.offsetFreq[:], t.offHist[:offsetCodeCount]) + + if t.n == 0 { + return + } + if filled { + return maxNumLit, maxNumDist + } + // get the number of literals + numLiterals = len(w.literalFreq) + for w.literalFreq[numLiterals-1] == 0 { + numLiterals-- + } + // get the number of offsets + numOffsets = len(w.offsetFreq) + for numOffsets > 0 && w.offsetFreq[numOffsets-1] == 0 { + numOffsets-- + } + if numOffsets == 0 { + // We haven't found a single match. If we want to go with the dynamic encoding, + // we should count at least one offset to be sure that the offset huffman tree could be encoded. + w.offsetFreq[0] = 1 + numOffsets = 1 + } + return +} + +func (w *huffmanBitWriter) generate(t *tokens) { + w.literalEncoding.generate(w.literalFreq[:literalCount], 15) + w.offsetEncoding.generate(w.offsetFreq[:offsetCodeCount], 15) +} + +// writeTokens writes a slice of tokens to the output. +// codes for literal and offset encoding must be supplied. +func (w *huffmanBitWriter) writeTokens(tokens []token, leCodes, oeCodes []hcode) { + if w.err != nil { + return + } + if len(tokens) == 0 { + return + } + + // Only last token should be endBlockMarker. + var deferEOB bool + if tokens[len(tokens)-1] == endBlockMarker { + tokens = tokens[:len(tokens)-1] + deferEOB = true + } + + // Create slices up to the next power of two to avoid bounds checks. + lits := leCodes[:256] + offs := oeCodes[:32] + lengths := leCodes[lengthCodesStart:] + lengths = lengths[:32] + for _, t := range tokens { + if t < matchType { + w.writeCode(lits[t.literal()]) + continue + } + + // Write the length + length := t.length() + lengthCode := lengthCode(length) + if false { + w.writeCode(lengths[lengthCode&31]) + } else { + // inlined + c := lengths[lengthCode&31] + w.bits |= uint64(c.code) << (w.nbits & 63) + w.nbits += c.len + if w.nbits >= 48 { + w.writeOutBits() + } + } + + extraLengthBits := uint16(lengthExtraBits[lengthCode&31]) + if extraLengthBits > 0 { + extraLength := int32(length - lengthBase[lengthCode&31]) + w.writeBits(extraLength, extraLengthBits) + } + // Write the offset + offset := t.offset() + offsetCode := offsetCode(offset) + if false { + w.writeCode(offs[offsetCode&31]) + } else { + // inlined + c := offs[offsetCode&31] + w.bits |= uint64(c.code) << (w.nbits & 63) + w.nbits += c.len + if w.nbits >= 48 { + w.writeOutBits() + } + } + extraOffsetBits := uint16(offsetExtraBits[offsetCode&63]) + if extraOffsetBits > 0 { + extraOffset := int32(offset - offsetBase[offsetCode&63]) + w.writeBits(extraOffset, extraOffsetBits) + } + } + if deferEOB { + w.writeCode(leCodes[endBlockMarker]) + } +} + +// huffOffset is a static offset encoder used for huffman only encoding. +// It can be reused since we will not be encoding offset values. +var huffOffset *huffmanEncoder + +func init() { + w := newHuffmanBitWriter(nil) + w.offsetFreq[0] = 1 + huffOffset = newHuffmanEncoder(offsetCodeCount) + huffOffset.generate(w.offsetFreq[:offsetCodeCount], 15) +} + +// writeBlockHuff encodes a block of bytes as either +// Huffman encoded literals or uncompressed bytes if the +// results only gains very little from compression. +func (w *huffmanBitWriter) writeBlockHuff(eof bool, input []byte, sync bool) { + if w.err != nil { + return + } + + // Clear histogram + for i := range w.literalFreq[:] { + w.literalFreq[i] = 0 + } + if !w.lastHuffMan { + for i := range w.offsetFreq[:] { + w.offsetFreq[i] = 0 + } + } + + // Add everything as literals + // We have to estimate the header size. + // Assume header is around 70 bytes: + // https://stackoverflow.com/a/25454430 + const guessHeaderSizeBits = 70 * 8 + estBits, estExtra := histogramSize(input, w.literalFreq[:], !eof && !sync) + estBits += w.lastHeader + 15 + if w.lastHeader == 0 { + estBits += guessHeaderSizeBits + } + estBits += estBits >> w.logNewTablePenalty + + // Store bytes, if we don't get a reasonable improvement. + ssize, storable := w.storedSize(input) + if storable && ssize < estBits { + w.writeStoredHeader(len(input), eof) + w.writeBytes(input) + return + } + + if w.lastHeader > 0 { + reuseSize := w.literalEncoding.bitLength(w.literalFreq[:256]) + estBits += estExtra + + if estBits < reuseSize { + // We owe an EOB + w.writeCode(w.literalEncoding.codes[endBlockMarker]) + w.lastHeader = 0 + } + } + + const numLiterals = endBlockMarker + 1 + const numOffsets = 1 + if w.lastHeader == 0 { + w.literalFreq[endBlockMarker] = 1 + w.literalEncoding.generate(w.literalFreq[:numLiterals], 15) + + // Generate codegen and codegenFrequencies, which indicates how to encode + // the literalEncoding and the offsetEncoding. + w.generateCodegen(numLiterals, numOffsets, w.literalEncoding, huffOffset) + w.codegenEncoding.generate(w.codegenFreq[:], 7) + numCodegens := w.codegens() + + // Huffman. + w.writeDynamicHeader(numLiterals, numOffsets, numCodegens, eof) + w.lastHuffMan = true + w.lastHeader, _ = w.headerSize() + } + + encoding := w.literalEncoding.codes[:257] + for _, t := range input { + // Bitwriting inlined, ~30% speedup + c := encoding[t] + w.bits |= uint64(c.code) << ((w.nbits) & 63) + w.nbits += c.len + if w.nbits >= 48 { + bits := w.bits + w.bits >>= 48 + w.nbits -= 48 + n := w.nbytes + w.bytes[n] = byte(bits) + w.bytes[n+1] = byte(bits >> 8) + w.bytes[n+2] = byte(bits >> 16) + w.bytes[n+3] = byte(bits >> 24) + w.bytes[n+4] = byte(bits >> 32) + w.bytes[n+5] = byte(bits >> 40) + n += 6 + if n >= bufferFlushSize { + if w.err != nil { + n = 0 + return + } + w.write(w.bytes[:n]) + n = 0 + } + w.nbytes = n + } + } + if eof || sync { + w.writeCode(encoding[endBlockMarker]) + w.lastHeader = 0 + w.lastHuffMan = false + } +} diff --git a/github.com/klauspost/compress/flate/huffman_bit_writer_test.go b/github.com/klauspost/compress/flate/huffman_bit_writer_test.go new file mode 100644 index 0000000..60aef15 --- /dev/null +++ b/github.com/klauspost/compress/flate/huffman_bit_writer_test.go @@ -0,0 +1,382 @@ +// Copyright 2016 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package flate + +import ( + "bytes" + "flag" + "fmt" + "io/ioutil" + "os" + "path/filepath" + "strings" + "testing" +) + +var update = flag.Bool("update", false, "update reference files") + +// TestBlockHuff tests huffman encoding against reference files +// to detect possible regressions. +// If encoding/bit allocation changes you can regenerate these files +// by using the -update flag. +func TestBlockHuff(t *testing.T) { + // determine input files + match, err := filepath.Glob("testdata/huffman-*.in") + if err != nil { + t.Fatal(err) + } + + for _, in := range match { + out := in // for files where input and output are identical + if strings.HasSuffix(in, ".in") { + out = in[:len(in)-len(".in")] + ".golden" + } + t.Run(in, func(t *testing.T) { + testBlockHuff(t, in, out) + }) + } +} + +func testBlockHuff(t *testing.T, in, out string) { + all, err := ioutil.ReadFile(in) + if err != nil { + t.Error(err) + return + } + var buf bytes.Buffer + bw := newHuffmanBitWriter(&buf) + bw.logNewTablePenalty = 8 + bw.writeBlockHuff(false, all, false) + bw.flush() + got := buf.Bytes() + + want, err := ioutil.ReadFile(out) + if err != nil && !*update { + t.Error(err) + return + } + + t.Logf("Testing %q", in) + if !bytes.Equal(got, want) { + if *update { + if in != out { + t.Logf("Updating %q", out) + if err := ioutil.WriteFile(out, got, 0666); err != nil { + t.Error(err) + } + return + } + // in == out: don't accidentally destroy input + t.Errorf("WARNING: -update did not rewrite input file %s", in) + } + + t.Errorf("%q != %q (see %q)", in, out, in+".got") + if err := ioutil.WriteFile(in+".got", got, 0666); err != nil { + t.Error(err) + } + return + } + t.Log("Output ok") + + // Test if the writer produces the same output after reset. + buf.Reset() + bw.reset(&buf) + bw.writeBlockHuff(false, all, false) + bw.flush() + got = buf.Bytes() + if !bytes.Equal(got, want) { + t.Errorf("after reset %q != %q (see %q)", in, out, in+".reset.got") + if err := ioutil.WriteFile(in+".reset.got", got, 0666); err != nil { + t.Error(err) + } + return + } + t.Log("Reset ok") + testWriterEOF(t, "huff", huffTest{input: in}, true) +} + +type huffTest struct { + tokens []token + input string // File name of input data matching the tokens. + want string // File name of data with the expected output with input available. + wantNoInput string // File name of the expected output when no input is available. +} + +const ml = 0x7fc00000 // Maximum length token. Used to reduce the size of writeBlockTests + +var writeBlockTests = []huffTest{ + { + input: "testdata/huffman-null-max.in", + want: "testdata/huffman-null-max.%s.expect", + wantNoInput: "testdata/huffman-null-max.%s.expect-noinput", + tokens: []token{0x0, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, 0x0, 0x0}, + }, + { + input: "testdata/huffman-pi.in", + want: "testdata/huffman-pi.%s.expect", + wantNoInput: "testdata/huffman-pi.%s.expect-noinput", + tokens: []token{0x33, 0x2e, 0x31, 0x34, 0x31, 0x35, 0x39, 0x32, 0x36, 0x35, 0x33, 0x35, 0x38, 0x39, 0x37, 0x39, 0x33, 0x32, 0x33, 0x38, 0x34, 0x36, 0x32, 0x36, 0x34, 0x33, 0x33, 0x38, 0x33, 0x32, 0x37, 0x39, 0x35, 0x30, 0x32, 0x38, 0x38, 0x34, 0x31, 0x39, 0x37, 0x31, 0x36, 0x39, 0x33, 0x39, 0x39, 0x33, 0x37, 0x35, 0x31, 0x30, 0x35, 0x38, 0x32, 0x30, 0x39, 0x37, 0x34, 0x39, 0x34, 0x34, 0x35, 0x39, 0x32, 0x33, 0x30, 0x37, 0x38, 0x31, 0x36, 0x34, 0x30, 0x36, 0x32, 0x38, 0x36, 0x32, 0x30, 0x38, 0x39, 0x39, 0x38, 0x36, 0x32, 0x38, 0x30, 0x33, 0x34, 0x38, 0x32, 0x35, 0x33, 0x34, 0x32, 0x31, 0x31, 0x37, 0x30, 0x36, 0x37, 0x39, 0x38, 0x32, 0x31, 0x34, 0x38, 0x30, 0x38, 0x36, 0x35, 0x31, 0x33, 0x32, 0x38, 0x32, 0x33, 0x30, 0x36, 0x36, 0x34, 0x37, 0x30, 0x39, 0x33, 0x38, 0x34, 0x34, 0x36, 0x30, 0x39, 0x35, 0x35, 0x30, 0x35, 0x38, 0x32, 0x32, 0x33, 0x31, 0x37, 0x32, 0x35, 0x33, 0x35, 0x39, 0x34, 0x30, 0x38, 0x31, 0x32, 0x38, 0x34, 0x38, 0x31, 0x31, 0x31, 0x37, 0x34, 0x4040007e, 0x34, 0x31, 0x30, 0x32, 0x37, 0x30, 0x31, 0x39, 0x33, 0x38, 0x35, 0x32, 0x31, 0x31, 0x30, 0x35, 0x35, 0x35, 0x39, 0x36, 0x34, 0x34, 0x36, 0x32, 0x32, 0x39, 0x34, 0x38, 0x39, 0x35, 0x34, 0x39, 0x33, 0x30, 0x33, 0x38, 0x31, 0x40400012, 0x32, 0x38, 0x38, 0x31, 0x30, 0x39, 0x37, 0x35, 0x36, 0x36, 0x35, 0x39, 0x33, 0x33, 0x34, 0x34, 0x36, 0x40400047, 0x37, 0x35, 0x36, 0x34, 0x38, 0x32, 0x33, 0x33, 0x37, 0x38, 0x36, 0x37, 0x38, 0x33, 0x31, 0x36, 0x35, 0x32, 0x37, 0x31, 0x32, 0x30, 0x31, 0x39, 0x30, 0x39, 0x31, 0x34, 0x4040001a, 0x35, 0x36, 0x36, 0x39, 0x32, 0x33, 0x34, 0x36, 0x404000b2, 0x36, 0x31, 0x30, 0x34, 0x35, 0x34, 0x33, 0x32, 0x36, 0x40400032, 0x31, 0x33, 0x33, 0x39, 0x33, 0x36, 0x30, 0x37, 0x32, 0x36, 0x30, 0x32, 0x34, 0x39, 0x31, 0x34, 0x31, 0x32, 0x37, 0x33, 0x37, 0x32, 0x34, 0x35, 0x38, 0x37, 0x30, 0x30, 0x36, 0x36, 0x30, 0x36, 0x33, 0x31, 0x35, 0x35, 0x38, 0x38, 0x31, 0x37, 0x34, 0x38, 0x38, 0x31, 0x35, 0x32, 0x30, 0x39, 0x32, 0x30, 0x39, 0x36, 0x32, 0x38, 0x32, 0x39, 0x32, 0x35, 0x34, 0x30, 0x39, 0x31, 0x37, 0x31, 0x35, 0x33, 0x36, 0x34, 0x33, 0x36, 0x37, 0x38, 0x39, 0x32, 0x35, 0x39, 0x30, 0x33, 0x36, 0x30, 0x30, 0x31, 0x31, 0x33, 0x33, 0x30, 0x35, 0x33, 0x30, 0x35, 0x34, 0x38, 0x38, 0x32, 0x30, 0x34, 0x36, 0x36, 0x35, 0x32, 0x31, 0x33, 0x38, 0x34, 0x31, 0x34, 0x36, 0x39, 0x35, 0x31, 0x39, 0x34, 0x31, 0x35, 0x31, 0x31, 0x36, 0x30, 0x39, 0x34, 0x33, 0x33, 0x30, 0x35, 0x37, 0x32, 0x37, 0x30, 0x33, 0x36, 0x35, 0x37, 0x35, 0x39, 0x35, 0x39, 0x31, 0x39, 0x35, 0x33, 0x30, 0x39, 0x32, 0x31, 0x38, 0x36, 0x31, 0x31, 0x37, 0x404000e9, 0x33, 0x32, 0x40400009, 0x39, 0x33, 0x31, 0x30, 0x35, 0x31, 0x31, 0x38, 0x35, 0x34, 0x38, 0x30, 0x37, 0x4040010e, 0x33, 0x37, 0x39, 0x39, 0x36, 0x32, 0x37, 0x34, 0x39, 0x35, 0x36, 0x37, 0x33, 0x35, 0x31, 0x38, 0x38, 0x35, 0x37, 0x35, 0x32, 0x37, 0x32, 0x34, 0x38, 0x39, 0x31, 0x32, 0x32, 0x37, 0x39, 0x33, 0x38, 0x31, 0x38, 0x33, 0x30, 0x31, 0x31, 0x39, 0x34, 0x39, 0x31, 0x32, 0x39, 0x38, 0x33, 0x33, 0x36, 0x37, 0x33, 0x33, 0x36, 0x32, 0x34, 0x34, 0x30, 0x36, 0x35, 0x36, 0x36, 0x34, 0x33, 0x30, 0x38, 0x36, 0x30, 0x32, 0x31, 0x33, 0x39, 0x34, 0x39, 0x34, 0x36, 0x33, 0x39, 0x35, 0x32, 0x32, 0x34, 0x37, 0x33, 0x37, 0x31, 0x39, 0x30, 0x37, 0x30, 0x32, 0x31, 0x37, 0x39, 0x38, 0x40800099, 0x37, 0x30, 0x32, 0x37, 0x37, 0x30, 0x35, 0x33, 0x39, 0x32, 0x31, 0x37, 0x31, 0x37, 0x36, 0x32, 0x39, 0x33, 0x31, 0x37, 0x36, 0x37, 0x35, 0x40800232, 0x37, 0x34, 0x38, 0x31, 0x40400006, 0x36, 0x36, 0x39, 0x34, 0x30, 0x404001e7, 0x30, 0x30, 0x30, 0x35, 0x36, 0x38, 0x31, 0x32, 0x37, 0x31, 0x34, 0x35, 0x32, 0x36, 0x33, 0x35, 0x36, 0x30, 0x38, 0x32, 0x37, 0x37, 0x38, 0x35, 0x37, 0x37, 0x31, 0x33, 0x34, 0x32, 0x37, 0x35, 0x37, 0x37, 0x38, 0x39, 0x36, 0x40400129, 0x33, 0x36, 0x33, 0x37, 0x31, 0x37, 0x38, 0x37, 0x32, 0x31, 0x34, 0x36, 0x38, 0x34, 0x34, 0x30, 0x39, 0x30, 0x31, 0x32, 0x32, 0x34, 0x39, 0x35, 0x33, 0x34, 0x33, 0x30, 0x31, 0x34, 0x36, 0x35, 0x34, 0x39, 0x35, 0x38, 0x35, 0x33, 0x37, 0x31, 0x30, 0x35, 0x30, 0x37, 0x39, 0x404000ca, 0x36, 0x40400153, 0x38, 0x39, 0x32, 0x33, 0x35, 0x34, 0x404001c9, 0x39, 0x35, 0x36, 0x31, 0x31, 0x32, 0x31, 0x32, 0x39, 0x30, 0x32, 0x31, 0x39, 0x36, 0x30, 0x38, 0x36, 0x34, 0x30, 0x33, 0x34, 0x34, 0x31, 0x38, 0x31, 0x35, 0x39, 0x38, 0x31, 0x33, 0x36, 0x32, 0x39, 0x37, 0x37, 0x34, 0x40400074, 0x30, 0x39, 0x39, 0x36, 0x30, 0x35, 0x31, 0x38, 0x37, 0x30, 0x37, 0x32, 0x31, 0x31, 0x33, 0x34, 0x39, 0x40800000, 0x38, 0x33, 0x37, 0x32, 0x39, 0x37, 0x38, 0x30, 0x34, 0x39, 0x39, 0x404002da, 0x39, 0x37, 0x33, 0x31, 0x37, 0x33, 0x32, 0x38, 0x4040018a, 0x36, 0x33, 0x31, 0x38, 0x35, 0x40400301, 0x404002e8, 0x34, 0x35, 0x35, 0x33, 0x34, 0x36, 0x39, 0x30, 0x38, 0x33, 0x30, 0x32, 0x36, 0x34, 0x32, 0x35, 0x32, 0x32, 0x33, 0x30, 0x404002e3, 0x40400267, 0x38, 0x35, 0x30, 0x33, 0x35, 0x32, 0x36, 0x31, 0x39, 0x33, 0x31, 0x31, 0x40400212, 0x31, 0x30, 0x31, 0x30, 0x30, 0x30, 0x33, 0x31, 0x33, 0x37, 0x38, 0x33, 0x38, 0x37, 0x35, 0x32, 0x38, 0x38, 0x36, 0x35, 0x38, 0x37, 0x35, 0x33, 0x33, 0x32, 0x30, 0x38, 0x33, 0x38, 0x31, 0x34, 0x32, 0x30, 0x36, 0x40400140, 0x4040012b, 0x31, 0x34, 0x37, 0x33, 0x30, 0x33, 0x35, 0x39, 0x4080032e, 0x39, 0x30, 0x34, 0x32, 0x38, 0x37, 0x35, 0x35, 0x34, 0x36, 0x38, 0x37, 0x33, 0x31, 0x31, 0x35, 0x39, 0x35, 0x40400355, 0x33, 0x38, 0x38, 0x32, 0x33, 0x35, 0x33, 0x37, 0x38, 0x37, 0x35, 0x4080037f, 0x39, 0x4040013a, 0x31, 0x40400148, 0x38, 0x30, 0x35, 0x33, 0x4040018a, 0x32, 0x32, 0x36, 0x38, 0x30, 0x36, 0x36, 0x31, 0x33, 0x30, 0x30, 0x31, 0x39, 0x32, 0x37, 0x38, 0x37, 0x36, 0x36, 0x31, 0x31, 0x31, 0x39, 0x35, 0x39, 0x40400237, 0x36, 0x40800124, 0x38, 0x39, 0x33, 0x38, 0x30, 0x39, 0x35, 0x32, 0x35, 0x37, 0x32, 0x30, 0x31, 0x30, 0x36, 0x35, 0x34, 0x38, 0x35, 0x38, 0x36, 0x33, 0x32, 0x37, 0x4040009a, 0x39, 0x33, 0x36, 0x31, 0x35, 0x33, 0x40400220, 0x4080015c, 0x32, 0x33, 0x30, 0x33, 0x30, 0x31, 0x39, 0x35, 0x32, 0x30, 0x33, 0x35, 0x33, 0x30, 0x31, 0x38, 0x35, 0x32, 0x40400171, 0x40400075, 0x33, 0x36, 0x32, 0x32, 0x35, 0x39, 0x39, 0x34, 0x31, 0x33, 0x40400254, 0x34, 0x39, 0x37, 0x32, 0x31, 0x37, 0x404000de, 0x33, 0x34, 0x37, 0x39, 0x31, 0x33, 0x31, 0x35, 0x31, 0x35, 0x35, 0x37, 0x34, 0x38, 0x35, 0x37, 0x32, 0x34, 0x32, 0x34, 0x35, 0x34, 0x31, 0x35, 0x30, 0x36, 0x39, 0x4040013f, 0x38, 0x32, 0x39, 0x35, 0x33, 0x33, 0x31, 0x31, 0x36, 0x38, 0x36, 0x31, 0x37, 0x32, 0x37, 0x38, 0x40400337, 0x39, 0x30, 0x37, 0x35, 0x30, 0x39, 0x4040010d, 0x37, 0x35, 0x34, 0x36, 0x33, 0x37, 0x34, 0x36, 0x34, 0x39, 0x33, 0x39, 0x33, 0x31, 0x39, 0x32, 0x35, 0x35, 0x30, 0x36, 0x30, 0x34, 0x30, 0x30, 0x39, 0x4040026b, 0x31, 0x36, 0x37, 0x31, 0x31, 0x33, 0x39, 0x30, 0x30, 0x39, 0x38, 0x40400335, 0x34, 0x30, 0x31, 0x32, 0x38, 0x35, 0x38, 0x33, 0x36, 0x31, 0x36, 0x30, 0x33, 0x35, 0x36, 0x33, 0x37, 0x30, 0x37, 0x36, 0x36, 0x30, 0x31, 0x30, 0x34, 0x40400172, 0x38, 0x31, 0x39, 0x34, 0x32, 0x39, 0x4080041e, 0x404000ef, 0x4040028b, 0x37, 0x38, 0x33, 0x37, 0x34, 0x404004a8, 0x38, 0x32, 0x35, 0x35, 0x33, 0x37, 0x40800209, 0x32, 0x36, 0x38, 0x4040002e, 0x34, 0x30, 0x34, 0x37, 0x404001d1, 0x34, 0x404004b5, 0x4040038d, 0x38, 0x34, 0x404003a8, 0x36, 0x40c0031f, 0x33, 0x33, 0x31, 0x33, 0x36, 0x37, 0x37, 0x30, 0x32, 0x38, 0x39, 0x38, 0x39, 0x31, 0x35, 0x32, 0x40400062, 0x35, 0x32, 0x31, 0x36, 0x32, 0x30, 0x35, 0x36, 0x39, 0x36, 0x40400411, 0x30, 0x35, 0x38, 0x40400477, 0x35, 0x40400498, 0x35, 0x31, 0x31, 0x40400209, 0x38, 0x32, 0x34, 0x33, 0x30, 0x30, 0x33, 0x35, 0x35, 0x38, 0x37, 0x36, 0x34, 0x30, 0x32, 0x34, 0x37, 0x34, 0x39, 0x36, 0x34, 0x37, 0x33, 0x32, 0x36, 0x33, 0x4040043e, 0x39, 0x39, 0x32, 0x4040044b, 0x34, 0x32, 0x36, 0x39, 0x40c002c5, 0x37, 0x404001d6, 0x34, 0x4040053d, 0x4040041d, 0x39, 0x33, 0x34, 0x31, 0x37, 0x404001ad, 0x31, 0x32, 0x4040002a, 0x34, 0x4040019e, 0x31, 0x35, 0x30, 0x33, 0x30, 0x32, 0x38, 0x36, 0x31, 0x38, 0x32, 0x39, 0x37, 0x34, 0x35, 0x35, 0x35, 0x37, 0x30, 0x36, 0x37, 0x34, 0x40400135, 0x35, 0x30, 0x35, 0x34, 0x39, 0x34, 0x35, 0x38, 0x404001c5, 0x39, 0x40400051, 0x35, 0x36, 0x404001ec, 0x37, 0x32, 0x31, 0x30, 0x37, 0x39, 0x40400159, 0x33, 0x30, 0x4040010a, 0x33, 0x32, 0x31, 0x31, 0x36, 0x35, 0x33, 0x34, 0x34, 0x39, 0x38, 0x37, 0x32, 0x30, 0x32, 0x37, 0x4040011b, 0x30, 0x32, 0x33, 0x36, 0x34, 0x4040022e, 0x35, 0x34, 0x39, 0x39, 0x31, 0x31, 0x39, 0x38, 0x40400418, 0x34, 0x4040011b, 0x35, 0x33, 0x35, 0x36, 0x36, 0x33, 0x36, 0x39, 0x40400450, 0x32, 0x36, 0x35, 0x404002e4, 0x37, 0x38, 0x36, 0x32, 0x35, 0x35, 0x31, 0x404003da, 0x31, 0x37, 0x35, 0x37, 0x34, 0x36, 0x37, 0x32, 0x38, 0x39, 0x30, 0x39, 0x37, 0x37, 0x37, 0x37, 0x40800453, 0x30, 0x30, 0x30, 0x404005fd, 0x37, 0x30, 0x404004df, 0x36, 0x404003e9, 0x34, 0x39, 0x31, 0x4040041e, 0x40400297, 0x32, 0x31, 0x34, 0x37, 0x37, 0x32, 0x33, 0x35, 0x30, 0x31, 0x34, 0x31, 0x34, 0x40400643, 0x33, 0x35, 0x36, 0x404004af, 0x31, 0x36, 0x31, 0x33, 0x36, 0x31, 0x31, 0x35, 0x37, 0x33, 0x35, 0x32, 0x35, 0x40400504, 0x33, 0x34, 0x4040005b, 0x31, 0x38, 0x4040047b, 0x38, 0x34, 0x404005e7, 0x33, 0x33, 0x32, 0x33, 0x39, 0x30, 0x37, 0x33, 0x39, 0x34, 0x31, 0x34, 0x33, 0x33, 0x33, 0x34, 0x35, 0x34, 0x37, 0x37, 0x36, 0x32, 0x34, 0x40400242, 0x32, 0x35, 0x31, 0x38, 0x39, 0x38, 0x33, 0x35, 0x36, 0x39, 0x34, 0x38, 0x35, 0x35, 0x36, 0x32, 0x30, 0x39, 0x39, 0x32, 0x31, 0x39, 0x32, 0x32, 0x32, 0x31, 0x38, 0x34, 0x32, 0x37, 0x4040023e, 0x32, 0x404000ba, 0x36, 0x38, 0x38, 0x37, 0x36, 0x37, 0x31, 0x37, 0x39, 0x30, 0x40400055, 0x30, 0x40800106, 0x36, 0x36, 0x404003e7, 0x38, 0x38, 0x36, 0x32, 0x37, 0x32, 0x404006dc, 0x31, 0x37, 0x38, 0x36, 0x30, 0x38, 0x35, 0x37, 0x40400073, 0x33, 0x408002fc, 0x37, 0x39, 0x37, 0x36, 0x36, 0x38, 0x31, 0x404002bd, 0x30, 0x30, 0x39, 0x35, 0x33, 0x38, 0x38, 0x40400638, 0x33, 0x404006a5, 0x30, 0x36, 0x38, 0x30, 0x30, 0x36, 0x34, 0x32, 0x32, 0x35, 0x31, 0x32, 0x35, 0x32, 0x4040057b, 0x37, 0x33, 0x39, 0x32, 0x40400297, 0x40400474, 0x34, 0x408006b3, 0x38, 0x36, 0x32, 0x36, 0x39, 0x34, 0x35, 0x404001e5, 0x34, 0x31, 0x39, 0x36, 0x35, 0x32, 0x38, 0x35, 0x30, 0x40400099, 0x4040039c, 0x31, 0x38, 0x36, 0x33, 0x404001be, 0x34, 0x40800154, 0x32, 0x30, 0x33, 0x39, 0x4040058b, 0x34, 0x35, 0x404002bc, 0x32, 0x33, 0x37, 0x4040042c, 0x36, 0x40400510, 0x35, 0x36, 0x40400638, 0x37, 0x31, 0x39, 0x31, 0x37, 0x32, 0x38, 0x40400171, 0x37, 0x36, 0x34, 0x36, 0x35, 0x37, 0x35, 0x37, 0x33, 0x39, 0x40400101, 0x33, 0x38, 0x39, 0x40400748, 0x38, 0x33, 0x32, 0x36, 0x34, 0x35, 0x39, 0x39, 0x35, 0x38, 0x404006a7, 0x30, 0x34, 0x37, 0x38, 0x404001de, 0x40400328, 0x39, 0x4040002d, 0x36, 0x34, 0x30, 0x37, 0x38, 0x39, 0x35, 0x31, 0x4040008e, 0x36, 0x38, 0x33, 0x4040012f, 0x32, 0x35, 0x39, 0x35, 0x37, 0x30, 0x40400468, 0x38, 0x32, 0x32, 0x404002c8, 0x32, 0x4040061b, 0x34, 0x30, 0x37, 0x37, 0x32, 0x36, 0x37, 0x31, 0x39, 0x34, 0x37, 0x38, 0x40400319, 0x38, 0x32, 0x36, 0x30, 0x31, 0x34, 0x37, 0x36, 0x39, 0x39, 0x30, 0x39, 0x404004e8, 0x30, 0x31, 0x33, 0x36, 0x33, 0x39, 0x34, 0x34, 0x33, 0x4040027f, 0x33, 0x30, 0x40400105, 0x32, 0x30, 0x33, 0x34, 0x39, 0x36, 0x32, 0x35, 0x32, 0x34, 0x35, 0x31, 0x37, 0x404003b5, 0x39, 0x36, 0x35, 0x31, 0x34, 0x33, 0x31, 0x34, 0x32, 0x39, 0x38, 0x30, 0x39, 0x31, 0x39, 0x30, 0x36, 0x35, 0x39, 0x32, 0x40400282, 0x37, 0x32, 0x32, 0x31, 0x36, 0x39, 0x36, 0x34, 0x36, 0x40400419, 0x4040007a, 0x35, 0x4040050e, 0x34, 0x40800565, 0x38, 0x40400559, 0x39, 0x37, 0x4040057b, 0x35, 0x34, 0x4040049d, 0x4040023e, 0x37, 0x4040065a, 0x38, 0x34, 0x36, 0x38, 0x31, 0x33, 0x4040008c, 0x36, 0x38, 0x33, 0x38, 0x36, 0x38, 0x39, 0x34, 0x32, 0x37, 0x37, 0x34, 0x31, 0x35, 0x35, 0x39, 0x39, 0x31, 0x38, 0x35, 0x4040005a, 0x32, 0x34, 0x35, 0x39, 0x35, 0x33, 0x39, 0x35, 0x39, 0x34, 0x33, 0x31, 0x404005b7, 0x37, 0x40400012, 0x36, 0x38, 0x30, 0x38, 0x34, 0x35, 0x404002e7, 0x37, 0x33, 0x4040081e, 0x39, 0x35, 0x38, 0x34, 0x38, 0x36, 0x35, 0x33, 0x38, 0x404006e8, 0x36, 0x32, 0x404000f2, 0x36, 0x30, 0x39, 0x404004b6, 0x36, 0x30, 0x38, 0x30, 0x35, 0x31, 0x32, 0x34, 0x33, 0x38, 0x38, 0x34, 0x4040013a, 0x4040000b, 0x34, 0x31, 0x33, 0x4040030f, 0x37, 0x36, 0x32, 0x37, 0x38, 0x40400341, 0x37, 0x31, 0x35, 0x4040059b, 0x33, 0x35, 0x39, 0x39, 0x37, 0x37, 0x30, 0x30, 0x31, 0x32, 0x39, 0x40400472, 0x38, 0x39, 0x34, 0x34, 0x31, 0x40400277, 0x36, 0x38, 0x35, 0x35, 0x4040005f, 0x34, 0x30, 0x36, 0x33, 0x404008e6, 0x32, 0x30, 0x37, 0x32, 0x32, 0x40400158, 0x40800203, 0x34, 0x38, 0x31, 0x35, 0x38, 0x40400205, 0x404001fe, 0x4040027a, 0x40400298, 0x33, 0x39, 0x34, 0x35, 0x32, 0x32, 0x36, 0x37, 0x40c00496, 0x38, 0x4040058a, 0x32, 0x31, 0x404002ea, 0x32, 0x40400387, 0x35, 0x34, 0x36, 0x36, 0x36, 0x4040051b, 0x32, 0x33, 0x39, 0x38, 0x36, 0x34, 0x35, 0x36, 0x404004c4, 0x31, 0x36, 0x33, 0x35, 0x40800253, 0x40400811, 0x37, 0x404008ad, 0x39, 0x38, 0x4040045e, 0x39, 0x33, 0x36, 0x33, 0x34, 0x4040075b, 0x37, 0x34, 0x33, 0x32, 0x34, 0x4040047b, 0x31, 0x35, 0x30, 0x37, 0x36, 0x404004bb, 0x37, 0x39, 0x34, 0x35, 0x31, 0x30, 0x39, 0x4040003e, 0x30, 0x39, 0x34, 0x30, 0x404006a6, 0x38, 0x38, 0x37, 0x39, 0x37, 0x31, 0x30, 0x38, 0x39, 0x33, 0x404008f0, 0x36, 0x39, 0x31, 0x33, 0x36, 0x38, 0x36, 0x37, 0x32, 0x4040025b, 0x404001fe, 0x35, 0x4040053f, 0x40400468, 0x40400801, 0x31, 0x37, 0x39, 0x32, 0x38, 0x36, 0x38, 0x404008cc, 0x38, 0x37, 0x34, 0x37, 0x4080079e, 0x38, 0x32, 0x34, 0x4040097a, 0x38, 0x4040025b, 0x37, 0x31, 0x34, 0x39, 0x30, 0x39, 0x36, 0x37, 0x35, 0x39, 0x38, 0x404006ef, 0x33, 0x36, 0x35, 0x40400134, 0x38, 0x31, 0x4040005c, 0x40400745, 0x40400936, 0x36, 0x38, 0x32, 0x39, 0x4040057e, 0x38, 0x37, 0x32, 0x32, 0x36, 0x35, 0x38, 0x38, 0x30, 0x40400611, 0x35, 0x40400249, 0x34, 0x32, 0x37, 0x30, 0x34, 0x37, 0x37, 0x35, 0x35, 0x4040081e, 0x33, 0x37, 0x39, 0x36, 0x34, 0x31, 0x34, 0x35, 0x31, 0x35, 0x32, 0x404005fd, 0x32, 0x33, 0x34, 0x33, 0x36, 0x34, 0x35, 0x34, 0x404005de, 0x34, 0x34, 0x34, 0x37, 0x39, 0x35, 0x4040003c, 0x40400523, 0x408008e6, 0x34, 0x31, 0x4040052a, 0x33, 0x40400304, 0x35, 0x32, 0x33, 0x31, 0x40800841, 0x31, 0x36, 0x36, 0x31, 0x404008b2, 0x35, 0x39, 0x36, 0x39, 0x35, 0x33, 0x36, 0x32, 0x33, 0x31, 0x34, 0x404005ff, 0x32, 0x34, 0x38, 0x34, 0x39, 0x33, 0x37, 0x31, 0x38, 0x37, 0x31, 0x31, 0x30, 0x31, 0x34, 0x35, 0x37, 0x36, 0x35, 0x34, 0x40400761, 0x30, 0x32, 0x37, 0x39, 0x39, 0x33, 0x34, 0x34, 0x30, 0x33, 0x37, 0x34, 0x32, 0x30, 0x30, 0x37, 0x4040093f, 0x37, 0x38, 0x35, 0x33, 0x39, 0x30, 0x36, 0x32, 0x31, 0x39, 0x40800299, 0x40400345, 0x38, 0x34, 0x37, 0x408003d2, 0x38, 0x33, 0x33, 0x32, 0x31, 0x34, 0x34, 0x35, 0x37, 0x31, 0x40400284, 0x40400776, 0x34, 0x33, 0x35, 0x30, 0x40400928, 0x40400468, 0x35, 0x33, 0x31, 0x39, 0x31, 0x30, 0x34, 0x38, 0x34, 0x38, 0x31, 0x30, 0x30, 0x35, 0x33, 0x37, 0x30, 0x36, 0x404008bc, 0x4080059d, 0x40800781, 0x31, 0x40400559, 0x37, 0x4040031b, 0x35, 0x404007ec, 0x4040040c, 0x36, 0x33, 0x408007dc, 0x34, 0x40400971, 0x4080034e, 0x408003f5, 0x38, 0x4080052d, 0x40800887, 0x39, 0x40400187, 0x39, 0x31, 0x404008ce, 0x38, 0x31, 0x34, 0x36, 0x37, 0x35, 0x31, 0x4040062b, 0x31, 0x32, 0x33, 0x39, 0x40c001a9, 0x39, 0x30, 0x37, 0x31, 0x38, 0x36, 0x34, 0x39, 0x34, 0x32, 0x33, 0x31, 0x39, 0x36, 0x31, 0x35, 0x36, 0x404001ec, 0x404006bc, 0x39, 0x35, 0x40400926, 0x40400469, 0x4040011b, 0x36, 0x30, 0x33, 0x38, 0x40400a25, 0x4040016f, 0x40400384, 0x36, 0x32, 0x4040045a, 0x35, 0x4040084c, 0x36, 0x33, 0x38, 0x39, 0x33, 0x37, 0x37, 0x38, 0x37, 0x404008c5, 0x404000f8, 0x39, 0x37, 0x39, 0x32, 0x30, 0x37, 0x37, 0x33, 0x404005d7, 0x32, 0x31, 0x38, 0x32, 0x35, 0x36, 0x404007df, 0x36, 0x36, 0x404006d6, 0x34, 0x32, 0x4080067e, 0x36, 0x404006e6, 0x34, 0x34, 0x40400024, 0x35, 0x34, 0x39, 0x32, 0x30, 0x32, 0x36, 0x30, 0x35, 0x40400ab3, 0x408003e4, 0x32, 0x30, 0x31, 0x34, 0x39, 0x404004d2, 0x38, 0x35, 0x30, 0x37, 0x33, 0x40400599, 0x36, 0x36, 0x36, 0x30, 0x40400194, 0x32, 0x34, 0x33, 0x34, 0x30, 0x40400087, 0x30, 0x4040076b, 0x38, 0x36, 0x33, 0x40400956, 0x404007e4, 0x4040042b, 0x40400174, 0x35, 0x37, 0x39, 0x36, 0x32, 0x36, 0x38, 0x35, 0x36, 0x40400140, 0x35, 0x30, 0x38, 0x40400523, 0x35, 0x38, 0x37, 0x39, 0x36, 0x39, 0x39, 0x40400711, 0x35, 0x37, 0x34, 0x40400a18, 0x38, 0x34, 0x30, 0x404008b3, 0x31, 0x34, 0x35, 0x39, 0x31, 0x4040078c, 0x37, 0x30, 0x40400234, 0x30, 0x31, 0x40400be7, 0x31, 0x32, 0x40400c74, 0x30, 0x404003c3, 0x33, 0x39, 0x40400b2a, 0x40400112, 0x37, 0x31, 0x35, 0x404003b0, 0x34, 0x32, 0x30, 0x40800bf2, 0x39, 0x40400bc2, 0x30, 0x37, 0x40400341, 0x40400795, 0x40400aaf, 0x40400c62, 0x32, 0x31, 0x40400960, 0x32, 0x35, 0x31, 0x4040057b, 0x40400944, 0x39, 0x32, 0x404001b2, 0x38, 0x32, 0x36, 0x40400b66, 0x32, 0x40400278, 0x33, 0x32, 0x31, 0x35, 0x37, 0x39, 0x31, 0x39, 0x38, 0x34, 0x31, 0x34, 0x4080087b, 0x39, 0x31, 0x36, 0x34, 0x408006e8, 0x39, 0x40800b58, 0x404008db, 0x37, 0x32, 0x32, 0x40400321, 0x35, 0x404008a4, 0x40400141, 0x39, 0x31, 0x30, 0x404000bc, 0x40400c5b, 0x35, 0x32, 0x38, 0x30, 0x31, 0x37, 0x40400231, 0x37, 0x31, 0x32, 0x40400914, 0x38, 0x33, 0x32, 0x40400373, 0x31, 0x40400589, 0x30, 0x39, 0x33, 0x35, 0x33, 0x39, 0x36, 0x35, 0x37, 0x4040064b, 0x31, 0x30, 0x38, 0x33, 0x40400069, 0x35, 0x31, 0x4040077a, 0x40400d5a, 0x31, 0x34, 0x34, 0x34, 0x32, 0x31, 0x30, 0x30, 0x40400202, 0x30, 0x33, 0x4040019c, 0x31, 0x31, 0x30, 0x33, 0x40400c81, 0x40400009, 0x40400026, 0x40c00602, 0x35, 0x31, 0x36, 0x404005d9, 0x40800883, 0x4040092a, 0x35, 0x40800c42, 0x38, 0x35, 0x31, 0x37, 0x31, 0x34, 0x33, 0x37, 0x40400605, 0x4040006d, 0x31, 0x35, 0x35, 0x36, 0x35, 0x30, 0x38, 0x38, 0x404003b9, 0x39, 0x38, 0x39, 0x38, 0x35, 0x39, 0x39, 0x38, 0x32, 0x33, 0x38, 0x404001cf, 0x404009ba, 0x33, 0x4040016c, 0x4040043e, 0x404009c3, 0x38, 0x40800e05, 0x33, 0x32, 0x40400107, 0x35, 0x40400305, 0x33, 0x404001ca, 0x39, 0x4040041b, 0x39, 0x38, 0x4040087d, 0x34, 0x40400cb8, 0x37, 0x4040064b, 0x30, 0x37, 0x404000e5, 0x34, 0x38, 0x31, 0x34, 0x31, 0x40400539, 0x38, 0x35, 0x39, 0x34, 0x36, 0x31, 0x40400bc9, 0x38, 0x30}, + }, + { + input: "testdata/huffman-rand-1k.in", + want: "testdata/huffman-rand-1k.%s.expect", + wantNoInput: "testdata/huffman-rand-1k.%s.expect-noinput", + tokens: []token{0xf8, 0x8b, 0x96, 0x76, 0x48, 0xd, 0x85, 0x94, 0x25, 0x80, 0xaf, 0xc2, 0xfe, 0x8d, 0xe8, 0x20, 0xeb, 0x17, 0x86, 0xc9, 0xb7, 0xc5, 0xde, 0x6, 0xea, 0x7d, 0x18, 0x8b, 0xe7, 0x3e, 0x7, 0xda, 0xdf, 0xff, 0x6c, 0x73, 0xde, 0xcc, 0xe7, 0x6d, 0x8d, 0x4, 0x19, 0x49, 0x7f, 0x47, 0x1f, 0x48, 0x15, 0xb0, 0xe8, 0x9e, 0xf2, 0x31, 0x59, 0xde, 0x34, 0xb4, 0x5b, 0xe5, 0xe0, 0x9, 0x11, 0x30, 0xc2, 0x88, 0x5b, 0x7c, 0x5d, 0x14, 0x13, 0x6f, 0x23, 0xa9, 0xd, 0xbc, 0x2d, 0x23, 0xbe, 0xd9, 0xed, 0x75, 0x4, 0x6c, 0x99, 0xdf, 0xfd, 0x70, 0x66, 0xe6, 0xee, 0xd9, 0xb1, 0x9e, 0x6e, 0x83, 0x59, 0xd5, 0xd4, 0x80, 0x59, 0x98, 0x77, 0x89, 0x43, 0x38, 0xc9, 0xaf, 0x30, 0x32, 0x9a, 0x20, 0x1b, 0x46, 0x3d, 0x67, 0x6e, 0xd7, 0x72, 0x9e, 0x4e, 0x21, 0x4f, 0xc6, 0xe0, 0xd4, 0x7b, 0x4, 0x8d, 0xa5, 0x3, 0xf6, 0x5, 0x9b, 0x6b, 0xdc, 0x2a, 0x93, 0x77, 0x28, 0xfd, 0xb4, 0x62, 0xda, 0x20, 0xe7, 0x1f, 0xab, 0x6b, 0x51, 0x43, 0x39, 0x2f, 0xa0, 0x92, 0x1, 0x6c, 0x75, 0x3e, 0xf4, 0x35, 0xfd, 0x43, 0x2e, 0xf7, 0xa4, 0x75, 0xda, 0xea, 0x9b, 0xa, 0x64, 0xb, 0xe0, 0x23, 0x29, 0xbd, 0xf7, 0xe7, 0x83, 0x3c, 0xfb, 0xdf, 0xb3, 0xae, 0x4f, 0xa4, 0x47, 0x55, 0x99, 0xde, 0x2f, 0x96, 0x6e, 0x1c, 0x43, 0x4c, 0x87, 0xe2, 0x7c, 0xd9, 0x5f, 0x4c, 0x7c, 0xe8, 0x90, 0x3, 0xdb, 0x30, 0x95, 0xd6, 0x22, 0xc, 0x47, 0xb8, 0x4d, 0x6b, 0xbd, 0x24, 0x11, 0xab, 0x2c, 0xd7, 0xbe, 0x6e, 0x7a, 0xd6, 0x8, 0xa3, 0x98, 0xd8, 0xdd, 0x15, 0x6a, 0xfa, 0x93, 0x30, 0x1, 0x25, 0x1d, 0xa2, 0x74, 0x86, 0x4b, 0x6a, 0x95, 0xe8, 0xe1, 0x4e, 0xe, 0x76, 0xb9, 0x49, 0xa9, 0x5f, 0xa0, 0xa6, 0x63, 0x3c, 0x7e, 0x7e, 0x20, 0x13, 0x4f, 0xbb, 0x66, 0x92, 0xb8, 0x2e, 0xa4, 0xfa, 0x48, 0xcb, 0xae, 0xb9, 0x3c, 0xaf, 0xd3, 0x1f, 0xe1, 0xd5, 0x8d, 0x42, 0x6d, 0xf0, 0xfc, 0x8c, 0xc, 0x0, 0xde, 0x40, 0xab, 0x8b, 0x47, 0x97, 0x4e, 0xa8, 0xcf, 0x8e, 0xdb, 0xa6, 0x8b, 0x20, 0x9, 0x84, 0x7a, 0x66, 0xe5, 0x98, 0x29, 0x2, 0x95, 0xe6, 0x38, 0x32, 0x60, 0x3, 0xe3, 0x9a, 0x1e, 0x54, 0xe8, 0x63, 0x80, 0x48, 0x9c, 0xe7, 0x63, 0x33, 0x6e, 0xa0, 0x65, 0x83, 0xfa, 0xc6, 0xba, 0x7a, 0x43, 0x71, 0x5, 0xf5, 0x68, 0x69, 0x85, 0x9c, 0xba, 0x45, 0xcd, 0x6b, 0xb, 0x19, 0xd1, 0xbb, 0x7f, 0x70, 0x85, 0x92, 0xd1, 0xb4, 0x64, 0x82, 0xb1, 0xe4, 0x62, 0xc5, 0x3c, 0x46, 0x1f, 0x92, 0x31, 0x1c, 0x4e, 0x41, 0x77, 0xf7, 0xe7, 0x87, 0xa2, 0xf, 0x6e, 0xe8, 0x92, 0x3, 0x6b, 0xa, 0xe7, 0xa9, 0x3b, 0x11, 0xda, 0x66, 0x8a, 0x29, 0xda, 0x79, 0xe1, 0x64, 0x8d, 0xe3, 0x54, 0xd4, 0xf5, 0xef, 0x64, 0x87, 0x3b, 0xf4, 0xc2, 0xf4, 0x71, 0x13, 0xa9, 0xe9, 0xe0, 0xa2, 0x6, 0x14, 0xab, 0x5d, 0xa7, 0x96, 0x0, 0xd6, 0xc3, 0xcc, 0x57, 0xed, 0x39, 0x6a, 0x25, 0xcd, 0x76, 0xea, 0xba, 0x3a, 0xf2, 0xa1, 0x95, 0x5d, 0xe5, 0x71, 0xcf, 0x9c, 0x62, 0x9e, 0x6a, 0xfa, 0xd5, 0x31, 0xd1, 0xa8, 0x66, 0x30, 0x33, 0xaa, 0x51, 0x17, 0x13, 0x82, 0x99, 0xc8, 0x14, 0x60, 0x9f, 0x4d, 0x32, 0x6d, 0xda, 0x19, 0x26, 0x21, 0xdc, 0x7e, 0x2e, 0x25, 0x67, 0x72, 0xca, 0xf, 0x92, 0xcd, 0xf6, 0xd6, 0xcb, 0x97, 0x8a, 0x33, 0x58, 0x73, 0x70, 0x91, 0x1d, 0xbf, 0x28, 0x23, 0xa3, 0xc, 0xf1, 0x83, 0xc3, 0xc8, 0x56, 0x77, 0x68, 0xe3, 0x82, 0xba, 0xb9, 0x57, 0x56, 0x57, 0x9c, 0xc3, 0xd6, 0x14, 0x5, 0x3c, 0xb1, 0xaf, 0x93, 0xc8, 0x8a, 0x57, 0x7f, 0x53, 0xfa, 0x2f, 0xaa, 0x6e, 0x66, 0x83, 0xfa, 0x33, 0xd1, 0x21, 0xab, 0x1b, 0x71, 0xb4, 0x7c, 0xda, 0xfd, 0xfb, 0x7f, 0x20, 0xab, 0x5e, 0xd5, 0xca, 0xfd, 0xdd, 0xe0, 0xee, 0xda, 0xba, 0xa8, 0x27, 0x99, 0x97, 0x69, 0xc1, 0x3c, 0x82, 0x8c, 0xa, 0x5c, 0x2d, 0x5b, 0x88, 0x3e, 0x34, 0x35, 0x86, 0x37, 0x46, 0x79, 0xe1, 0xaa, 0x19, 0xfb, 0xaa, 0xde, 0x15, 0x9, 0xd, 0x1a, 0x57, 0xff, 0xb5, 0xf, 0xf3, 0x2b, 0x5a, 0x6a, 0x4d, 0x19, 0x77, 0x71, 0x45, 0xdf, 0x4f, 0xb3, 0xec, 0xf1, 0xeb, 0x18, 0x53, 0x3e, 0x3b, 0x47, 0x8, 0x9a, 0x73, 0xa0, 0x5c, 0x8c, 0x5f, 0xeb, 0xf, 0x3a, 0xc2, 0x43, 0x67, 0xb4, 0x66, 0x67, 0x80, 0x58, 0xe, 0xc1, 0xec, 0x40, 0xd4, 0x22, 0x94, 0xca, 0xf9, 0xe8, 0x92, 0xe4, 0x69, 0x38, 0xbe, 0x67, 0x64, 0xca, 0x50, 0xc7, 0x6, 0x67, 0x42, 0x6e, 0xa3, 0xf0, 0xb7, 0x6c, 0xf2, 0xe8, 0x5f, 0xb1, 0xaf, 0xe7, 0xdb, 0xbb, 0x77, 0xb5, 0xf8, 0xcb, 0x8, 0xc4, 0x75, 0x7e, 0xc0, 0xf9, 0x1c, 0x7f, 0x3c, 0x89, 0x2f, 0xd2, 0x58, 0x3a, 0xe2, 0xf8, 0x91, 0xb6, 0x7b, 0x24, 0x27, 0xe9, 0xae, 0x84, 0x8b, 0xde, 0x74, 0xac, 0xfd, 0xd9, 0xb7, 0x69, 0x2a, 0xec, 0x32, 0x6f, 0xf0, 0x92, 0x84, 0xf1, 0x40, 0xc, 0x8a, 0xbc, 0x39, 0x6e, 0x2e, 0x73, 0xd4, 0x6e, 0x8a, 0x74, 0x2a, 0xdc, 0x60, 0x1f, 0xa3, 0x7, 0xde, 0x75, 0x8b, 0x74, 0xc8, 0xfe, 0x63, 0x75, 0xf6, 0x3d, 0x63, 0xac, 0x33, 0x89, 0xc3, 0xf0, 0xf8, 0x2d, 0x6b, 0xb4, 0x9e, 0x74, 0x8b, 0x5c, 0x33, 0xb4, 0xca, 0xa8, 0xe4, 0x99, 0xb6, 0x90, 0xa1, 0xef, 0xf, 0xd3, 0x61, 0xb2, 0xc6, 0x1a, 0x94, 0x7c, 0x44, 0x55, 0xf4, 0x45, 0xff, 0x9e, 0xa5, 0x5a, 0xc6, 0xa0, 0xe8, 0x2a, 0xc1, 0x8d, 0x6f, 0x34, 0x11, 0xb9, 0xbe, 0x4e, 0xd9, 0x87, 0x97, 0x73, 0xcf, 0x3d, 0x23, 0xae, 0xd5, 0x1a, 0x5e, 0xae, 0x5d, 0x6a, 0x3, 0xf9, 0x22, 0xd, 0x10, 0xd9, 0x47, 0x69, 0x15, 0x3f, 0xee, 0x52, 0xa3, 0x8, 0xd2, 0x3c, 0x51, 0xf4, 0xf8, 0x9d, 0xe4, 0x98, 0x89, 0xc8, 0x67, 0x39, 0xd5, 0x5e, 0x35, 0x78, 0x27, 0xe8, 0x3c, 0x80, 0xae, 0x79, 0x71, 0xd2, 0x93, 0xf4, 0xaa, 0x51, 0x12, 0x1c, 0x4b, 0x1b, 0xe5, 0x6e, 0x15, 0x6f, 0xe4, 0xbb, 0x51, 0x9b, 0x45, 0x9f, 0xf9, 0xc4, 0x8c, 0x2a, 0xfb, 0x1a, 0xdf, 0x55, 0xd3, 0x48, 0x93, 0x27, 0x1, 0x26, 0xc2, 0x6b, 0x55, 0x6d, 0xa2, 0xfb, 0x84, 0x8b, 0xc9, 0x9e, 0x28, 0xc2, 0xef, 0x1a, 0x24, 0xec, 0x9b, 0xae, 0xbd, 0x60, 0xe9, 0x15, 0x35, 0xee, 0x42, 0xa4, 0x33, 0x5b, 0xfa, 0xf, 0xb6, 0xf7, 0x1, 0xa6, 0x2, 0x4c, 0xca, 0x90, 0x58, 0x3a, 0x96, 0x41, 0xe7, 0xcb, 0x9, 0x8c, 0xdb, 0x85, 0x4d, 0xa8, 0x89, 0xf3, 0xb5, 0x8e, 0xfd, 0x75, 0x5b, 0x4f, 0xed, 0xde, 0x3f, 0xeb, 0x38, 0xa3, 0xbe, 0xb0, 0x73, 0xfc, 0xb8, 0x54, 0xf7, 0x4c, 0x30, 0x67, 0x2e, 0x38, 0xa2, 0x54, 0x18, 0xba, 0x8, 0xbf, 0xf2, 0x39, 0xd5, 0xfe, 0xa5, 0x41, 0xc6, 0x66, 0x66, 0xba, 0x81, 0xef, 0x67, 0xe4, 0xe6, 0x3c, 0xc, 0xca, 0xa4, 0xa, 0x79, 0xb3, 0x57, 0x8b, 0x8a, 0x75, 0x98, 0x18, 0x42, 0x2f, 0x29, 0xa3, 0x82, 0xef, 0x9f, 0x86, 0x6, 0x23, 0xe1, 0x75, 0xfa, 0x8, 0xb1, 0xde, 0x17, 0x4a}, + }, + { + input: "testdata/huffman-rand-limit.in", + want: "testdata/huffman-rand-limit.%s.expect", + wantNoInput: "testdata/huffman-rand-limit.%s.expect-noinput", + tokens: []token{0x61, 0x51c00000, 0xa, 0xf8, 0x8b, 0x96, 0x76, 0x48, 0xa, 0x85, 0x94, 0x25, 0x80, 0xaf, 0xc2, 0xfe, 0x8d, 0xe8, 0x20, 0xeb, 0x17, 0x86, 0xc9, 0xb7, 0xc5, 0xde, 0x6, 0xea, 0x7d, 0x18, 0x8b, 0xe7, 0x3e, 0x7, 0xda, 0xdf, 0xff, 0x6c, 0x73, 0xde, 0xcc, 0xe7, 0x6d, 0x8d, 0x4, 0x19, 0x49, 0x7f, 0x47, 0x1f, 0x48, 0x15, 0xb0, 0xe8, 0x9e, 0xf2, 0x31, 0x59, 0xde, 0x34, 0xb4, 0x5b, 0xe5, 0xe0, 0x9, 0x11, 0x30, 0xc2, 0x88, 0x5b, 0x7c, 0x5d, 0x14, 0x13, 0x6f, 0x23, 0xa9, 0xa, 0xbc, 0x2d, 0x23, 0xbe, 0xd9, 0xed, 0x75, 0x4, 0x6c, 0x99, 0xdf, 0xfd, 0x70, 0x66, 0xe6, 0xee, 0xd9, 0xb1, 0x9e, 0x6e, 0x83, 0x59, 0xd5, 0xd4, 0x80, 0x59, 0x98, 0x77, 0x89, 0x43, 0x38, 0xc9, 0xaf, 0x30, 0x32, 0x9a, 0x20, 0x1b, 0x46, 0x3d, 0x67, 0x6e, 0xd7, 0x72, 0x9e, 0x4e, 0x21, 0x4f, 0xc6, 0xe0, 0xd4, 0x7b, 0x4, 0x8d, 0xa5, 0x3, 0xf6, 0x5, 0x9b, 0x6b, 0xdc, 0x2a, 0x93, 0x77, 0x28, 0xfd, 0xb4, 0x62, 0xda, 0x20, 0xe7, 0x1f, 0xab, 0x6b, 0x51, 0x43, 0x39, 0x2f, 0xa0, 0x92, 0x1, 0x6c, 0x75, 0x3e, 0xf4, 0x35, 0xfd, 0x43, 0x2e, 0xf7, 0xa4, 0x75, 0xda, 0xea, 0x9b, 0xa}, + }, + { + input: "testdata/huffman-shifts.in", + want: "testdata/huffman-shifts.%s.expect", + wantNoInput: "testdata/huffman-shifts.%s.expect-noinput", + tokens: []token{0x31, 0x30, 0x7fc00001, 0x7fc00001, 0x7fc00001, 0x7fc00001, 0x7fc00001, 0x7fc00001, 0x7fc00001, 0x7fc00001, 0x7fc00001, 0x7fc00001, 0x7fc00001, 0x7fc00001, 0x7fc00001, 0x7fc00001, 0x7fc00001, 0x52400001, 0xd, 0xa, 0x32, 0x33, 0x7fc00001, 0x7fc00001, 0x7fc00001, 0x7fc00001, 0x7fc00001, 0x7fc00001, 0x7fc00001, 0x7fc00001, 0x7fc00001, 0x7f400001}, + }, + { + input: "testdata/huffman-text-shift.in", + want: "testdata/huffman-text-shift.%s.expect", + wantNoInput: "testdata/huffman-text-shift.%s.expect-noinput", + tokens: []token{0x2f, 0x2f, 0x43, 0x6f, 0x70, 0x79, 0x72, 0x69, 0x67, 0x68, 0x74, 0x32, 0x30, 0x30, 0x39, 0x54, 0x68, 0x47, 0x6f, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x2e, 0x41, 0x6c, 0x6c, 0x40800016, 0x72, 0x72, 0x76, 0x64, 0x2e, 0xd, 0xa, 0x2f, 0x2f, 0x55, 0x6f, 0x66, 0x74, 0x68, 0x69, 0x6f, 0x75, 0x72, 0x63, 0x63, 0x6f, 0x64, 0x69, 0x67, 0x6f, 0x76, 0x72, 0x6e, 0x64, 0x62, 0x79, 0x42, 0x53, 0x44, 0x2d, 0x74, 0x79, 0x6c, 0x40400020, 0x6c, 0x69, 0x63, 0x6e, 0x74, 0x68, 0x74, 0x63, 0x6e, 0x62, 0x66, 0x6f, 0x75, 0x6e, 0x64, 0x69, 0x6e, 0x74, 0x68, 0x4c, 0x49, 0x43, 0x45, 0x4e, 0x53, 0x45, 0x66, 0x69, 0x6c, 0x2e, 0xd, 0xa, 0xd, 0xa, 0x70, 0x63, 0x6b, 0x67, 0x6d, 0x69, 0x6e, 0x4040000a, 0x69, 0x6d, 0x70, 0x6f, 0x72, 0x74, 0x22, 0x6f, 0x22, 0x4040000c, 0x66, 0x75, 0x6e, 0x63, 0x6d, 0x69, 0x6e, 0x28, 0x29, 0x7b, 0xd, 0xa, 0x9, 0x76, 0x72, 0x62, 0x3d, 0x6d, 0x6b, 0x28, 0x5b, 0x5d, 0x62, 0x79, 0x74, 0x2c, 0x36, 0x35, 0x35, 0x33, 0x35, 0x29, 0xd, 0xa, 0x9, 0x66, 0x2c, 0x5f, 0x3a, 0x3d, 0x6f, 0x2e, 0x43, 0x72, 0x74, 0x28, 0x22, 0x68, 0x75, 0x66, 0x66, 0x6d, 0x6e, 0x2d, 0x6e, 0x75, 0x6c, 0x6c, 0x2d, 0x6d, 0x78, 0x2e, 0x69, 0x6e, 0x22, 0x40800021, 0x2e, 0x57, 0x72, 0x69, 0x74, 0x28, 0x62, 0x29, 0xd, 0xa, 0x7d, 0xd, 0xa, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x58, 0x78, 0x79, 0x7a, 0x21, 0x22, 0x23, 0xc2, 0xa4, 0x25, 0x26, 0x2f, 0x3f, 0x22}, + }, + { + input: "testdata/huffman-text.in", + want: "testdata/huffman-text.%s.expect", + wantNoInput: "testdata/huffman-text.%s.expect-noinput", + tokens: []token{0x2f, 0x2f, 0x20, 0x43, 0x6f, 0x70, 0x79, 0x72, 0x69, 0x67, 0x68, 0x74, 0x20, 0x32, 0x30, 0x30, 0x39, 0x20, 0x54, 0x68, 0x65, 0x20, 0x47, 0x6f, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x73, 0x2e, 0x20, 0x41, 0x6c, 0x6c, 0x20, 0x4080001e, 0x73, 0x20, 0x72, 0x65, 0x73, 0x65, 0x72, 0x76, 0x65, 0x64, 0x2e, 0xd, 0xa, 0x2f, 0x2f, 0x20, 0x55, 0x73, 0x65, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x69, 0x73, 0x20, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x20, 0x63, 0x6f, 0x64, 0x65, 0x20, 0x69, 0x73, 0x20, 0x67, 0x6f, 0x76, 0x65, 0x72, 0x6e, 0x65, 0x64, 0x20, 0x62, 0x79, 0x20, 0x61, 0x20, 0x42, 0x53, 0x44, 0x2d, 0x73, 0x74, 0x79, 0x6c, 0x65, 0x40800036, 0x6c, 0x69, 0x63, 0x65, 0x6e, 0x73, 0x65, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x63, 0x61, 0x6e, 0x20, 0x62, 0x65, 0x20, 0x66, 0x6f, 0x75, 0x6e, 0x64, 0x20, 0x69, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x4c, 0x49, 0x43, 0x45, 0x4e, 0x53, 0x45, 0x20, 0x66, 0x69, 0x6c, 0x65, 0x2e, 0xd, 0xa, 0xd, 0xa, 0x70, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x20, 0x6d, 0x61, 0x69, 0x6e, 0x4040000f, 0x69, 0x6d, 0x70, 0x6f, 0x72, 0x74, 0x20, 0x22, 0x6f, 0x73, 0x22, 0x4040000e, 0x66, 0x75, 0x6e, 0x63, 0x4080001b, 0x28, 0x29, 0x20, 0x7b, 0xd, 0xa, 0x9, 0x76, 0x61, 0x72, 0x20, 0x62, 0x20, 0x3d, 0x20, 0x6d, 0x61, 0x6b, 0x65, 0x28, 0x5b, 0x5d, 0x62, 0x79, 0x74, 0x65, 0x2c, 0x20, 0x36, 0x35, 0x35, 0x33, 0x35, 0x29, 0xd, 0xa, 0x9, 0x66, 0x2c, 0x20, 0x5f, 0x20, 0x3a, 0x3d, 0x20, 0x6f, 0x73, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x28, 0x22, 0x68, 0x75, 0x66, 0x66, 0x6d, 0x61, 0x6e, 0x2d, 0x6e, 0x75, 0x6c, 0x6c, 0x2d, 0x6d, 0x61, 0x78, 0x2e, 0x69, 0x6e, 0x22, 0x4080002a, 0x2e, 0x57, 0x72, 0x69, 0x74, 0x65, 0x28, 0x62, 0x29, 0xd, 0xa, 0x7d, 0xd, 0xa}, + }, + { + input: "testdata/huffman-zero.in", + want: "testdata/huffman-zero.%s.expect", + wantNoInput: "testdata/huffman-zero.%s.expect-noinput", + tokens: []token{0x30, ml, 0x4b800000}, + }, + { + input: "", + want: "", + wantNoInput: "testdata/null-long-match.%s.expect-noinput", + tokens: []token{0x0, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, ml, 0x41400000}, + }, +} + +// TestWriteBlock tests if the writeBlock encoding has changed. +// To update the reference files use the "-update" flag on the test. +func TestWriteBlock(t *testing.T) { + for _, test := range writeBlockTests { + testBlock(t, test, "wb") + } +} + +// TestWriteBlockDynamic tests if the writeBlockDynamic encoding has changed. +// To update the reference files use the "-update" flag on the test. +func TestWriteBlockDynamic(t *testing.T) { + for _, test := range writeBlockTests { + testBlock(t, test, "dyn") + } +} + +// TestWriteBlockDynamic tests if the writeBlockDynamic encoding has changed. +// To update the reference files use the "-update" flag on the test. +func TestWriteBlockDynamicSync(t *testing.T) { + for _, test := range writeBlockTests { + testBlock(t, test, "sync") + } +} + +// testBlock tests a block against its references, +// or regenerate the references, if "-update" flag is set. +func testBlock(t *testing.T, test huffTest, ttype string) { + if test.want != "" { + test.want = fmt.Sprintf(test.want, ttype) + } + const gotSuffix = ".got" + test.wantNoInput = fmt.Sprintf(test.wantNoInput, ttype) + tokens := indexTokens(test.tokens) + if *update { + if test.input != "" { + t.Logf("Updating %q", test.want) + input, err := ioutil.ReadFile(test.input) + if err != nil { + t.Error(err) + return + } + + f, err := os.Create(test.want) + if err != nil { + t.Error(err) + return + } + defer f.Close() + bw := newHuffmanBitWriter(f) + writeToType(t, ttype, bw, tokens, input) + } + + t.Logf("Updating %q", test.wantNoInput) + f, err := os.Create(test.wantNoInput) + if err != nil { + t.Error(err) + return + } + defer f.Close() + bw := newHuffmanBitWriter(f) + writeToType(t, ttype, bw, tokens, nil) + return + } + + if test.input != "" { + t.Logf("Testing %q", test.want) + input, err := ioutil.ReadFile(test.input) + if err != nil { + t.Error(err) + return + } + want, err := ioutil.ReadFile(test.want) + if err != nil { + t.Error(err) + return + } + var buf bytes.Buffer + bw := newHuffmanBitWriter(&buf) + writeToType(t, ttype, bw, tokens, input) + + got := buf.Bytes() + if !bytes.Equal(got, want) { + t.Errorf("writeBlock did not yield expected result for file %q with input. See %q", test.want, test.want+gotSuffix) + if err := ioutil.WriteFile(test.want+gotSuffix, got, 0666); err != nil { + t.Error(err) + } + } + t.Log("Output ok") + + // Test if the writer produces the same output after reset. + buf.Reset() + bw.reset(&buf) + writeToType(t, ttype, bw, tokens, input) + bw.flush() + got = buf.Bytes() + if !bytes.Equal(got, want) { + t.Errorf("reset: writeBlock did not yield expected result for file %q with input. See %q", test.want, test.want+".reset"+gotSuffix) + if err := ioutil.WriteFile(test.want+".reset"+gotSuffix, got, 0666); err != nil { + t.Error(err) + } + return + } + t.Log("Reset ok") + testWriterEOF(t, "wb", test, true) + } + t.Logf("Testing %q", test.wantNoInput) + wantNI, err := ioutil.ReadFile(test.wantNoInput) + if err != nil { + t.Error(err) + return + } + var buf bytes.Buffer + bw := newHuffmanBitWriter(&buf) + writeToType(t, ttype, bw, tokens, nil) + + got := buf.Bytes() + if !bytes.Equal(got, wantNI) { + t.Errorf("writeBlock did not yield expected result for file %q with input. See %q", test.wantNoInput, test.wantNoInput+gotSuffix) + if err := ioutil.WriteFile(test.wantNoInput+gotSuffix, got, 0666); err != nil { + t.Error(err) + } + } else if got[0]&1 == 1 { + t.Error("got unexpected EOF") + return + } + + t.Log("Output ok") + + // Test if the writer produces the same output after reset. + buf.Reset() + bw.reset(&buf) + writeToType(t, ttype, bw, tokens, nil) + bw.flush() + got = buf.Bytes() + if !bytes.Equal(got, wantNI) { + t.Errorf("reset: writeBlock did not yield expected result for file %q without input. See %q", test.wantNoInput, test.wantNoInput+".reset"+gotSuffix) + if err := ioutil.WriteFile(test.wantNoInput+".reset"+gotSuffix, got, 0666); err != nil { + t.Error(err) + } + return + } + t.Log("Reset ok") + testWriterEOF(t, "wb", test, false) +} + +func writeToType(t *testing.T, ttype string, bw *huffmanBitWriter, tok tokens, input []byte) { + switch ttype { + case "wb": + bw.writeBlock(&tok, false, input) + case "dyn": + bw.writeBlockDynamic(&tok, false, input, false) + case "sync": + bw.writeBlockDynamic(&tok, false, input, true) + default: + panic("unknown test type") + } + + if bw.err != nil { + t.Error(bw.err) + return + } + + bw.flush() + if bw.err != nil { + t.Error(bw.err) + return + } +} + +// testWriterEOF tests if the written block contains an EOF marker. +func testWriterEOF(t *testing.T, ttype string, test huffTest, useInput bool) { + if useInput && test.input == "" { + return + } + var input []byte + if useInput { + var err error + input, err = ioutil.ReadFile(test.input) + if err != nil { + t.Error(err) + return + } + } + var buf bytes.Buffer + bw := newHuffmanBitWriter(&buf) + tokens := indexTokens(test.tokens) + switch ttype { + case "wb": + bw.writeBlock(&tokens, true, input) + case "dyn": + bw.writeBlockDynamic(&tokens, true, input, true) + case "huff": + bw.writeBlockHuff(true, input, true) + default: + panic("unknown test type") + } + if bw.err != nil { + t.Error(bw.err) + return + } + + bw.flush() + if bw.err != nil { + t.Error(bw.err) + return + } + b := buf.Bytes() + if len(b) == 0 { + t.Error("no output received") + return + } + if b[0]&1 != 1 { + t.Errorf("block not marked with EOF for input %q", test.input) + return + } + t.Log("EOF ok") +} diff --git a/github.com/klauspost/compress/flate/huffman_code.go b/github.com/klauspost/compress/flate/huffman_code.go new file mode 100644 index 0000000..4c39a30 --- /dev/null +++ b/github.com/klauspost/compress/flate/huffman_code.go @@ -0,0 +1,363 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package flate + +import ( + "math" + "math/bits" +) + +const ( + maxBitsLimit = 16 + // number of valid literals + literalCount = 286 +) + +// hcode is a huffman code with a bit code and bit length. +type hcode struct { + code, len uint16 +} + +type huffmanEncoder struct { + codes []hcode + freqcache []literalNode + bitCount [17]int32 +} + +type literalNode struct { + literal uint16 + freq uint16 +} + +// A levelInfo describes the state of the constructed tree for a given depth. +type levelInfo struct { + // Our level. for better printing + level int32 + + // The frequency of the last node at this level + lastFreq int32 + + // The frequency of the next character to add to this level + nextCharFreq int32 + + // The frequency of the next pair (from level below) to add to this level. + // Only valid if the "needed" value of the next lower level is 0. + nextPairFreq int32 + + // The number of chains remaining to generate for this level before moving + // up to the next level + needed int32 +} + +// set sets the code and length of an hcode. +func (h *hcode) set(code uint16, length uint16) { + h.len = length + h.code = code +} + +func reverseBits(number uint16, bitLength byte) uint16 { + return bits.Reverse16(number << ((16 - bitLength) & 15)) +} + +func maxNode() literalNode { return literalNode{math.MaxUint16, math.MaxUint16} } + +func newHuffmanEncoder(size int) *huffmanEncoder { + // Make capacity to next power of two. + c := uint(bits.Len32(uint32(size - 1))) + return &huffmanEncoder{codes: make([]hcode, size, 1<= 3 +// The cases of 0, 1, and 2 literals are handled by special case code. +// +// list An array of the literals with non-zero frequencies +// and their associated frequencies. The array is in order of increasing +// frequency, and has as its last element a special element with frequency +// MaxInt32 +// maxBits The maximum number of bits that should be used to encode any literal. +// Must be less than 16. +// return An integer array in which array[i] indicates the number of literals +// that should be encoded in i bits. +func (h *huffmanEncoder) bitCounts(list []literalNode, maxBits int32) []int32 { + if maxBits >= maxBitsLimit { + panic("flate: maxBits too large") + } + n := int32(len(list)) + list = list[0 : n+1] + list[n] = maxNode() + + // The tree can't have greater depth than n - 1, no matter what. This + // saves a little bit of work in some small cases + if maxBits > n-1 { + maxBits = n - 1 + } + + // Create information about each of the levels. + // A bogus "Level 0" whose sole purpose is so that + // level1.prev.needed==0. This makes level1.nextPairFreq + // be a legitimate value that never gets chosen. + var levels [maxBitsLimit]levelInfo + // leafCounts[i] counts the number of literals at the left + // of ancestors of the rightmost node at level i. + // leafCounts[i][j] is the number of literals at the left + // of the level j ancestor. + var leafCounts [maxBitsLimit][maxBitsLimit]int32 + + for level := int32(1); level <= maxBits; level++ { + // For every level, the first two items are the first two characters. + // We initialize the levels as if we had already figured this out. + levels[level] = levelInfo{ + level: level, + lastFreq: int32(list[1].freq), + nextCharFreq: int32(list[2].freq), + nextPairFreq: int32(list[0].freq) + int32(list[1].freq), + } + leafCounts[level][level] = 2 + if level == 1 { + levels[level].nextPairFreq = math.MaxInt32 + } + } + + // We need a total of 2*n - 2 items at top level and have already generated 2. + levels[maxBits].needed = 2*n - 4 + + level := maxBits + for { + l := &levels[level] + if l.nextPairFreq == math.MaxInt32 && l.nextCharFreq == math.MaxInt32 { + // We've run out of both leafs and pairs. + // End all calculations for this level. + // To make sure we never come back to this level or any lower level, + // set nextPairFreq impossibly large. + l.needed = 0 + levels[level+1].nextPairFreq = math.MaxInt32 + level++ + continue + } + + prevFreq := l.lastFreq + if l.nextCharFreq < l.nextPairFreq { + // The next item on this row is a leaf node. + n := leafCounts[level][level] + 1 + l.lastFreq = l.nextCharFreq + // Lower leafCounts are the same of the previous node. + leafCounts[level][level] = n + e := list[n] + if e.literal < math.MaxUint16 { + l.nextCharFreq = int32(e.freq) + } else { + l.nextCharFreq = math.MaxInt32 + } + } else { + // The next item on this row is a pair from the previous row. + // nextPairFreq isn't valid until we generate two + // more values in the level below + l.lastFreq = l.nextPairFreq + // Take leaf counts from the lower level, except counts[level] remains the same. + copy(leafCounts[level][:level], leafCounts[level-1][:level]) + levels[l.level-1].needed = 2 + } + + if l.needed--; l.needed == 0 { + // We've done everything we need to do for this level. + // Continue calculating one level up. Fill in nextPairFreq + // of that level with the sum of the two nodes we've just calculated on + // this level. + if l.level == maxBits { + // All done! + break + } + levels[l.level+1].nextPairFreq = prevFreq + l.lastFreq + level++ + } else { + // If we stole from below, move down temporarily to replenish it. + for levels[level-1].needed > 0 { + level-- + } + } + } + + // Somethings is wrong if at the end, the top level is null or hasn't used + // all of the leaves. + if leafCounts[maxBits][maxBits] != n { + panic("leafCounts[maxBits][maxBits] != n") + } + + bitCount := h.bitCount[:maxBits+1] + bits := 1 + counts := &leafCounts[maxBits] + for level := maxBits; level > 0; level-- { + // chain.leafCount gives the number of literals requiring at least "bits" + // bits to encode. + bitCount[bits] = counts[level] - counts[level-1] + bits++ + } + return bitCount +} + +// Look at the leaves and assign them a bit count and an encoding as specified +// in RFC 1951 3.2.2 +func (h *huffmanEncoder) assignEncodingAndSize(bitCount []int32, list []literalNode) { + code := uint16(0) + for n, bits := range bitCount { + code <<= 1 + if n == 0 || bits == 0 { + continue + } + // The literals list[len(list)-bits] .. list[len(list)-bits] + // are encoded using "bits" bits, and get the values + // code, code + 1, .... The code values are + // assigned in literal order (not frequency order). + chunk := list[len(list)-int(bits):] + + sortByLiteral(chunk) + for _, node := range chunk { + h.codes[node.literal] = hcode{code: reverseBits(code, uint8(n)), len: uint16(n)} + code++ + } + list = list[0 : len(list)-int(bits)] + } +} + +// Update this Huffman Code object to be the minimum code for the specified frequency count. +// +// freq An array of frequencies, in which frequency[i] gives the frequency of literal i. +// maxBits The maximum number of bits to use for any literal. +func (h *huffmanEncoder) generate(freq []uint16, maxBits int32) { + if h.freqcache == nil { + // Allocate a reusable buffer with the longest possible frequency table. + // Possible lengths are codegenCodeCount, offsetCodeCount and literalCount. + // The largest of these is literalCount, so we allocate for that case. + h.freqcache = make([]literalNode, literalCount+1) + } + list := h.freqcache[:len(freq)+1] + // Number of non-zero literals + count := 0 + // Set list to be the set of all non-zero literals and their frequencies + for i, f := range freq { + if f != 0 { + list[count] = literalNode{uint16(i), f} + count++ + } else { + list[count] = literalNode{} + h.codes[i].len = 0 + } + } + list[len(freq)] = literalNode{} + + list = list[:count] + if count <= 2 { + // Handle the small cases here, because they are awkward for the general case code. With + // two or fewer literals, everything has bit length 1. + for i, node := range list { + // "list" is in order of increasing literal value. + h.codes[node.literal].set(uint16(i), 1) + } + return + } + sortByFreq(list) + + // Get the number of literals for each bit count + bitCount := h.bitCounts(list, maxBits) + // And do the assignment + h.assignEncodingAndSize(bitCount, list) +} + +func atLeastOne(v float32) float32 { + if v < 1 { + return 1 + } + return v +} + +// histogramSize accumulates a histogram of b in h. +// An estimated size in bits is returned. +// Unassigned values are assigned '1' in the histogram. +// len(h) must be >= 256, and h's elements must be all zeroes. +func histogramSize(b []byte, h []uint16, fill bool) (int, int) { + h = h[:256] + for _, t := range b { + h[t]++ + } + invTotal := 1.0 / float32(len(b)) + shannon := float32(0.0) + var extra float32 + if fill { + oneBits := atLeastOne(-mFastLog2(invTotal)) + for i, v := range h[:] { + if v > 0 { + n := float32(v) + shannon += atLeastOne(-mFastLog2(n*invTotal)) * n + } else { + h[i] = 1 + extra += oneBits + } + } + } else { + for _, v := range h[:] { + if v > 0 { + n := float32(v) + shannon += atLeastOne(-mFastLog2(n*invTotal)) * n + } + } + } + + return int(shannon + 0.99), int(extra + 0.99) +} diff --git a/github.com/klauspost/compress/flate/huffman_sortByFreq.go b/github.com/klauspost/compress/flate/huffman_sortByFreq.go new file mode 100644 index 0000000..2077802 --- /dev/null +++ b/github.com/klauspost/compress/flate/huffman_sortByFreq.go @@ -0,0 +1,178 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package flate + +// Sort sorts data. +// It makes one call to data.Len to determine n, and O(n*log(n)) calls to +// data.Less and data.Swap. The sort is not guaranteed to be stable. +func sortByFreq(data []literalNode) { + n := len(data) + quickSortByFreq(data, 0, n, maxDepth(n)) +} + +func quickSortByFreq(data []literalNode, a, b, maxDepth int) { + for b-a > 12 { // Use ShellSort for slices <= 12 elements + if maxDepth == 0 { + heapSort(data, a, b) + return + } + maxDepth-- + mlo, mhi := doPivotByFreq(data, a, b) + // Avoiding recursion on the larger subproblem guarantees + // a stack depth of at most lg(b-a). + if mlo-a < b-mhi { + quickSortByFreq(data, a, mlo, maxDepth) + a = mhi // i.e., quickSortByFreq(data, mhi, b) + } else { + quickSortByFreq(data, mhi, b, maxDepth) + b = mlo // i.e., quickSortByFreq(data, a, mlo) + } + } + if b-a > 1 { + // Do ShellSort pass with gap 6 + // It could be written in this simplified form cause b-a <= 12 + for i := a + 6; i < b; i++ { + if data[i].freq == data[i-6].freq && data[i].literal < data[i-6].literal || data[i].freq < data[i-6].freq { + data[i], data[i-6] = data[i-6], data[i] + } + } + insertionSortByFreq(data, a, b) + } +} + +// siftDownByFreq implements the heap property on data[lo, hi). +// first is an offset into the array where the root of the heap lies. +func siftDownByFreq(data []literalNode, lo, hi, first int) { + root := lo + for { + child := 2*root + 1 + if child >= hi { + break + } + if child+1 < hi && (data[first+child].freq == data[first+child+1].freq && data[first+child].literal < data[first+child+1].literal || data[first+child].freq < data[first+child+1].freq) { + child++ + } + if data[first+root].freq == data[first+child].freq && data[first+root].literal > data[first+child].literal || data[first+root].freq > data[first+child].freq { + return + } + data[first+root], data[first+child] = data[first+child], data[first+root] + root = child + } +} +func doPivotByFreq(data []literalNode, lo, hi int) (midlo, midhi int) { + m := int(uint(lo+hi) >> 1) // Written like this to avoid integer overflow. + if hi-lo > 40 { + // Tukey's ``Ninther,'' median of three medians of three. + s := (hi - lo) / 8 + medianOfThreeSortByFreq(data, lo, lo+s, lo+2*s) + medianOfThreeSortByFreq(data, m, m-s, m+s) + medianOfThreeSortByFreq(data, hi-1, hi-1-s, hi-1-2*s) + } + medianOfThreeSortByFreq(data, lo, m, hi-1) + + // Invariants are: + // data[lo] = pivot (set up by ChoosePivot) + // data[lo < i < a] < pivot + // data[a <= i < b] <= pivot + // data[b <= i < c] unexamined + // data[c <= i < hi-1] > pivot + // data[hi-1] >= pivot + pivot := lo + a, c := lo+1, hi-1 + + for ; a < c && (data[a].freq == data[pivot].freq && data[a].literal < data[pivot].literal || data[a].freq < data[pivot].freq); a++ { + } + b := a + for { + for ; b < c && (data[pivot].freq == data[b].freq && data[pivot].literal > data[b].literal || data[pivot].freq > data[b].freq); b++ { // data[b] <= pivot + } + for ; b < c && (data[pivot].freq == data[c-1].freq && data[pivot].literal < data[c-1].literal || data[pivot].freq < data[c-1].freq); c-- { // data[c-1] > pivot + } + if b >= c { + break + } + // data[b] > pivot; data[c-1] <= pivot + data[b], data[c-1] = data[c-1], data[b] + b++ + c-- + } + // If hi-c<3 then there are duplicates (by property of median of nine). + // Let's be a bit more conservative, and set border to 5. + protect := hi-c < 5 + if !protect && hi-c < (hi-lo)/4 { + // Lets test some points for equality to pivot + dups := 0 + if data[pivot].freq == data[hi-1].freq && data[pivot].literal > data[hi-1].literal || data[pivot].freq > data[hi-1].freq { // data[hi-1] = pivot + data[c], data[hi-1] = data[hi-1], data[c] + c++ + dups++ + } + if data[b-1].freq == data[pivot].freq && data[b-1].literal > data[pivot].literal || data[b-1].freq > data[pivot].freq { // data[b-1] = pivot + b-- + dups++ + } + // m-lo = (hi-lo)/2 > 6 + // b-lo > (hi-lo)*3/4-1 > 8 + // ==> m < b ==> data[m] <= pivot + if data[m].freq == data[pivot].freq && data[m].literal > data[pivot].literal || data[m].freq > data[pivot].freq { // data[m] = pivot + data[m], data[b-1] = data[b-1], data[m] + b-- + dups++ + } + // if at least 2 points are equal to pivot, assume skewed distribution + protect = dups > 1 + } + if protect { + // Protect against a lot of duplicates + // Add invariant: + // data[a <= i < b] unexamined + // data[b <= i < c] = pivot + for { + for ; a < b && (data[b-1].freq == data[pivot].freq && data[b-1].literal > data[pivot].literal || data[b-1].freq > data[pivot].freq); b-- { // data[b] == pivot + } + for ; a < b && (data[a].freq == data[pivot].freq && data[a].literal < data[pivot].literal || data[a].freq < data[pivot].freq); a++ { // data[a] < pivot + } + if a >= b { + break + } + // data[a] == pivot; data[b-1] < pivot + data[a], data[b-1] = data[b-1], data[a] + a++ + b-- + } + } + // Swap pivot into middle + data[pivot], data[b-1] = data[b-1], data[pivot] + return b - 1, c +} + +// Insertion sort +func insertionSortByFreq(data []literalNode, a, b int) { + for i := a + 1; i < b; i++ { + for j := i; j > a && (data[j].freq == data[j-1].freq && data[j].literal < data[j-1].literal || data[j].freq < data[j-1].freq); j-- { + data[j], data[j-1] = data[j-1], data[j] + } + } +} + +// quickSortByFreq, loosely following Bentley and McIlroy, +// ``Engineering a Sort Function,'' SP&E November 1993. + +// medianOfThreeSortByFreq moves the median of the three values data[m0], data[m1], data[m2] into data[m1]. +func medianOfThreeSortByFreq(data []literalNode, m1, m0, m2 int) { + // sort 3 elements + if data[m1].freq == data[m0].freq && data[m1].literal < data[m0].literal || data[m1].freq < data[m0].freq { + data[m1], data[m0] = data[m0], data[m1] + } + // data[m0] <= data[m1] + if data[m2].freq == data[m1].freq && data[m2].literal < data[m1].literal || data[m2].freq < data[m1].freq { + data[m2], data[m1] = data[m1], data[m2] + // data[m0] <= data[m2] && data[m1] < data[m2] + if data[m1].freq == data[m0].freq && data[m1].literal < data[m0].literal || data[m1].freq < data[m0].freq { + data[m1], data[m0] = data[m0], data[m1] + } + } + // now data[m0] <= data[m1] <= data[m2] +} diff --git a/github.com/klauspost/compress/flate/huffman_sortByLiteral.go b/github.com/klauspost/compress/flate/huffman_sortByLiteral.go new file mode 100644 index 0000000..93f1aea --- /dev/null +++ b/github.com/klauspost/compress/flate/huffman_sortByLiteral.go @@ -0,0 +1,201 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package flate + +// Sort sorts data. +// It makes one call to data.Len to determine n, and O(n*log(n)) calls to +// data.Less and data.Swap. The sort is not guaranteed to be stable. +func sortByLiteral(data []literalNode) { + n := len(data) + quickSort(data, 0, n, maxDepth(n)) +} + +func quickSort(data []literalNode, a, b, maxDepth int) { + for b-a > 12 { // Use ShellSort for slices <= 12 elements + if maxDepth == 0 { + heapSort(data, a, b) + return + } + maxDepth-- + mlo, mhi := doPivot(data, a, b) + // Avoiding recursion on the larger subproblem guarantees + // a stack depth of at most lg(b-a). + if mlo-a < b-mhi { + quickSort(data, a, mlo, maxDepth) + a = mhi // i.e., quickSort(data, mhi, b) + } else { + quickSort(data, mhi, b, maxDepth) + b = mlo // i.e., quickSort(data, a, mlo) + } + } + if b-a > 1 { + // Do ShellSort pass with gap 6 + // It could be written in this simplified form cause b-a <= 12 + for i := a + 6; i < b; i++ { + if data[i].literal < data[i-6].literal { + data[i], data[i-6] = data[i-6], data[i] + } + } + insertionSort(data, a, b) + } +} +func heapSort(data []literalNode, a, b int) { + first := a + lo := 0 + hi := b - a + + // Build heap with greatest element at top. + for i := (hi - 1) / 2; i >= 0; i-- { + siftDown(data, i, hi, first) + } + + // Pop elements, largest first, into end of data. + for i := hi - 1; i >= 0; i-- { + data[first], data[first+i] = data[first+i], data[first] + siftDown(data, lo, i, first) + } +} + +// siftDown implements the heap property on data[lo, hi). +// first is an offset into the array where the root of the heap lies. +func siftDown(data []literalNode, lo, hi, first int) { + root := lo + for { + child := 2*root + 1 + if child >= hi { + break + } + if child+1 < hi && data[first+child].literal < data[first+child+1].literal { + child++ + } + if data[first+root].literal > data[first+child].literal { + return + } + data[first+root], data[first+child] = data[first+child], data[first+root] + root = child + } +} +func doPivot(data []literalNode, lo, hi int) (midlo, midhi int) { + m := int(uint(lo+hi) >> 1) // Written like this to avoid integer overflow. + if hi-lo > 40 { + // Tukey's ``Ninther,'' median of three medians of three. + s := (hi - lo) / 8 + medianOfThree(data, lo, lo+s, lo+2*s) + medianOfThree(data, m, m-s, m+s) + medianOfThree(data, hi-1, hi-1-s, hi-1-2*s) + } + medianOfThree(data, lo, m, hi-1) + + // Invariants are: + // data[lo] = pivot (set up by ChoosePivot) + // data[lo < i < a] < pivot + // data[a <= i < b] <= pivot + // data[b <= i < c] unexamined + // data[c <= i < hi-1] > pivot + // data[hi-1] >= pivot + pivot := lo + a, c := lo+1, hi-1 + + for ; a < c && data[a].literal < data[pivot].literal; a++ { + } + b := a + for { + for ; b < c && data[pivot].literal > data[b].literal; b++ { // data[b] <= pivot + } + for ; b < c && data[pivot].literal < data[c-1].literal; c-- { // data[c-1] > pivot + } + if b >= c { + break + } + // data[b] > pivot; data[c-1] <= pivot + data[b], data[c-1] = data[c-1], data[b] + b++ + c-- + } + // If hi-c<3 then there are duplicates (by property of median of nine). + // Let's be a bit more conservative, and set border to 5. + protect := hi-c < 5 + if !protect && hi-c < (hi-lo)/4 { + // Lets test some points for equality to pivot + dups := 0 + if data[pivot].literal > data[hi-1].literal { // data[hi-1] = pivot + data[c], data[hi-1] = data[hi-1], data[c] + c++ + dups++ + } + if data[b-1].literal > data[pivot].literal { // data[b-1] = pivot + b-- + dups++ + } + // m-lo = (hi-lo)/2 > 6 + // b-lo > (hi-lo)*3/4-1 > 8 + // ==> m < b ==> data[m] <= pivot + if data[m].literal > data[pivot].literal { // data[m] = pivot + data[m], data[b-1] = data[b-1], data[m] + b-- + dups++ + } + // if at least 2 points are equal to pivot, assume skewed distribution + protect = dups > 1 + } + if protect { + // Protect against a lot of duplicates + // Add invariant: + // data[a <= i < b] unexamined + // data[b <= i < c] = pivot + for { + for ; a < b && data[b-1].literal > data[pivot].literal; b-- { // data[b] == pivot + } + for ; a < b && data[a].literal < data[pivot].literal; a++ { // data[a] < pivot + } + if a >= b { + break + } + // data[a] == pivot; data[b-1] < pivot + data[a], data[b-1] = data[b-1], data[a] + a++ + b-- + } + } + // Swap pivot into middle + data[pivot], data[b-1] = data[b-1], data[pivot] + return b - 1, c +} + +// Insertion sort +func insertionSort(data []literalNode, a, b int) { + for i := a + 1; i < b; i++ { + for j := i; j > a && data[j].literal < data[j-1].literal; j-- { + data[j], data[j-1] = data[j-1], data[j] + } + } +} + +// maxDepth returns a threshold at which quicksort should switch +// to heapsort. It returns 2*ceil(lg(n+1)). +func maxDepth(n int) int { + var depth int + for i := n; i > 0; i >>= 1 { + depth++ + } + return depth * 2 +} + +// medianOfThree moves the median of the three values data[m0], data[m1], data[m2] into data[m1]. +func medianOfThree(data []literalNode, m1, m0, m2 int) { + // sort 3 elements + if data[m1].literal < data[m0].literal { + data[m1], data[m0] = data[m0], data[m1] + } + // data[m0] <= data[m1] + if data[m2].literal < data[m1].literal { + data[m2], data[m1] = data[m1], data[m2] + // data[m0] <= data[m2] && data[m1] < data[m2] + if data[m1].literal < data[m0].literal { + data[m1], data[m0] = data[m0], data[m1] + } + } + // now data[m0] <= data[m1] <= data[m2] +} diff --git a/github.com/klauspost/compress/flate/inflate.go b/github.com/klauspost/compress/flate/inflate.go new file mode 100644 index 0000000..3e4259f --- /dev/null +++ b/github.com/klauspost/compress/flate/inflate.go @@ -0,0 +1,1001 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package flate implements the DEFLATE compressed data format, described in +// RFC 1951. The gzip and zlib packages implement access to DEFLATE-based file +// formats. +package flate + +import ( + "bufio" + "fmt" + "io" + "math/bits" + "strconv" + "sync" +) + +const ( + maxCodeLen = 16 // max length of Huffman code + maxCodeLenMask = 15 // mask for max length of Huffman code + // The next three numbers come from the RFC section 3.2.7, with the + // additional proviso in section 3.2.5 which implies that distance codes + // 30 and 31 should never occur in compressed data. + maxNumLit = 286 + maxNumDist = 30 + numCodes = 19 // number of codes in Huffman meta-code + + debugDecode = false +) + +// Initialize the fixedHuffmanDecoder only once upon first use. +var fixedOnce sync.Once +var fixedHuffmanDecoder huffmanDecoder + +// A CorruptInputError reports the presence of corrupt input at a given offset. +type CorruptInputError int64 + +func (e CorruptInputError) Error() string { + return "flate: corrupt input before offset " + strconv.FormatInt(int64(e), 10) +} + +// An InternalError reports an error in the flate code itself. +type InternalError string + +func (e InternalError) Error() string { return "flate: internal error: " + string(e) } + +// A ReadError reports an error encountered while reading input. +// +// Deprecated: No longer returned. +type ReadError struct { + Offset int64 // byte offset where error occurred + Err error // error returned by underlying Read +} + +func (e *ReadError) Error() string { + return "flate: read error at offset " + strconv.FormatInt(e.Offset, 10) + ": " + e.Err.Error() +} + +// A WriteError reports an error encountered while writing output. +// +// Deprecated: No longer returned. +type WriteError struct { + Offset int64 // byte offset where error occurred + Err error // error returned by underlying Write +} + +func (e *WriteError) Error() string { + return "flate: write error at offset " + strconv.FormatInt(e.Offset, 10) + ": " + e.Err.Error() +} + +// Resetter resets a ReadCloser returned by NewReader or NewReaderDict to +// to switch to a new underlying Reader. This permits reusing a ReadCloser +// instead of allocating a new one. +type Resetter interface { + // Reset discards any buffered data and resets the Resetter as if it was + // newly initialized with the given reader. + Reset(r io.Reader, dict []byte) error +} + +// The data structure for decoding Huffman tables is based on that of +// zlib. There is a lookup table of a fixed bit width (huffmanChunkBits), +// For codes smaller than the table width, there are multiple entries +// (each combination of trailing bits has the same value). For codes +// larger than the table width, the table contains a link to an overflow +// table. The width of each entry in the link table is the maximum code +// size minus the chunk width. +// +// Note that you can do a lookup in the table even without all bits +// filled. Since the extra bits are zero, and the DEFLATE Huffman codes +// have the property that shorter codes come before longer ones, the +// bit length estimate in the result is a lower bound on the actual +// number of bits. +// +// See the following: +// http://www.gzip.org/algorithm.txt + +// chunk & 15 is number of bits +// chunk >> 4 is value, including table link + +const ( + huffmanChunkBits = 9 + huffmanNumChunks = 1 << huffmanChunkBits + huffmanCountMask = 15 + huffmanValueShift = 4 +) + +type huffmanDecoder struct { + maxRead int // the maximum number of bits we can read and not overread + chunks *[huffmanNumChunks]uint16 // chunks as described above + links [][]uint16 // overflow links + linkMask uint32 // mask the width of the link table +} + +// Initialize Huffman decoding tables from array of code lengths. +// Following this function, h is guaranteed to be initialized into a complete +// tree (i.e., neither over-subscribed nor under-subscribed). The exception is a +// degenerate case where the tree has only a single symbol with length 1. Empty +// trees are permitted. +func (h *huffmanDecoder) init(lengths []int) bool { + // Sanity enables additional runtime tests during Huffman + // table construction. It's intended to be used during + // development to supplement the currently ad-hoc unit tests. + const sanity = false + + if h.chunks == nil { + h.chunks = &[huffmanNumChunks]uint16{} + } + if h.maxRead != 0 { + *h = huffmanDecoder{chunks: h.chunks, links: h.links} + } + + // Count number of codes of each length, + // compute maxRead and max length. + var count [maxCodeLen]int + var min, max int + for _, n := range lengths { + if n == 0 { + continue + } + if min == 0 || n < min { + min = n + } + if n > max { + max = n + } + count[n&maxCodeLenMask]++ + } + + // Empty tree. The decompressor.huffSym function will fail later if the tree + // is used. Technically, an empty tree is only valid for the HDIST tree and + // not the HCLEN and HLIT tree. However, a stream with an empty HCLEN tree + // is guaranteed to fail since it will attempt to use the tree to decode the + // codes for the HLIT and HDIST trees. Similarly, an empty HLIT tree is + // guaranteed to fail later since the compressed data section must be + // composed of at least one symbol (the end-of-block marker). + if max == 0 { + return true + } + + code := 0 + var nextcode [maxCodeLen]int + for i := min; i <= max; i++ { + code <<= 1 + nextcode[i&maxCodeLenMask] = code + code += count[i&maxCodeLenMask] + } + + // Check that the coding is complete (i.e., that we've + // assigned all 2-to-the-max possible bit sequences). + // Exception: To be compatible with zlib, we also need to + // accept degenerate single-code codings. See also + // TestDegenerateHuffmanCoding. + if code != 1< huffmanChunkBits { + numLinks := 1 << (uint(max) - huffmanChunkBits) + h.linkMask = uint32(numLinks - 1) + + // create link tables + link := nextcode[huffmanChunkBits+1] >> 1 + if cap(h.links) < huffmanNumChunks-link { + h.links = make([][]uint16, huffmanNumChunks-link) + } else { + h.links = h.links[:huffmanNumChunks-link] + } + for j := uint(link); j < huffmanNumChunks; j++ { + reverse := int(bits.Reverse16(uint16(j))) + reverse >>= uint(16 - huffmanChunkBits) + off := j - uint(link) + if sanity && h.chunks[reverse] != 0 { + panic("impossible: overwriting existing chunk") + } + h.chunks[reverse] = uint16(off<>= uint(16 - n) + if n <= huffmanChunkBits { + for off := reverse; off < len(h.chunks); off += 1 << uint(n) { + // We should never need to overwrite + // an existing chunk. Also, 0 is + // never a valid chunk, because the + // lower 4 "count" bits should be + // between 1 and 15. + if sanity && h.chunks[off] != 0 { + panic("impossible: overwriting existing chunk") + } + h.chunks[off] = chunk + } + } else { + j := reverse & (huffmanNumChunks - 1) + if sanity && h.chunks[j]&huffmanCountMask != huffmanChunkBits+1 { + // Longer codes should have been + // associated with a link table above. + panic("impossible: not an indirect chunk") + } + value := h.chunks[j] >> huffmanValueShift + linktab := h.links[value] + reverse >>= huffmanChunkBits + for off := reverse; off < len(linktab); off += 1 << uint(n-huffmanChunkBits) { + if sanity && linktab[off] != 0 { + panic("impossible: overwriting existing chunk") + } + linktab[off] = chunk + } + } + } + + if sanity { + // Above we've sanity checked that we never overwrote + // an existing entry. Here we additionally check that + // we filled the tables completely. + for i, chunk := range h.chunks { + if chunk == 0 { + // As an exception, in the degenerate + // single-code case, we allow odd + // chunks to be missing. + if code == 1 && i%2 == 1 { + continue + } + panic("impossible: missing chunk") + } + } + for _, linktab := range h.links { + for _, chunk := range linktab { + if chunk == 0 { + panic("impossible: missing chunk") + } + } + } + } + + return true +} + +// The actual read interface needed by NewReader. +// If the passed in io.Reader does not also have ReadByte, +// the NewReader will introduce its own buffering. +type Reader interface { + io.Reader + io.ByteReader +} + +// Decompress state. +type decompressor struct { + // Input source. + r Reader + roffset int64 + + // Huffman decoders for literal/length, distance. + h1, h2 huffmanDecoder + + // Length arrays used to define Huffman codes. + bits *[maxNumLit + maxNumDist]int + codebits *[numCodes]int + + // Output history, buffer. + dict dictDecoder + + // Next step in the decompression, + // and decompression state. + step func(*decompressor) + stepState int + err error + toRead []byte + hl, hd *huffmanDecoder + copyLen int + copyDist int + + // Temporary buffer (avoids repeated allocation). + buf [4]byte + + // Input bits, in top of b. + b uint32 + + nb uint + final bool +} + +func (f *decompressor) nextBlock() { + for f.nb < 1+2 { + if f.err = f.moreBits(); f.err != nil { + return + } + } + f.final = f.b&1 == 1 + f.b >>= 1 + typ := f.b & 3 + f.b >>= 2 + f.nb -= 1 + 2 + switch typ { + case 0: + f.dataBlock() + case 1: + // compressed, fixed Huffman tables + f.hl = &fixedHuffmanDecoder + f.hd = nil + f.huffmanBlockDecoder()() + case 2: + // compressed, dynamic Huffman tables + if f.err = f.readHuffman(); f.err != nil { + break + } + f.hl = &f.h1 + f.hd = &f.h2 + f.huffmanBlockDecoder()() + default: + // 3 is reserved. + if debugDecode { + fmt.Println("reserved data block encountered") + } + f.err = CorruptInputError(f.roffset) + } +} + +func (f *decompressor) Read(b []byte) (int, error) { + for { + if len(f.toRead) > 0 { + n := copy(b, f.toRead) + f.toRead = f.toRead[n:] + if len(f.toRead) == 0 { + return n, f.err + } + return n, nil + } + if f.err != nil { + return 0, f.err + } + f.step(f) + if f.err != nil && len(f.toRead) == 0 { + f.toRead = f.dict.readFlush() // Flush what's left in case of error + } + } +} + +// Support the io.WriteTo interface for io.Copy and friends. +func (f *decompressor) WriteTo(w io.Writer) (int64, error) { + total := int64(0) + flushed := false + for { + if len(f.toRead) > 0 { + n, err := w.Write(f.toRead) + total += int64(n) + if err != nil { + f.err = err + return total, err + } + if n != len(f.toRead) { + return total, io.ErrShortWrite + } + f.toRead = f.toRead[:0] + } + if f.err != nil && flushed { + if f.err == io.EOF { + return total, nil + } + return total, f.err + } + if f.err == nil { + f.step(f) + } + if len(f.toRead) == 0 && f.err != nil && !flushed { + f.toRead = f.dict.readFlush() // Flush what's left in case of error + flushed = true + } + } +} + +func (f *decompressor) Close() error { + if f.err == io.EOF { + return nil + } + return f.err +} + +// RFC 1951 section 3.2.7. +// Compression with dynamic Huffman codes + +var codeOrder = [...]int{16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15} + +func (f *decompressor) readHuffman() error { + // HLIT[5], HDIST[5], HCLEN[4]. + for f.nb < 5+5+4 { + if err := f.moreBits(); err != nil { + return err + } + } + nlit := int(f.b&0x1F) + 257 + if nlit > maxNumLit { + if debugDecode { + fmt.Println("nlit > maxNumLit", nlit) + } + return CorruptInputError(f.roffset) + } + f.b >>= 5 + ndist := int(f.b&0x1F) + 1 + if ndist > maxNumDist { + if debugDecode { + fmt.Println("ndist > maxNumDist", ndist) + } + return CorruptInputError(f.roffset) + } + f.b >>= 5 + nclen := int(f.b&0xF) + 4 + // numCodes is 19, so nclen is always valid. + f.b >>= 4 + f.nb -= 5 + 5 + 4 + + // (HCLEN+4)*3 bits: code lengths in the magic codeOrder order. + for i := 0; i < nclen; i++ { + for f.nb < 3 { + if err := f.moreBits(); err != nil { + return err + } + } + f.codebits[codeOrder[i]] = int(f.b & 0x7) + f.b >>= 3 + f.nb -= 3 + } + for i := nclen; i < len(codeOrder); i++ { + f.codebits[codeOrder[i]] = 0 + } + if !f.h1.init(f.codebits[0:]) { + if debugDecode { + fmt.Println("init codebits failed") + } + return CorruptInputError(f.roffset) + } + + // HLIT + 257 code lengths, HDIST + 1 code lengths, + // using the code length Huffman code. + for i, n := 0, nlit+ndist; i < n; { + x, err := f.huffSym(&f.h1) + if err != nil { + return err + } + if x < 16 { + // Actual length. + f.bits[i] = x + i++ + continue + } + // Repeat previous length or zero. + var rep int + var nb uint + var b int + switch x { + default: + return InternalError("unexpected length code") + case 16: + rep = 3 + nb = 2 + if i == 0 { + if debugDecode { + fmt.Println("i==0") + } + return CorruptInputError(f.roffset) + } + b = f.bits[i-1] + case 17: + rep = 3 + nb = 3 + b = 0 + case 18: + rep = 11 + nb = 7 + b = 0 + } + for f.nb < nb { + if err := f.moreBits(); err != nil { + if debugDecode { + fmt.Println("morebits:", err) + } + return err + } + } + rep += int(f.b & uint32(1<>= nb + f.nb -= nb + if i+rep > n { + if debugDecode { + fmt.Println("i+rep > n", i, rep, n) + } + return CorruptInputError(f.roffset) + } + for j := 0; j < rep; j++ { + f.bits[i] = b + i++ + } + } + + if !f.h1.init(f.bits[0:nlit]) || !f.h2.init(f.bits[nlit:nlit+ndist]) { + if debugDecode { + fmt.Println("init2 failed") + } + return CorruptInputError(f.roffset) + } + + // As an optimization, we can initialize the maxRead bits to read at a time + // for the HLIT tree to the length of the EOB marker since we know that + // every block must terminate with one. This preserves the property that + // we never read any extra bytes after the end of the DEFLATE stream. + if f.h1.maxRead < f.bits[endBlockMarker] { + f.h1.maxRead = f.bits[endBlockMarker] + } + if !f.final { + // If not the final block, the smallest block possible is + // a predefined table, BTYPE=01, with a single EOB marker. + // This will take up 3 + 7 bits. + f.h1.maxRead += 10 + } + + return nil +} + +// Decode a single Huffman block from f. +// hl and hd are the Huffman states for the lit/length values +// and the distance values, respectively. If hd == nil, using the +// fixed distance encoding associated with fixed Huffman blocks. +func (f *decompressor) huffmanBlockGeneric() { + const ( + stateInit = iota // Zero value must be stateInit + stateDict + ) + + switch f.stepState { + case stateInit: + goto readLiteral + case stateDict: + goto copyHistory + } + +readLiteral: + // Read literal and/or (length, distance) according to RFC section 3.2.3. + { + var v int + { + // Inlined v, err := f.huffSym(f.hl) + // Since a huffmanDecoder can be empty or be composed of a degenerate tree + // with single element, huffSym must error on these two edge cases. In both + // cases, the chunks slice will be 0 for the invalid sequence, leading it + // satisfy the n == 0 check below. + n := uint(f.hl.maxRead) + // Optimization. Compiler isn't smart enough to keep f.b,f.nb in registers, + // but is smart enough to keep local variables in registers, so use nb and b, + // inline call to moreBits and reassign b,nb back to f on return. + nb, b := f.nb, f.b + for { + for nb < n { + c, err := f.r.ReadByte() + if err != nil { + f.b = b + f.nb = nb + f.err = noEOF(err) + return + } + f.roffset++ + b |= uint32(c) << (nb & 31) + nb += 8 + } + chunk := f.hl.chunks[b&(huffmanNumChunks-1)] + n = uint(chunk & huffmanCountMask) + if n > huffmanChunkBits { + chunk = f.hl.links[chunk>>huffmanValueShift][(b>>huffmanChunkBits)&f.hl.linkMask] + n = uint(chunk & huffmanCountMask) + } + if n <= nb { + if n == 0 { + f.b = b + f.nb = nb + if debugDecode { + fmt.Println("huffsym: n==0") + } + f.err = CorruptInputError(f.roffset) + return + } + f.b = b >> (n & 31) + f.nb = nb - n + v = int(chunk >> huffmanValueShift) + break + } + } + } + + var n uint // number of bits extra + var length int + var err error + switch { + case v < 256: + f.dict.writeByte(byte(v)) + if f.dict.availWrite() == 0 { + f.toRead = f.dict.readFlush() + f.step = (*decompressor).huffmanBlockGeneric + f.stepState = stateInit + return + } + goto readLiteral + case v == 256: + f.finishBlock() + return + // otherwise, reference to older data + case v < 265: + length = v - (257 - 3) + n = 0 + case v < 269: + length = v*2 - (265*2 - 11) + n = 1 + case v < 273: + length = v*4 - (269*4 - 19) + n = 2 + case v < 277: + length = v*8 - (273*8 - 35) + n = 3 + case v < 281: + length = v*16 - (277*16 - 67) + n = 4 + case v < 285: + length = v*32 - (281*32 - 131) + n = 5 + case v < maxNumLit: + length = 258 + n = 0 + default: + if debugDecode { + fmt.Println(v, ">= maxNumLit") + } + f.err = CorruptInputError(f.roffset) + return + } + if n > 0 { + for f.nb < n { + if err = f.moreBits(); err != nil { + if debugDecode { + fmt.Println("morebits n>0:", err) + } + f.err = err + return + } + } + length += int(f.b & uint32(1<>= n + f.nb -= n + } + + var dist int + if f.hd == nil { + for f.nb < 5 { + if err = f.moreBits(); err != nil { + if debugDecode { + fmt.Println("morebits f.nb<5:", err) + } + f.err = err + return + } + } + dist = int(bits.Reverse8(uint8(f.b & 0x1F << 3))) + f.b >>= 5 + f.nb -= 5 + } else { + if dist, err = f.huffSym(f.hd); err != nil { + if debugDecode { + fmt.Println("huffsym:", err) + } + f.err = err + return + } + } + + switch { + case dist < 4: + dist++ + case dist < maxNumDist: + nb := uint(dist-2) >> 1 + // have 1 bit in bottom of dist, need nb more. + extra := (dist & 1) << nb + for f.nb < nb { + if err = f.moreBits(); err != nil { + if debugDecode { + fmt.Println("morebits f.nb>= nb + f.nb -= nb + dist = 1<<(nb+1) + 1 + extra + default: + if debugDecode { + fmt.Println("dist too big:", dist, maxNumDist) + } + f.err = CorruptInputError(f.roffset) + return + } + + // No check on length; encoding can be prescient. + if dist > f.dict.histSize() { + if debugDecode { + fmt.Println("dist > f.dict.histSize():", dist, f.dict.histSize()) + } + f.err = CorruptInputError(f.roffset) + return + } + + f.copyLen, f.copyDist = length, dist + goto copyHistory + } + +copyHistory: + // Perform a backwards copy according to RFC section 3.2.3. + { + cnt := f.dict.tryWriteCopy(f.copyDist, f.copyLen) + if cnt == 0 { + cnt = f.dict.writeCopy(f.copyDist, f.copyLen) + } + f.copyLen -= cnt + + if f.dict.availWrite() == 0 || f.copyLen > 0 { + f.toRead = f.dict.readFlush() + f.step = (*decompressor).huffmanBlockGeneric // We need to continue this work + f.stepState = stateDict + return + } + goto readLiteral + } +} + +// Copy a single uncompressed data block from input to output. +func (f *decompressor) dataBlock() { + // Uncompressed. + // Discard current half-byte. + left := (f.nb) & 7 + f.nb -= left + f.b >>= left + + offBytes := f.nb >> 3 + // Unfilled values will be overwritten. + f.buf[0] = uint8(f.b) + f.buf[1] = uint8(f.b >> 8) + f.buf[2] = uint8(f.b >> 16) + f.buf[3] = uint8(f.b >> 24) + + f.roffset += int64(offBytes) + f.nb, f.b = 0, 0 + + // Length then ones-complement of length. + nr, err := io.ReadFull(f.r, f.buf[offBytes:4]) + f.roffset += int64(nr) + if err != nil { + f.err = noEOF(err) + return + } + n := uint16(f.buf[0]) | uint16(f.buf[1])<<8 + nn := uint16(f.buf[2]) | uint16(f.buf[3])<<8 + if nn != ^n { + if debugDecode { + ncomp := ^n + fmt.Println("uint16(nn) != uint16(^n)", nn, ncomp) + } + f.err = CorruptInputError(f.roffset) + return + } + + if n == 0 { + f.toRead = f.dict.readFlush() + f.finishBlock() + return + } + + f.copyLen = int(n) + f.copyData() +} + +// copyData copies f.copyLen bytes from the underlying reader into f.hist. +// It pauses for reads when f.hist is full. +func (f *decompressor) copyData() { + buf := f.dict.writeSlice() + if len(buf) > f.copyLen { + buf = buf[:f.copyLen] + } + + cnt, err := io.ReadFull(f.r, buf) + f.roffset += int64(cnt) + f.copyLen -= cnt + f.dict.writeMark(cnt) + if err != nil { + f.err = noEOF(err) + return + } + + if f.dict.availWrite() == 0 || f.copyLen > 0 { + f.toRead = f.dict.readFlush() + f.step = (*decompressor).copyData + return + } + f.finishBlock() +} + +func (f *decompressor) finishBlock() { + if f.final { + if f.dict.availRead() > 0 { + f.toRead = f.dict.readFlush() + } + f.err = io.EOF + } + f.step = (*decompressor).nextBlock +} + +// noEOF returns err, unless err == io.EOF, in which case it returns io.ErrUnexpectedEOF. +func noEOF(e error) error { + if e == io.EOF { + return io.ErrUnexpectedEOF + } + return e +} + +func (f *decompressor) moreBits() error { + c, err := f.r.ReadByte() + if err != nil { + return noEOF(err) + } + f.roffset++ + f.b |= uint32(c) << f.nb + f.nb += 8 + return nil +} + +// Read the next Huffman-encoded symbol from f according to h. +func (f *decompressor) huffSym(h *huffmanDecoder) (int, error) { + // Since a huffmanDecoder can be empty or be composed of a degenerate tree + // with single element, huffSym must error on these two edge cases. In both + // cases, the chunks slice will be 0 for the invalid sequence, leading it + // satisfy the n == 0 check below. + n := uint(h.maxRead) + // Optimization. Compiler isn't smart enough to keep f.b,f.nb in registers, + // but is smart enough to keep local variables in registers, so use nb and b, + // inline call to moreBits and reassign b,nb back to f on return. + nb, b := f.nb, f.b + for { + for nb < n { + c, err := f.r.ReadByte() + if err != nil { + f.b = b + f.nb = nb + return 0, noEOF(err) + } + f.roffset++ + b |= uint32(c) << (nb & 31) + nb += 8 + } + chunk := h.chunks[b&(huffmanNumChunks-1)] + n = uint(chunk & huffmanCountMask) + if n > huffmanChunkBits { + chunk = h.links[chunk>>huffmanValueShift][(b>>huffmanChunkBits)&h.linkMask] + n = uint(chunk & huffmanCountMask) + } + if n <= nb { + if n == 0 { + f.b = b + f.nb = nb + if debugDecode { + fmt.Println("huffsym: n==0") + } + f.err = CorruptInputError(f.roffset) + return 0, f.err + } + f.b = b >> (n & 31) + f.nb = nb - n + return int(chunk >> huffmanValueShift), nil + } + } +} + +func makeReader(r io.Reader) Reader { + if rr, ok := r.(Reader); ok { + return rr + } + return bufio.NewReader(r) +} + +func fixedHuffmanDecoderInit() { + fixedOnce.Do(func() { + // These come from the RFC section 3.2.6. + var bits [288]int + for i := 0; i < 144; i++ { + bits[i] = 8 + } + for i := 144; i < 256; i++ { + bits[i] = 9 + } + for i := 256; i < 280; i++ { + bits[i] = 7 + } + for i := 280; i < 288; i++ { + bits[i] = 8 + } + fixedHuffmanDecoder.init(bits[:]) + }) +} + +func (f *decompressor) Reset(r io.Reader, dict []byte) error { + *f = decompressor{ + r: makeReader(r), + bits: f.bits, + codebits: f.codebits, + h1: f.h1, + h2: f.h2, + dict: f.dict, + step: (*decompressor).nextBlock, + } + f.dict.init(maxMatchOffset, dict) + return nil +} + +// NewReader returns a new ReadCloser that can be used +// to read the uncompressed version of r. +// If r does not also implement io.ByteReader, +// the decompressor may read more data than necessary from r. +// It is the caller's responsibility to call Close on the ReadCloser +// when finished reading. +// +// The ReadCloser returned by NewReader also implements Resetter. +func NewReader(r io.Reader) io.ReadCloser { + fixedHuffmanDecoderInit() + + var f decompressor + f.r = makeReader(r) + f.bits = new([maxNumLit + maxNumDist]int) + f.codebits = new([numCodes]int) + f.step = (*decompressor).nextBlock + f.dict.init(maxMatchOffset, nil) + return &f +} + +// NewReaderDict is like NewReader but initializes the reader +// with a preset dictionary. The returned Reader behaves as if +// the uncompressed data stream started with the given dictionary, +// which has already been read. NewReaderDict is typically used +// to read data compressed by NewWriterDict. +// +// The ReadCloser returned by NewReader also implements Resetter. +func NewReaderDict(r io.Reader, dict []byte) io.ReadCloser { + fixedHuffmanDecoderInit() + + var f decompressor + f.r = makeReader(r) + f.bits = new([maxNumLit + maxNumDist]int) + f.codebits = new([numCodes]int) + f.step = (*decompressor).nextBlock + f.dict.init(maxMatchOffset, dict) + return &f +} diff --git a/github.com/klauspost/compress/flate/inflate_gen.go b/github.com/klauspost/compress/flate/inflate_gen.go new file mode 100644 index 0000000..397dc1b --- /dev/null +++ b/github.com/klauspost/compress/flate/inflate_gen.go @@ -0,0 +1,922 @@ +// Code generated by go generate gen_inflate.go. DO NOT EDIT. + +package flate + +import ( + "bufio" + "bytes" + "fmt" + "math/bits" + "strings" +) + +// Decode a single Huffman block from f. +// hl and hd are the Huffman states for the lit/length values +// and the distance values, respectively. If hd == nil, using the +// fixed distance encoding associated with fixed Huffman blocks. +func (f *decompressor) huffmanBytesBuffer() { + const ( + stateInit = iota // Zero value must be stateInit + stateDict + ) + fr := f.r.(*bytes.Buffer) + moreBits := func() error { + c, err := fr.ReadByte() + if err != nil { + return noEOF(err) + } + f.roffset++ + f.b |= uint32(c) << f.nb + f.nb += 8 + return nil + } + + switch f.stepState { + case stateInit: + goto readLiteral + case stateDict: + goto copyHistory + } + +readLiteral: + // Read literal and/or (length, distance) according to RFC section 3.2.3. + { + var v int + { + // Inlined v, err := f.huffSym(f.hl) + // Since a huffmanDecoder can be empty or be composed of a degenerate tree + // with single element, huffSym must error on these two edge cases. In both + // cases, the chunks slice will be 0 for the invalid sequence, leading it + // satisfy the n == 0 check below. + n := uint(f.hl.maxRead) + // Optimization. Compiler isn't smart enough to keep f.b,f.nb in registers, + // but is smart enough to keep local variables in registers, so use nb and b, + // inline call to moreBits and reassign b,nb back to f on return. + nb, b := f.nb, f.b + for { + for nb < n { + c, err := fr.ReadByte() + if err != nil { + f.b = b + f.nb = nb + f.err = noEOF(err) + return + } + f.roffset++ + b |= uint32(c) << (nb & 31) + nb += 8 + } + chunk := f.hl.chunks[b&(huffmanNumChunks-1)] + n = uint(chunk & huffmanCountMask) + if n > huffmanChunkBits { + chunk = f.hl.links[chunk>>huffmanValueShift][(b>>huffmanChunkBits)&f.hl.linkMask] + n = uint(chunk & huffmanCountMask) + } + if n <= nb { + if n == 0 { + f.b = b + f.nb = nb + if debugDecode { + fmt.Println("huffsym: n==0") + } + f.err = CorruptInputError(f.roffset) + return + } + f.b = b >> (n & 31) + f.nb = nb - n + v = int(chunk >> huffmanValueShift) + break + } + } + } + + var n uint // number of bits extra + var length int + var err error + switch { + case v < 256: + f.dict.writeByte(byte(v)) + if f.dict.availWrite() == 0 { + f.toRead = f.dict.readFlush() + f.step = (*decompressor).huffmanBytesBuffer + f.stepState = stateInit + return + } + goto readLiteral + case v == 256: + f.finishBlock() + return + // otherwise, reference to older data + case v < 265: + length = v - (257 - 3) + n = 0 + case v < 269: + length = v*2 - (265*2 - 11) + n = 1 + case v < 273: + length = v*4 - (269*4 - 19) + n = 2 + case v < 277: + length = v*8 - (273*8 - 35) + n = 3 + case v < 281: + length = v*16 - (277*16 - 67) + n = 4 + case v < 285: + length = v*32 - (281*32 - 131) + n = 5 + case v < maxNumLit: + length = 258 + n = 0 + default: + if debugDecode { + fmt.Println(v, ">= maxNumLit") + } + f.err = CorruptInputError(f.roffset) + return + } + if n > 0 { + for f.nb < n { + if err = moreBits(); err != nil { + if debugDecode { + fmt.Println("morebits n>0:", err) + } + f.err = err + return + } + } + length += int(f.b & uint32(1<>= n + f.nb -= n + } + + var dist int + if f.hd == nil { + for f.nb < 5 { + if err = moreBits(); err != nil { + if debugDecode { + fmt.Println("morebits f.nb<5:", err) + } + f.err = err + return + } + } + dist = int(bits.Reverse8(uint8(f.b & 0x1F << 3))) + f.b >>= 5 + f.nb -= 5 + } else { + if dist, err = f.huffSym(f.hd); err != nil { + if debugDecode { + fmt.Println("huffsym:", err) + } + f.err = err + return + } + } + + switch { + case dist < 4: + dist++ + case dist < maxNumDist: + nb := uint(dist-2) >> 1 + // have 1 bit in bottom of dist, need nb more. + extra := (dist & 1) << nb + for f.nb < nb { + if err = moreBits(); err != nil { + if debugDecode { + fmt.Println("morebits f.nb>= nb + f.nb -= nb + dist = 1<<(nb+1) + 1 + extra + default: + if debugDecode { + fmt.Println("dist too big:", dist, maxNumDist) + } + f.err = CorruptInputError(f.roffset) + return + } + + // No check on length; encoding can be prescient. + if dist > f.dict.histSize() { + if debugDecode { + fmt.Println("dist > f.dict.histSize():", dist, f.dict.histSize()) + } + f.err = CorruptInputError(f.roffset) + return + } + + f.copyLen, f.copyDist = length, dist + goto copyHistory + } + +copyHistory: + // Perform a backwards copy according to RFC section 3.2.3. + { + cnt := f.dict.tryWriteCopy(f.copyDist, f.copyLen) + if cnt == 0 { + cnt = f.dict.writeCopy(f.copyDist, f.copyLen) + } + f.copyLen -= cnt + + if f.dict.availWrite() == 0 || f.copyLen > 0 { + f.toRead = f.dict.readFlush() + f.step = (*decompressor).huffmanBytesBuffer // We need to continue this work + f.stepState = stateDict + return + } + goto readLiteral + } +} + +// Decode a single Huffman block from f. +// hl and hd are the Huffman states for the lit/length values +// and the distance values, respectively. If hd == nil, using the +// fixed distance encoding associated with fixed Huffman blocks. +func (f *decompressor) huffmanBytesReader() { + const ( + stateInit = iota // Zero value must be stateInit + stateDict + ) + fr := f.r.(*bytes.Reader) + moreBits := func() error { + c, err := fr.ReadByte() + if err != nil { + return noEOF(err) + } + f.roffset++ + f.b |= uint32(c) << f.nb + f.nb += 8 + return nil + } + + switch f.stepState { + case stateInit: + goto readLiteral + case stateDict: + goto copyHistory + } + +readLiteral: + // Read literal and/or (length, distance) according to RFC section 3.2.3. + { + var v int + { + // Inlined v, err := f.huffSym(f.hl) + // Since a huffmanDecoder can be empty or be composed of a degenerate tree + // with single element, huffSym must error on these two edge cases. In both + // cases, the chunks slice will be 0 for the invalid sequence, leading it + // satisfy the n == 0 check below. + n := uint(f.hl.maxRead) + // Optimization. Compiler isn't smart enough to keep f.b,f.nb in registers, + // but is smart enough to keep local variables in registers, so use nb and b, + // inline call to moreBits and reassign b,nb back to f on return. + nb, b := f.nb, f.b + for { + for nb < n { + c, err := fr.ReadByte() + if err != nil { + f.b = b + f.nb = nb + f.err = noEOF(err) + return + } + f.roffset++ + b |= uint32(c) << (nb & 31) + nb += 8 + } + chunk := f.hl.chunks[b&(huffmanNumChunks-1)] + n = uint(chunk & huffmanCountMask) + if n > huffmanChunkBits { + chunk = f.hl.links[chunk>>huffmanValueShift][(b>>huffmanChunkBits)&f.hl.linkMask] + n = uint(chunk & huffmanCountMask) + } + if n <= nb { + if n == 0 { + f.b = b + f.nb = nb + if debugDecode { + fmt.Println("huffsym: n==0") + } + f.err = CorruptInputError(f.roffset) + return + } + f.b = b >> (n & 31) + f.nb = nb - n + v = int(chunk >> huffmanValueShift) + break + } + } + } + + var n uint // number of bits extra + var length int + var err error + switch { + case v < 256: + f.dict.writeByte(byte(v)) + if f.dict.availWrite() == 0 { + f.toRead = f.dict.readFlush() + f.step = (*decompressor).huffmanBytesReader + f.stepState = stateInit + return + } + goto readLiteral + case v == 256: + f.finishBlock() + return + // otherwise, reference to older data + case v < 265: + length = v - (257 - 3) + n = 0 + case v < 269: + length = v*2 - (265*2 - 11) + n = 1 + case v < 273: + length = v*4 - (269*4 - 19) + n = 2 + case v < 277: + length = v*8 - (273*8 - 35) + n = 3 + case v < 281: + length = v*16 - (277*16 - 67) + n = 4 + case v < 285: + length = v*32 - (281*32 - 131) + n = 5 + case v < maxNumLit: + length = 258 + n = 0 + default: + if debugDecode { + fmt.Println(v, ">= maxNumLit") + } + f.err = CorruptInputError(f.roffset) + return + } + if n > 0 { + for f.nb < n { + if err = moreBits(); err != nil { + if debugDecode { + fmt.Println("morebits n>0:", err) + } + f.err = err + return + } + } + length += int(f.b & uint32(1<>= n + f.nb -= n + } + + var dist int + if f.hd == nil { + for f.nb < 5 { + if err = moreBits(); err != nil { + if debugDecode { + fmt.Println("morebits f.nb<5:", err) + } + f.err = err + return + } + } + dist = int(bits.Reverse8(uint8(f.b & 0x1F << 3))) + f.b >>= 5 + f.nb -= 5 + } else { + if dist, err = f.huffSym(f.hd); err != nil { + if debugDecode { + fmt.Println("huffsym:", err) + } + f.err = err + return + } + } + + switch { + case dist < 4: + dist++ + case dist < maxNumDist: + nb := uint(dist-2) >> 1 + // have 1 bit in bottom of dist, need nb more. + extra := (dist & 1) << nb + for f.nb < nb { + if err = moreBits(); err != nil { + if debugDecode { + fmt.Println("morebits f.nb>= nb + f.nb -= nb + dist = 1<<(nb+1) + 1 + extra + default: + if debugDecode { + fmt.Println("dist too big:", dist, maxNumDist) + } + f.err = CorruptInputError(f.roffset) + return + } + + // No check on length; encoding can be prescient. + if dist > f.dict.histSize() { + if debugDecode { + fmt.Println("dist > f.dict.histSize():", dist, f.dict.histSize()) + } + f.err = CorruptInputError(f.roffset) + return + } + + f.copyLen, f.copyDist = length, dist + goto copyHistory + } + +copyHistory: + // Perform a backwards copy according to RFC section 3.2.3. + { + cnt := f.dict.tryWriteCopy(f.copyDist, f.copyLen) + if cnt == 0 { + cnt = f.dict.writeCopy(f.copyDist, f.copyLen) + } + f.copyLen -= cnt + + if f.dict.availWrite() == 0 || f.copyLen > 0 { + f.toRead = f.dict.readFlush() + f.step = (*decompressor).huffmanBytesReader // We need to continue this work + f.stepState = stateDict + return + } + goto readLiteral + } +} + +// Decode a single Huffman block from f. +// hl and hd are the Huffman states for the lit/length values +// and the distance values, respectively. If hd == nil, using the +// fixed distance encoding associated with fixed Huffman blocks. +func (f *decompressor) huffmanBufioReader() { + const ( + stateInit = iota // Zero value must be stateInit + stateDict + ) + fr := f.r.(*bufio.Reader) + moreBits := func() error { + c, err := fr.ReadByte() + if err != nil { + return noEOF(err) + } + f.roffset++ + f.b |= uint32(c) << f.nb + f.nb += 8 + return nil + } + + switch f.stepState { + case stateInit: + goto readLiteral + case stateDict: + goto copyHistory + } + +readLiteral: + // Read literal and/or (length, distance) according to RFC section 3.2.3. + { + var v int + { + // Inlined v, err := f.huffSym(f.hl) + // Since a huffmanDecoder can be empty or be composed of a degenerate tree + // with single element, huffSym must error on these two edge cases. In both + // cases, the chunks slice will be 0 for the invalid sequence, leading it + // satisfy the n == 0 check below. + n := uint(f.hl.maxRead) + // Optimization. Compiler isn't smart enough to keep f.b,f.nb in registers, + // but is smart enough to keep local variables in registers, so use nb and b, + // inline call to moreBits and reassign b,nb back to f on return. + nb, b := f.nb, f.b + for { + for nb < n { + c, err := fr.ReadByte() + if err != nil { + f.b = b + f.nb = nb + f.err = noEOF(err) + return + } + f.roffset++ + b |= uint32(c) << (nb & 31) + nb += 8 + } + chunk := f.hl.chunks[b&(huffmanNumChunks-1)] + n = uint(chunk & huffmanCountMask) + if n > huffmanChunkBits { + chunk = f.hl.links[chunk>>huffmanValueShift][(b>>huffmanChunkBits)&f.hl.linkMask] + n = uint(chunk & huffmanCountMask) + } + if n <= nb { + if n == 0 { + f.b = b + f.nb = nb + if debugDecode { + fmt.Println("huffsym: n==0") + } + f.err = CorruptInputError(f.roffset) + return + } + f.b = b >> (n & 31) + f.nb = nb - n + v = int(chunk >> huffmanValueShift) + break + } + } + } + + var n uint // number of bits extra + var length int + var err error + switch { + case v < 256: + f.dict.writeByte(byte(v)) + if f.dict.availWrite() == 0 { + f.toRead = f.dict.readFlush() + f.step = (*decompressor).huffmanBufioReader + f.stepState = stateInit + return + } + goto readLiteral + case v == 256: + f.finishBlock() + return + // otherwise, reference to older data + case v < 265: + length = v - (257 - 3) + n = 0 + case v < 269: + length = v*2 - (265*2 - 11) + n = 1 + case v < 273: + length = v*4 - (269*4 - 19) + n = 2 + case v < 277: + length = v*8 - (273*8 - 35) + n = 3 + case v < 281: + length = v*16 - (277*16 - 67) + n = 4 + case v < 285: + length = v*32 - (281*32 - 131) + n = 5 + case v < maxNumLit: + length = 258 + n = 0 + default: + if debugDecode { + fmt.Println(v, ">= maxNumLit") + } + f.err = CorruptInputError(f.roffset) + return + } + if n > 0 { + for f.nb < n { + if err = moreBits(); err != nil { + if debugDecode { + fmt.Println("morebits n>0:", err) + } + f.err = err + return + } + } + length += int(f.b & uint32(1<>= n + f.nb -= n + } + + var dist int + if f.hd == nil { + for f.nb < 5 { + if err = moreBits(); err != nil { + if debugDecode { + fmt.Println("morebits f.nb<5:", err) + } + f.err = err + return + } + } + dist = int(bits.Reverse8(uint8(f.b & 0x1F << 3))) + f.b >>= 5 + f.nb -= 5 + } else { + if dist, err = f.huffSym(f.hd); err != nil { + if debugDecode { + fmt.Println("huffsym:", err) + } + f.err = err + return + } + } + + switch { + case dist < 4: + dist++ + case dist < maxNumDist: + nb := uint(dist-2) >> 1 + // have 1 bit in bottom of dist, need nb more. + extra := (dist & 1) << nb + for f.nb < nb { + if err = moreBits(); err != nil { + if debugDecode { + fmt.Println("morebits f.nb>= nb + f.nb -= nb + dist = 1<<(nb+1) + 1 + extra + default: + if debugDecode { + fmt.Println("dist too big:", dist, maxNumDist) + } + f.err = CorruptInputError(f.roffset) + return + } + + // No check on length; encoding can be prescient. + if dist > f.dict.histSize() { + if debugDecode { + fmt.Println("dist > f.dict.histSize():", dist, f.dict.histSize()) + } + f.err = CorruptInputError(f.roffset) + return + } + + f.copyLen, f.copyDist = length, dist + goto copyHistory + } + +copyHistory: + // Perform a backwards copy according to RFC section 3.2.3. + { + cnt := f.dict.tryWriteCopy(f.copyDist, f.copyLen) + if cnt == 0 { + cnt = f.dict.writeCopy(f.copyDist, f.copyLen) + } + f.copyLen -= cnt + + if f.dict.availWrite() == 0 || f.copyLen > 0 { + f.toRead = f.dict.readFlush() + f.step = (*decompressor).huffmanBufioReader // We need to continue this work + f.stepState = stateDict + return + } + goto readLiteral + } +} + +// Decode a single Huffman block from f. +// hl and hd are the Huffman states for the lit/length values +// and the distance values, respectively. If hd == nil, using the +// fixed distance encoding associated with fixed Huffman blocks. +func (f *decompressor) huffmanStringsReader() { + const ( + stateInit = iota // Zero value must be stateInit + stateDict + ) + fr := f.r.(*strings.Reader) + moreBits := func() error { + c, err := fr.ReadByte() + if err != nil { + return noEOF(err) + } + f.roffset++ + f.b |= uint32(c) << f.nb + f.nb += 8 + return nil + } + + switch f.stepState { + case stateInit: + goto readLiteral + case stateDict: + goto copyHistory + } + +readLiteral: + // Read literal and/or (length, distance) according to RFC section 3.2.3. + { + var v int + { + // Inlined v, err := f.huffSym(f.hl) + // Since a huffmanDecoder can be empty or be composed of a degenerate tree + // with single element, huffSym must error on these two edge cases. In both + // cases, the chunks slice will be 0 for the invalid sequence, leading it + // satisfy the n == 0 check below. + n := uint(f.hl.maxRead) + // Optimization. Compiler isn't smart enough to keep f.b,f.nb in registers, + // but is smart enough to keep local variables in registers, so use nb and b, + // inline call to moreBits and reassign b,nb back to f on return. + nb, b := f.nb, f.b + for { + for nb < n { + c, err := fr.ReadByte() + if err != nil { + f.b = b + f.nb = nb + f.err = noEOF(err) + return + } + f.roffset++ + b |= uint32(c) << (nb & 31) + nb += 8 + } + chunk := f.hl.chunks[b&(huffmanNumChunks-1)] + n = uint(chunk & huffmanCountMask) + if n > huffmanChunkBits { + chunk = f.hl.links[chunk>>huffmanValueShift][(b>>huffmanChunkBits)&f.hl.linkMask] + n = uint(chunk & huffmanCountMask) + } + if n <= nb { + if n == 0 { + f.b = b + f.nb = nb + if debugDecode { + fmt.Println("huffsym: n==0") + } + f.err = CorruptInputError(f.roffset) + return + } + f.b = b >> (n & 31) + f.nb = nb - n + v = int(chunk >> huffmanValueShift) + break + } + } + } + + var n uint // number of bits extra + var length int + var err error + switch { + case v < 256: + f.dict.writeByte(byte(v)) + if f.dict.availWrite() == 0 { + f.toRead = f.dict.readFlush() + f.step = (*decompressor).huffmanStringsReader + f.stepState = stateInit + return + } + goto readLiteral + case v == 256: + f.finishBlock() + return + // otherwise, reference to older data + case v < 265: + length = v - (257 - 3) + n = 0 + case v < 269: + length = v*2 - (265*2 - 11) + n = 1 + case v < 273: + length = v*4 - (269*4 - 19) + n = 2 + case v < 277: + length = v*8 - (273*8 - 35) + n = 3 + case v < 281: + length = v*16 - (277*16 - 67) + n = 4 + case v < 285: + length = v*32 - (281*32 - 131) + n = 5 + case v < maxNumLit: + length = 258 + n = 0 + default: + if debugDecode { + fmt.Println(v, ">= maxNumLit") + } + f.err = CorruptInputError(f.roffset) + return + } + if n > 0 { + for f.nb < n { + if err = moreBits(); err != nil { + if debugDecode { + fmt.Println("morebits n>0:", err) + } + f.err = err + return + } + } + length += int(f.b & uint32(1<>= n + f.nb -= n + } + + var dist int + if f.hd == nil { + for f.nb < 5 { + if err = moreBits(); err != nil { + if debugDecode { + fmt.Println("morebits f.nb<5:", err) + } + f.err = err + return + } + } + dist = int(bits.Reverse8(uint8(f.b & 0x1F << 3))) + f.b >>= 5 + f.nb -= 5 + } else { + if dist, err = f.huffSym(f.hd); err != nil { + if debugDecode { + fmt.Println("huffsym:", err) + } + f.err = err + return + } + } + + switch { + case dist < 4: + dist++ + case dist < maxNumDist: + nb := uint(dist-2) >> 1 + // have 1 bit in bottom of dist, need nb more. + extra := (dist & 1) << nb + for f.nb < nb { + if err = moreBits(); err != nil { + if debugDecode { + fmt.Println("morebits f.nb>= nb + f.nb -= nb + dist = 1<<(nb+1) + 1 + extra + default: + if debugDecode { + fmt.Println("dist too big:", dist, maxNumDist) + } + f.err = CorruptInputError(f.roffset) + return + } + + // No check on length; encoding can be prescient. + if dist > f.dict.histSize() { + if debugDecode { + fmt.Println("dist > f.dict.histSize():", dist, f.dict.histSize()) + } + f.err = CorruptInputError(f.roffset) + return + } + + f.copyLen, f.copyDist = length, dist + goto copyHistory + } + +copyHistory: + // Perform a backwards copy according to RFC section 3.2.3. + { + cnt := f.dict.tryWriteCopy(f.copyDist, f.copyLen) + if cnt == 0 { + cnt = f.dict.writeCopy(f.copyDist, f.copyLen) + } + f.copyLen -= cnt + + if f.dict.availWrite() == 0 || f.copyLen > 0 { + f.toRead = f.dict.readFlush() + f.step = (*decompressor).huffmanStringsReader // We need to continue this work + f.stepState = stateDict + return + } + goto readLiteral + } +} + +func (f *decompressor) huffmanBlockDecoder() func() { + switch f.r.(type) { + case *bytes.Buffer: + return f.huffmanBytesBuffer + case *bytes.Reader: + return f.huffmanBytesReader + case *bufio.Reader: + return f.huffmanBufioReader + case *strings.Reader: + return f.huffmanStringsReader + default: + return f.huffmanBlockGeneric + } +} diff --git a/github.com/klauspost/compress/flate/inflate_test.go b/github.com/klauspost/compress/flate/inflate_test.go new file mode 100644 index 0000000..8402c0c --- /dev/null +++ b/github.com/klauspost/compress/flate/inflate_test.go @@ -0,0 +1,282 @@ +// Copyright 2014 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package flate + +import ( + "bytes" + "crypto/rand" + "io" + "io/ioutil" + "strconv" + "strings" + "testing" +) + +func TestReset(t *testing.T) { + ss := []string{ + "lorem ipsum izzle fo rizzle", + "the quick brown fox jumped over", + } + + deflated := make([]bytes.Buffer, 2) + for i, s := range ss { + w, _ := NewWriter(&deflated[i], 1) + w.Write([]byte(s)) + w.Close() + } + + inflated := make([]bytes.Buffer, 2) + + f := NewReader(&deflated[0]) + io.Copy(&inflated[0], f) + f.(Resetter).Reset(&deflated[1], nil) + io.Copy(&inflated[1], f) + f.Close() + + for i, s := range ss { + if s != inflated[i].String() { + t.Errorf("inflated[%d]:\ngot %q\nwant %q", i, inflated[i], s) + } + } +} + +func TestReaderTruncated(t *testing.T) { + vectors := []struct{ input, output string }{ + {"\x00", ""}, + {"\x00\f", ""}, + {"\x00\f\x00", ""}, + {"\x00\f\x00\xf3\xff", ""}, + {"\x00\f\x00\xf3\xffhello", "hello"}, + {"\x00\f\x00\xf3\xffhello, world", "hello, world"}, + {"\x02", ""}, + {"\xf2H\xcd", "He"}, + {"\xf2HÍ™0a\u0084\t", "Hel\x90\x90\x90\x90\x90"}, + {"\xf2HÍ™0a\u0084\t\x00", "Hel\x90\x90\x90\x90\x90"}, + } + + for i, v := range vectors { + r := strings.NewReader(v.input) + zr := NewReader(r) + b, err := ioutil.ReadAll(zr) + if err != io.ErrUnexpectedEOF { + t.Errorf("test %d, error mismatch: got %v, want io.ErrUnexpectedEOF", i, err) + } + if string(b) != v.output { + t.Errorf("test %d, output mismatch: got %q, want %q", i, b, v.output) + } + } +} + +func TestResetDict(t *testing.T) { + dict := []byte("the lorem fox") + ss := []string{ + "lorem ipsum izzle fo rizzle", + "the quick brown fox jumped over", + } + + deflated := make([]bytes.Buffer, len(ss)) + for i, s := range ss { + w, _ := NewWriterDict(&deflated[i], DefaultCompression, dict) + w.Write([]byte(s)) + w.Close() + } + + inflated := make([]bytes.Buffer, len(ss)) + + f := NewReader(nil) + for i := range inflated { + f.(Resetter).Reset(&deflated[i], dict) + io.Copy(&inflated[i], f) + } + f.Close() + + for i, s := range ss { + if s != inflated[i].String() { + t.Errorf("inflated[%d]:\ngot %q\nwant %q", i, inflated[i], s) + } + } +} + +// Tests ported from zlib/test/infcover.c +type infTest struct { + hex string + id string + n int +} + +var infTests = []infTest{ + {"0 0 0 0 0", "invalid stored block lengths", 1}, + {"3 0", "fixed", 0}, + {"6", "invalid block type", 1}, + {"1 1 0 fe ff 0", "stored", 0}, + {"fc 0 0", "too many length or distance symbols", 1}, + {"4 0 fe ff", "invalid code lengths set", 1}, + {"4 0 24 49 0", "invalid bit length repeat", 1}, + {"4 0 24 e9 ff ff", "invalid bit length repeat", 1}, + {"4 0 24 e9 ff 6d", "invalid code -- missing end-of-block", 1}, + {"4 80 49 92 24 49 92 24 71 ff ff 93 11 0", "invalid literal/lengths set", 1}, + {"4 80 49 92 24 49 92 24 f b4 ff ff c3 84", "invalid distances set", 1}, + {"4 c0 81 8 0 0 0 0 20 7f eb b 0 0", "invalid literal/length code", 1}, + {"2 7e ff ff", "invalid distance code", 1}, + {"c c0 81 0 0 0 0 0 90 ff 6b 4 0", "invalid distance too far back", 1}, + + // also trailer mismatch just in inflate() + {"1f 8b 8 0 0 0 0 0 0 0 3 0 0 0 0 1", "incorrect data check", -1}, + {"1f 8b 8 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 0 1", "incorrect length check", -1}, + {"5 c0 21 d 0 0 0 80 b0 fe 6d 2f 91 6c", "pull 17", 0}, + {"5 e0 81 91 24 cb b2 2c 49 e2 f 2e 8b 9a 47 56 9f fb fe ec d2 ff 1f", "long code", 0}, + {"ed c0 1 1 0 0 0 40 20 ff 57 1b 42 2c 4f", "length extra", 0}, + {"ed cf c1 b1 2c 47 10 c4 30 fa 6f 35 1d 1 82 59 3d fb be 2e 2a fc f c", "long distance and extra", 0}, + {"ed c0 81 0 0 0 0 80 a0 fd a9 17 a9 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 6", "window end", 0}, +} + +func TestInflate(t *testing.T) { + for _, test := range infTests { + hex := strings.Split(test.hex, " ") + data := make([]byte, len(hex)) + for i, h := range hex { + b, _ := strconv.ParseInt(h, 16, 32) + data[i] = byte(b) + } + buf := bytes.NewReader(data) + r := NewReader(buf) + + _, err := io.Copy(ioutil.Discard, r) + if (test.n == 0 && err == nil) || (test.n != 0 && err != nil) { + t.Logf("%q: OK:", test.id) + t.Logf(" - got %v", err) + continue + } + + if test.n == 0 && err != nil { + t.Errorf("%q: Expected no error, but got %v", test.id, err) + continue + } + + if test.n != 0 && err == nil { + t.Errorf("%q:Expected an error, but got none", test.id) + continue + } + t.Fatal(test.n, err) + } + + for _, test := range infOutTests { + hex := strings.Split(test.hex, " ") + data := make([]byte, len(hex)) + for i, h := range hex { + b, _ := strconv.ParseInt(h, 16, 32) + data[i] = byte(b) + } + buf := bytes.NewReader(data) + r := NewReader(buf) + + _, err := io.Copy(ioutil.Discard, r) + if test.err == (err != nil) { + t.Logf("%q: OK:", test.id) + t.Logf(" - got %v", err) + continue + } + + if test.err == false && err != nil { + t.Errorf("%q: Expected no error, but got %v", test.id, err) + continue + } + + if test.err && err == nil { + t.Errorf("%q: Expected an error, but got none", test.id) + continue + } + t.Fatal(test.err, err) + } + +} + +// Tests ported from zlib/test/infcover.c +// Since zlib inflate is push (writer) instead of pull (reader) +// some of the window size tests have been removed, since they +// are irrelevant. +type infOutTest struct { + hex string + id string + step int + win int + length int + err bool +} + +var infOutTests = []infOutTest{ + {"2 8 20 80 0 3 0", "inflate_fast TYPE return", 0, -15, 258, false}, + {"63 18 5 40 c 0", "window wrap", 3, -8, 300, false}, + {"e5 e0 81 ad 6d cb b2 2c c9 01 1e 59 63 ae 7d ee fb 4d fd b5 35 41 68 ff 7f 0f 0 0 0", "fast length extra bits", 0, -8, 258, true}, + {"25 fd 81 b5 6d 59 b6 6a 49 ea af 35 6 34 eb 8c b9 f6 b9 1e ef 67 49 50 fe ff ff 3f 0 0", "fast distance extra bits", 0, -8, 258, true}, + {"3 7e 0 0 0 0 0", "fast invalid distance code", 0, -8, 258, true}, + {"1b 7 0 0 0 0 0", "fast invalid literal/length code", 0, -8, 258, true}, + {"d c7 1 ae eb 38 c 4 41 a0 87 72 de df fb 1f b8 36 b1 38 5d ff ff 0", "fast 2nd level codes and too far back", 0, -8, 258, true}, + {"63 18 5 8c 10 8 0 0 0 0", "very common case", 0, -8, 259, false}, + {"63 60 60 18 c9 0 8 18 18 18 26 c0 28 0 29 0 0 0", "contiguous and wrap around window", 6, -8, 259, false}, + {"63 0 3 0 0 0 0 0", "copy direct from output", 0, -8, 259, false}, + {"1f 8b 0 0", "bad gzip method", 0, 31, 0, true}, + {"1f 8b 8 80", "bad gzip flags", 0, 31, 0, true}, + {"77 85", "bad zlib method", 0, 15, 0, true}, + {"78 9c", "bad zlib window size", 0, 8, 0, true}, + {"1f 8b 8 1e 0 0 0 0 0 0 1 0 0 0 0 0 0", "bad header crc", 0, 47, 1, true}, + {"1f 8b 8 2 0 0 0 0 0 0 1d 26 3 0 0 0 0 0 0 0 0 0", "check gzip length", 0, 47, 0, true}, + {"78 90", "bad zlib header check", 0, 47, 0, true}, + {"8 b8 0 0 0 1", "need dictionary", 0, 8, 0, true}, + {"63 18 68 30 d0 0 0", "force split window update", 4, -8, 259, false}, + {"3 0", "use fixed blocks", 0, -15, 1, false}, + {"", "bad window size", 0, 1, 0, true}, +} + +func TestWriteTo(t *testing.T) { + input := make([]byte, 100000) + n, err := rand.Read(input) + if err != nil { + t.Fatal(err) + } + if n != len(input) { + t.Fatal("did not fill buffer") + } + compressed := &bytes.Buffer{} + w, err := NewWriter(compressed, -2) + if err != nil { + t.Fatal(err) + } + n, err = w.Write(input) + if err != nil { + t.Fatal(err) + } + if n != len(input) { + t.Fatal("did not fill buffer") + } + w.Close() + buf := compressed.Bytes() + + dec := NewReader(bytes.NewBuffer(buf)) + // ReadAll does not use WriteTo, but we wrap it in a NopCloser to be sure. + readall, err := ioutil.ReadAll(ioutil.NopCloser(dec)) + if err != nil { + t.Fatal(err) + } + if len(readall) != len(input) { + t.Fatal("did not decompress everything") + } + + dec = NewReader(bytes.NewBuffer(buf)) + wtbuf := &bytes.Buffer{} + written, err := dec.(io.WriterTo).WriteTo(wtbuf) + if err != nil { + t.Fatal(err) + } + if written != int64(len(input)) { + t.Error("Returned length did not match, expected", len(input), "got", written) + } + if wtbuf.Len() != len(input) { + t.Error("Actual Length did not match, expected", len(input), "got", wtbuf.Len()) + } + if bytes.Compare(wtbuf.Bytes(), input) != 0 { + t.Fatal("output did not match input") + } +} diff --git a/github.com/klauspost/compress/flate/level1.go b/github.com/klauspost/compress/flate/level1.go new file mode 100644 index 0000000..1e5eea3 --- /dev/null +++ b/github.com/klauspost/compress/flate/level1.go @@ -0,0 +1,179 @@ +package flate + +import "fmt" + +// fastGen maintains the table for matches, +// and the previous byte block for level 2. +// This is the generic implementation. +type fastEncL1 struct { + fastGen + table [tableSize]tableEntry +} + +// EncodeL1 uses a similar algorithm to level 1 +func (e *fastEncL1) Encode(dst *tokens, src []byte) { + const ( + inputMargin = 12 - 1 + minNonLiteralBlockSize = 1 + 1 + inputMargin + ) + if debugDeflate && e.cur < 0 { + panic(fmt.Sprint("e.cur < 0: ", e.cur)) + } + + // Protect against e.cur wraparound. + for e.cur >= bufferReset { + if len(e.hist) == 0 { + for i := range e.table[:] { + e.table[i] = tableEntry{} + } + e.cur = maxMatchOffset + break + } + // Shift down everything in the table that isn't already too far away. + minOff := e.cur + int32(len(e.hist)) - maxMatchOffset + for i := range e.table[:] { + v := e.table[i].offset + if v <= minOff { + v = 0 + } else { + v = v - e.cur + maxMatchOffset + } + e.table[i].offset = v + } + e.cur = maxMatchOffset + } + + s := e.addBlock(src) + + // This check isn't in the Snappy implementation, but there, the caller + // instead of the callee handles this case. + if len(src) < minNonLiteralBlockSize { + // We do not fill the token table. + // This will be picked up by caller. + dst.n = uint16(len(src)) + return + } + + // Override src + src = e.hist + nextEmit := s + + // sLimit is when to stop looking for offset/length copies. The inputMargin + // lets us use a fast path for emitLiteral in the main loop, while we are + // looking for copies. + sLimit := int32(len(src) - inputMargin) + + // nextEmit is where in src the next emitLiteral should start from. + cv := load3232(src, s) + + for { + const skipLog = 5 + const doEvery = 2 + + nextS := s + var candidate tableEntry + for { + nextHash := hash(cv) + candidate = e.table[nextHash] + nextS = s + doEvery + (s-nextEmit)>>skipLog + if nextS > sLimit { + goto emitRemainder + } + + now := load6432(src, nextS) + e.table[nextHash] = tableEntry{offset: s + e.cur} + nextHash = hash(uint32(now)) + + offset := s - (candidate.offset - e.cur) + if offset < maxMatchOffset && cv == load3232(src, candidate.offset-e.cur) { + e.table[nextHash] = tableEntry{offset: nextS + e.cur} + break + } + + // Do one right away... + cv = uint32(now) + s = nextS + nextS++ + candidate = e.table[nextHash] + now >>= 8 + e.table[nextHash] = tableEntry{offset: s + e.cur} + + offset = s - (candidate.offset - e.cur) + if offset < maxMatchOffset && cv == load3232(src, candidate.offset-e.cur) { + e.table[nextHash] = tableEntry{offset: nextS + e.cur} + break + } + cv = uint32(now) + s = nextS + } + + // A 4-byte match has been found. We'll later see if more than 4 bytes + // match. But, prior to the match, src[nextEmit:s] are unmatched. Emit + // them as literal bytes. + for { + // Invariant: we have a 4-byte match at s, and no need to emit any + // literal bytes prior to s. + + // Extend the 4-byte match as long as possible. + t := candidate.offset - e.cur + l := e.matchlenLong(s+4, t+4, src) + 4 + + // Extend backwards + for t > 0 && s > nextEmit && src[t-1] == src[s-1] { + s-- + t-- + l++ + } + if nextEmit < s { + emitLiteral(dst, src[nextEmit:s]) + } + + // Save the match found + dst.AddMatchLong(l, uint32(s-t-baseMatchOffset)) + s += l + nextEmit = s + if nextS >= s { + s = nextS + 1 + } + if s >= sLimit { + // Index first pair after match end. + if int(s+l+4) < len(src) { + cv := load3232(src, s) + e.table[hash(cv)] = tableEntry{offset: s + e.cur} + } + goto emitRemainder + } + + // We could immediately start working at s now, but to improve + // compression we first update the hash table at s-2 and at s. If + // another emitCopy is not our next move, also calculate nextHash + // at s+1. At least on GOARCH=amd64, these three hash calculations + // are faster as one load64 call (with some shifts) instead of + // three load32 calls. + x := load6432(src, s-2) + o := e.cur + s - 2 + prevHash := hash(uint32(x)) + e.table[prevHash] = tableEntry{offset: o} + x >>= 16 + currHash := hash(uint32(x)) + candidate = e.table[currHash] + e.table[currHash] = tableEntry{offset: o + 2} + + offset := s - (candidate.offset - e.cur) + if offset > maxMatchOffset || uint32(x) != load3232(src, candidate.offset-e.cur) { + cv = uint32(x >> 8) + s++ + break + } + } + } + +emitRemainder: + if int(nextEmit) < len(src) { + // If nothing was added, don't encode literals. + if dst.n == 0 { + return + } + emitLiteral(dst, src[nextEmit:]) + } +} diff --git a/github.com/klauspost/compress/flate/level2.go b/github.com/klauspost/compress/flate/level2.go new file mode 100644 index 0000000..5b986a1 --- /dev/null +++ b/github.com/klauspost/compress/flate/level2.go @@ -0,0 +1,205 @@ +package flate + +import "fmt" + +// fastGen maintains the table for matches, +// and the previous byte block for level 2. +// This is the generic implementation. +type fastEncL2 struct { + fastGen + table [bTableSize]tableEntry +} + +// EncodeL2 uses a similar algorithm to level 1, but is capable +// of matching across blocks giving better compression at a small slowdown. +func (e *fastEncL2) Encode(dst *tokens, src []byte) { + const ( + inputMargin = 12 - 1 + minNonLiteralBlockSize = 1 + 1 + inputMargin + ) + + if debugDeflate && e.cur < 0 { + panic(fmt.Sprint("e.cur < 0: ", e.cur)) + } + + // Protect against e.cur wraparound. + for e.cur >= bufferReset { + if len(e.hist) == 0 { + for i := range e.table[:] { + e.table[i] = tableEntry{} + } + e.cur = maxMatchOffset + break + } + // Shift down everything in the table that isn't already too far away. + minOff := e.cur + int32(len(e.hist)) - maxMatchOffset + for i := range e.table[:] { + v := e.table[i].offset + if v <= minOff { + v = 0 + } else { + v = v - e.cur + maxMatchOffset + } + e.table[i].offset = v + } + e.cur = maxMatchOffset + } + + s := e.addBlock(src) + + // This check isn't in the Snappy implementation, but there, the caller + // instead of the callee handles this case. + if len(src) < minNonLiteralBlockSize { + // We do not fill the token table. + // This will be picked up by caller. + dst.n = uint16(len(src)) + return + } + + // Override src + src = e.hist + nextEmit := s + + // sLimit is when to stop looking for offset/length copies. The inputMargin + // lets us use a fast path for emitLiteral in the main loop, while we are + // looking for copies. + sLimit := int32(len(src) - inputMargin) + + // nextEmit is where in src the next emitLiteral should start from. + cv := load3232(src, s) + for { + // When should we start skipping if we haven't found matches in a long while. + const skipLog = 5 + const doEvery = 2 + + nextS := s + var candidate tableEntry + for { + nextHash := hash4u(cv, bTableBits) + s = nextS + nextS = s + doEvery + (s-nextEmit)>>skipLog + if nextS > sLimit { + goto emitRemainder + } + candidate = e.table[nextHash] + now := load6432(src, nextS) + e.table[nextHash] = tableEntry{offset: s + e.cur} + nextHash = hash4u(uint32(now), bTableBits) + + offset := s - (candidate.offset - e.cur) + if offset < maxMatchOffset && cv == load3232(src, candidate.offset-e.cur) { + e.table[nextHash] = tableEntry{offset: nextS + e.cur} + break + } + + // Do one right away... + cv = uint32(now) + s = nextS + nextS++ + candidate = e.table[nextHash] + now >>= 8 + e.table[nextHash] = tableEntry{offset: s + e.cur} + + offset = s - (candidate.offset - e.cur) + if offset < maxMatchOffset && cv == load3232(src, candidate.offset-e.cur) { + break + } + cv = uint32(now) + } + + // A 4-byte match has been found. We'll later see if more than 4 bytes + // match. But, prior to the match, src[nextEmit:s] are unmatched. Emit + // them as literal bytes. + + // Call emitCopy, and then see if another emitCopy could be our next + // move. Repeat until we find no match for the input immediately after + // what was consumed by the last emitCopy call. + // + // If we exit this loop normally then we need to call emitLiteral next, + // though we don't yet know how big the literal will be. We handle that + // by proceeding to the next iteration of the main loop. We also can + // exit this loop via goto if we get close to exhausting the input. + for { + // Invariant: we have a 4-byte match at s, and no need to emit any + // literal bytes prior to s. + + // Extend the 4-byte match as long as possible. + t := candidate.offset - e.cur + l := e.matchlenLong(s+4, t+4, src) + 4 + + // Extend backwards + for t > 0 && s > nextEmit && src[t-1] == src[s-1] { + s-- + t-- + l++ + } + if nextEmit < s { + emitLiteral(dst, src[nextEmit:s]) + } + + dst.AddMatchLong(l, uint32(s-t-baseMatchOffset)) + s += l + nextEmit = s + if nextS >= s { + s = nextS + 1 + } + + if s >= sLimit { + // Index first pair after match end. + if int(s+l+4) < len(src) { + cv := load3232(src, s) + e.table[hash4u(cv, bTableBits)] = tableEntry{offset: s + e.cur} + } + goto emitRemainder + } + + // Store every second hash in-between, but offset by 1. + for i := s - l + 2; i < s-5; i += 7 { + x := load6432(src, int32(i)) + nextHash := hash4u(uint32(x), bTableBits) + e.table[nextHash] = tableEntry{offset: e.cur + i} + // Skip one + x >>= 16 + nextHash = hash4u(uint32(x), bTableBits) + e.table[nextHash] = tableEntry{offset: e.cur + i + 2} + // Skip one + x >>= 16 + nextHash = hash4u(uint32(x), bTableBits) + e.table[nextHash] = tableEntry{offset: e.cur + i + 4} + } + + // We could immediately start working at s now, but to improve + // compression we first update the hash table at s-2 to s. If + // another emitCopy is not our next move, also calculate nextHash + // at s+1. At least on GOARCH=amd64, these three hash calculations + // are faster as one load64 call (with some shifts) instead of + // three load32 calls. + x := load6432(src, s-2) + o := e.cur + s - 2 + prevHash := hash4u(uint32(x), bTableBits) + prevHash2 := hash4u(uint32(x>>8), bTableBits) + e.table[prevHash] = tableEntry{offset: o} + e.table[prevHash2] = tableEntry{offset: o + 1} + currHash := hash4u(uint32(x>>16), bTableBits) + candidate = e.table[currHash] + e.table[currHash] = tableEntry{offset: o + 2} + + offset := s - (candidate.offset - e.cur) + if offset > maxMatchOffset || uint32(x>>16) != load3232(src, candidate.offset-e.cur) { + cv = uint32(x >> 24) + s++ + break + } + } + } + +emitRemainder: + if int(nextEmit) < len(src) { + // If nothing was added, don't encode literals. + if dst.n == 0 { + return + } + + emitLiteral(dst, src[nextEmit:]) + } +} diff --git a/github.com/klauspost/compress/flate/level3.go b/github.com/klauspost/compress/flate/level3.go new file mode 100644 index 0000000..c22b424 --- /dev/null +++ b/github.com/klauspost/compress/flate/level3.go @@ -0,0 +1,229 @@ +package flate + +import "fmt" + +// fastEncL3 +type fastEncL3 struct { + fastGen + table [tableSize]tableEntryPrev +} + +// Encode uses a similar algorithm to level 2, will check up to two candidates. +func (e *fastEncL3) Encode(dst *tokens, src []byte) { + const ( + inputMargin = 8 - 1 + minNonLiteralBlockSize = 1 + 1 + inputMargin + ) + + if debugDeflate && e.cur < 0 { + panic(fmt.Sprint("e.cur < 0: ", e.cur)) + } + + // Protect against e.cur wraparound. + for e.cur >= bufferReset { + if len(e.hist) == 0 { + for i := range e.table[:] { + e.table[i] = tableEntryPrev{} + } + e.cur = maxMatchOffset + break + } + // Shift down everything in the table that isn't already too far away. + minOff := e.cur + int32(len(e.hist)) - maxMatchOffset + for i := range e.table[:] { + v := e.table[i] + if v.Cur.offset <= minOff { + v.Cur.offset = 0 + } else { + v.Cur.offset = v.Cur.offset - e.cur + maxMatchOffset + } + if v.Prev.offset <= minOff { + v.Prev.offset = 0 + } else { + v.Prev.offset = v.Prev.offset - e.cur + maxMatchOffset + } + e.table[i] = v + } + e.cur = maxMatchOffset + } + + s := e.addBlock(src) + + // Skip if too small. + if len(src) < minNonLiteralBlockSize { + // We do not fill the token table. + // This will be picked up by caller. + dst.n = uint16(len(src)) + return + } + + // Override src + src = e.hist + nextEmit := s + + // sLimit is when to stop looking for offset/length copies. The inputMargin + // lets us use a fast path for emitLiteral in the main loop, while we are + // looking for copies. + sLimit := int32(len(src) - inputMargin) + + // nextEmit is where in src the next emitLiteral should start from. + cv := load3232(src, s) + for { + const skipLog = 6 + nextS := s + var candidate tableEntry + for { + nextHash := hash(cv) + s = nextS + nextS = s + 1 + (s-nextEmit)>>skipLog + if nextS > sLimit { + goto emitRemainder + } + candidates := e.table[nextHash] + now := load3232(src, nextS) + + // Safe offset distance until s + 4... + minOffset := e.cur + s - (maxMatchOffset - 4) + e.table[nextHash] = tableEntryPrev{Prev: candidates.Cur, Cur: tableEntry{offset: s + e.cur}} + + // Check both candidates + candidate = candidates.Cur + if candidate.offset < minOffset { + cv = now + // Previous will also be invalid, we have nothing. + continue + } + + if cv == load3232(src, candidate.offset-e.cur) { + if candidates.Prev.offset < minOffset || cv != load3232(src, candidates.Prev.offset-e.cur) { + break + } + // Both match and are valid, pick longest. + offset := s - (candidate.offset - e.cur) + o2 := s - (candidates.Prev.offset - e.cur) + l1, l2 := matchLen(src[s+4:], src[s-offset+4:]), matchLen(src[s+4:], src[s-o2+4:]) + if l2 > l1 { + candidate = candidates.Prev + } + break + } else { + // We only check if value mismatches. + // Offset will always be invalid in other cases. + candidate = candidates.Prev + if candidate.offset > minOffset && cv == load3232(src, candidate.offset-e.cur) { + break + } + } + cv = now + } + + // Call emitCopy, and then see if another emitCopy could be our next + // move. Repeat until we find no match for the input immediately after + // what was consumed by the last emitCopy call. + // + // If we exit this loop normally then we need to call emitLiteral next, + // though we don't yet know how big the literal will be. We handle that + // by proceeding to the next iteration of the main loop. We also can + // exit this loop via goto if we get close to exhausting the input. + for { + // Invariant: we have a 4-byte match at s, and no need to emit any + // literal bytes prior to s. + + // Extend the 4-byte match as long as possible. + // + t := candidate.offset - e.cur + l := e.matchlenLong(s+4, t+4, src) + 4 + + // Extend backwards + for t > 0 && s > nextEmit && src[t-1] == src[s-1] { + s-- + t-- + l++ + } + if nextEmit < s { + emitLiteral(dst, src[nextEmit:s]) + } + + dst.AddMatchLong(l, uint32(s-t-baseMatchOffset)) + s += l + nextEmit = s + if nextS >= s { + s = nextS + 1 + } + + if s >= sLimit { + t += l + // Index first pair after match end. + if int(t+4) < len(src) && t > 0 { + cv := load3232(src, t) + nextHash := hash(cv) + e.table[nextHash] = tableEntryPrev{ + Prev: e.table[nextHash].Cur, + Cur: tableEntry{offset: e.cur + t}, + } + } + goto emitRemainder + } + + // We could immediately start working at s now, but to improve + // compression we first update the hash table at s-3 to s. + x := load6432(src, s-3) + prevHash := hash(uint32(x)) + e.table[prevHash] = tableEntryPrev{ + Prev: e.table[prevHash].Cur, + Cur: tableEntry{offset: e.cur + s - 3}, + } + x >>= 8 + prevHash = hash(uint32(x)) + + e.table[prevHash] = tableEntryPrev{ + Prev: e.table[prevHash].Cur, + Cur: tableEntry{offset: e.cur + s - 2}, + } + x >>= 8 + prevHash = hash(uint32(x)) + + e.table[prevHash] = tableEntryPrev{ + Prev: e.table[prevHash].Cur, + Cur: tableEntry{offset: e.cur + s - 1}, + } + x >>= 8 + currHash := hash(uint32(x)) + candidates := e.table[currHash] + cv = uint32(x) + e.table[currHash] = tableEntryPrev{ + Prev: candidates.Cur, + Cur: tableEntry{offset: s + e.cur}, + } + + // Check both candidates + candidate = candidates.Cur + minOffset := e.cur + s - (maxMatchOffset - 4) + + if candidate.offset > minOffset && cv != load3232(src, candidate.offset-e.cur) { + // We only check if value mismatches. + // Offset will always be invalid in other cases. + candidate = candidates.Prev + if candidate.offset > minOffset && cv == load3232(src, candidate.offset-e.cur) { + offset := s - (candidate.offset - e.cur) + if offset <= maxMatchOffset { + continue + } + } + } + cv = uint32(x >> 8) + s++ + break + } + } + +emitRemainder: + if int(nextEmit) < len(src) { + // If nothing was added, don't encode literals. + if dst.n == 0 { + return + } + + emitLiteral(dst, src[nextEmit:]) + } +} diff --git a/github.com/klauspost/compress/flate/level4.go b/github.com/klauspost/compress/flate/level4.go new file mode 100644 index 0000000..e62f0c0 --- /dev/null +++ b/github.com/klauspost/compress/flate/level4.go @@ -0,0 +1,212 @@ +package flate + +import "fmt" + +type fastEncL4 struct { + fastGen + table [tableSize]tableEntry + bTable [tableSize]tableEntry +} + +func (e *fastEncL4) Encode(dst *tokens, src []byte) { + const ( + inputMargin = 12 - 1 + minNonLiteralBlockSize = 1 + 1 + inputMargin + ) + if debugDeflate && e.cur < 0 { + panic(fmt.Sprint("e.cur < 0: ", e.cur)) + } + // Protect against e.cur wraparound. + for e.cur >= bufferReset { + if len(e.hist) == 0 { + for i := range e.table[:] { + e.table[i] = tableEntry{} + } + for i := range e.bTable[:] { + e.bTable[i] = tableEntry{} + } + e.cur = maxMatchOffset + break + } + // Shift down everything in the table that isn't already too far away. + minOff := e.cur + int32(len(e.hist)) - maxMatchOffset + for i := range e.table[:] { + v := e.table[i].offset + if v <= minOff { + v = 0 + } else { + v = v - e.cur + maxMatchOffset + } + e.table[i].offset = v + } + for i := range e.bTable[:] { + v := e.bTable[i].offset + if v <= minOff { + v = 0 + } else { + v = v - e.cur + maxMatchOffset + } + e.bTable[i].offset = v + } + e.cur = maxMatchOffset + } + + s := e.addBlock(src) + + // This check isn't in the Snappy implementation, but there, the caller + // instead of the callee handles this case. + if len(src) < minNonLiteralBlockSize { + // We do not fill the token table. + // This will be picked up by caller. + dst.n = uint16(len(src)) + return + } + + // Override src + src = e.hist + nextEmit := s + + // sLimit is when to stop looking for offset/length copies. The inputMargin + // lets us use a fast path for emitLiteral in the main loop, while we are + // looking for copies. + sLimit := int32(len(src) - inputMargin) + + // nextEmit is where in src the next emitLiteral should start from. + cv := load6432(src, s) + for { + const skipLog = 6 + const doEvery = 1 + + nextS := s + var t int32 + for { + nextHashS := hash4x64(cv, tableBits) + nextHashL := hash7(cv, tableBits) + + s = nextS + nextS = s + doEvery + (s-nextEmit)>>skipLog + if nextS > sLimit { + goto emitRemainder + } + // Fetch a short+long candidate + sCandidate := e.table[nextHashS] + lCandidate := e.bTable[nextHashL] + next := load6432(src, nextS) + entry := tableEntry{offset: s + e.cur} + e.table[nextHashS] = entry + e.bTable[nextHashL] = entry + + t = lCandidate.offset - e.cur + if s-t < maxMatchOffset && uint32(cv) == load3232(src, lCandidate.offset-e.cur) { + // We got a long match. Use that. + break + } + + t = sCandidate.offset - e.cur + if s-t < maxMatchOffset && uint32(cv) == load3232(src, sCandidate.offset-e.cur) { + // Found a 4 match... + lCandidate = e.bTable[hash7(next, tableBits)] + + // If the next long is a candidate, check if we should use that instead... + lOff := nextS - (lCandidate.offset - e.cur) + if lOff < maxMatchOffset && load3232(src, lCandidate.offset-e.cur) == uint32(next) { + l1, l2 := matchLen(src[s+4:], src[t+4:]), matchLen(src[nextS+4:], src[nextS-lOff+4:]) + if l2 > l1 { + s = nextS + t = lCandidate.offset - e.cur + } + } + break + } + cv = next + } + + // A 4-byte match has been found. We'll later see if more than 4 bytes + // match. But, prior to the match, src[nextEmit:s] are unmatched. Emit + // them as literal bytes. + + // Extend the 4-byte match as long as possible. + l := e.matchlenLong(s+4, t+4, src) + 4 + + // Extend backwards + for t > 0 && s > nextEmit && src[t-1] == src[s-1] { + s-- + t-- + l++ + } + if nextEmit < s { + emitLiteral(dst, src[nextEmit:s]) + } + if debugDeflate { + if t >= s { + panic("s-t") + } + if (s - t) > maxMatchOffset { + panic(fmt.Sprintln("mmo", t)) + } + if l < baseMatchLength { + panic("bml") + } + } + + dst.AddMatchLong(l, uint32(s-t-baseMatchOffset)) + s += l + nextEmit = s + if nextS >= s { + s = nextS + 1 + } + + if s >= sLimit { + // Index first pair after match end. + if int(s+8) < len(src) { + cv := load6432(src, s) + e.table[hash4x64(cv, tableBits)] = tableEntry{offset: s + e.cur} + e.bTable[hash7(cv, tableBits)] = tableEntry{offset: s + e.cur} + } + goto emitRemainder + } + + // Store every 3rd hash in-between + if true { + i := nextS + if i < s-1 { + cv := load6432(src, i) + t := tableEntry{offset: i + e.cur} + t2 := tableEntry{offset: t.offset + 1} + e.bTable[hash7(cv, tableBits)] = t + e.bTable[hash7(cv>>8, tableBits)] = t2 + e.table[hash4u(uint32(cv>>8), tableBits)] = t2 + + i += 3 + for ; i < s-1; i += 3 { + cv := load6432(src, i) + t := tableEntry{offset: i + e.cur} + t2 := tableEntry{offset: t.offset + 1} + e.bTable[hash7(cv, tableBits)] = t + e.bTable[hash7(cv>>8, tableBits)] = t2 + e.table[hash4u(uint32(cv>>8), tableBits)] = t2 + } + } + } + + // We could immediately start working at s now, but to improve + // compression we first update the hash table at s-1 and at s. + x := load6432(src, s-1) + o := e.cur + s - 1 + prevHashS := hash4x64(x, tableBits) + prevHashL := hash7(x, tableBits) + e.table[prevHashS] = tableEntry{offset: o} + e.bTable[prevHashL] = tableEntry{offset: o} + cv = x >> 8 + } + +emitRemainder: + if int(nextEmit) < len(src) { + // If nothing was added, don't encode literals. + if dst.n == 0 { + return + } + + emitLiteral(dst, src[nextEmit:]) + } +} diff --git a/github.com/klauspost/compress/flate/level5.go b/github.com/klauspost/compress/flate/level5.go new file mode 100644 index 0000000..d513f1f --- /dev/null +++ b/github.com/klauspost/compress/flate/level5.go @@ -0,0 +1,279 @@ +package flate + +import "fmt" + +type fastEncL5 struct { + fastGen + table [tableSize]tableEntry + bTable [tableSize]tableEntryPrev +} + +func (e *fastEncL5) Encode(dst *tokens, src []byte) { + const ( + inputMargin = 12 - 1 + minNonLiteralBlockSize = 1 + 1 + inputMargin + ) + if debugDeflate && e.cur < 0 { + panic(fmt.Sprint("e.cur < 0: ", e.cur)) + } + + // Protect against e.cur wraparound. + for e.cur >= bufferReset { + if len(e.hist) == 0 { + for i := range e.table[:] { + e.table[i] = tableEntry{} + } + for i := range e.bTable[:] { + e.bTable[i] = tableEntryPrev{} + } + e.cur = maxMatchOffset + break + } + // Shift down everything in the table that isn't already too far away. + minOff := e.cur + int32(len(e.hist)) - maxMatchOffset + for i := range e.table[:] { + v := e.table[i].offset + if v <= minOff { + v = 0 + } else { + v = v - e.cur + maxMatchOffset + } + e.table[i].offset = v + } + for i := range e.bTable[:] { + v := e.bTable[i] + if v.Cur.offset <= minOff { + v.Cur.offset = 0 + v.Prev.offset = 0 + } else { + v.Cur.offset = v.Cur.offset - e.cur + maxMatchOffset + if v.Prev.offset <= minOff { + v.Prev.offset = 0 + } else { + v.Prev.offset = v.Prev.offset - e.cur + maxMatchOffset + } + } + e.bTable[i] = v + } + e.cur = maxMatchOffset + } + + s := e.addBlock(src) + + // This check isn't in the Snappy implementation, but there, the caller + // instead of the callee handles this case. + if len(src) < minNonLiteralBlockSize { + // We do not fill the token table. + // This will be picked up by caller. + dst.n = uint16(len(src)) + return + } + + // Override src + src = e.hist + nextEmit := s + + // sLimit is when to stop looking for offset/length copies. The inputMargin + // lets us use a fast path for emitLiteral in the main loop, while we are + // looking for copies. + sLimit := int32(len(src) - inputMargin) + + // nextEmit is where in src the next emitLiteral should start from. + cv := load6432(src, s) + for { + const skipLog = 6 + const doEvery = 1 + + nextS := s + var l int32 + var t int32 + for { + nextHashS := hash4x64(cv, tableBits) + nextHashL := hash7(cv, tableBits) + + s = nextS + nextS = s + doEvery + (s-nextEmit)>>skipLog + if nextS > sLimit { + goto emitRemainder + } + // Fetch a short+long candidate + sCandidate := e.table[nextHashS] + lCandidate := e.bTable[nextHashL] + next := load6432(src, nextS) + entry := tableEntry{offset: s + e.cur} + e.table[nextHashS] = entry + eLong := &e.bTable[nextHashL] + eLong.Cur, eLong.Prev = entry, eLong.Cur + + nextHashS = hash4x64(next, tableBits) + nextHashL = hash7(next, tableBits) + + t = lCandidate.Cur.offset - e.cur + if s-t < maxMatchOffset { + if uint32(cv) == load3232(src, lCandidate.Cur.offset-e.cur) { + // Store the next match + e.table[nextHashS] = tableEntry{offset: nextS + e.cur} + eLong := &e.bTable[nextHashL] + eLong.Cur, eLong.Prev = tableEntry{offset: nextS + e.cur}, eLong.Cur + + t2 := lCandidate.Prev.offset - e.cur + if s-t2 < maxMatchOffset && uint32(cv) == load3232(src, lCandidate.Prev.offset-e.cur) { + l = e.matchlen(s+4, t+4, src) + 4 + ml1 := e.matchlen(s+4, t2+4, src) + 4 + if ml1 > l { + t = t2 + l = ml1 + break + } + } + break + } + t = lCandidate.Prev.offset - e.cur + if s-t < maxMatchOffset && uint32(cv) == load3232(src, lCandidate.Prev.offset-e.cur) { + // Store the next match + e.table[nextHashS] = tableEntry{offset: nextS + e.cur} + eLong := &e.bTable[nextHashL] + eLong.Cur, eLong.Prev = tableEntry{offset: nextS + e.cur}, eLong.Cur + break + } + } + + t = sCandidate.offset - e.cur + if s-t < maxMatchOffset && uint32(cv) == load3232(src, sCandidate.offset-e.cur) { + // Found a 4 match... + l = e.matchlen(s+4, t+4, src) + 4 + lCandidate = e.bTable[nextHashL] + // Store the next match + + e.table[nextHashS] = tableEntry{offset: nextS + e.cur} + eLong := &e.bTable[nextHashL] + eLong.Cur, eLong.Prev = tableEntry{offset: nextS + e.cur}, eLong.Cur + + // If the next long is a candidate, use that... + t2 := lCandidate.Cur.offset - e.cur + if nextS-t2 < maxMatchOffset { + if load3232(src, lCandidate.Cur.offset-e.cur) == uint32(next) { + ml := e.matchlen(nextS+4, t2+4, src) + 4 + if ml > l { + t = t2 + s = nextS + l = ml + break + } + } + // If the previous long is a candidate, use that... + t2 = lCandidate.Prev.offset - e.cur + if nextS-t2 < maxMatchOffset && load3232(src, lCandidate.Prev.offset-e.cur) == uint32(next) { + ml := e.matchlen(nextS+4, t2+4, src) + 4 + if ml > l { + t = t2 + s = nextS + l = ml + break + } + } + } + break + } + cv = next + } + + // A 4-byte match has been found. We'll later see if more than 4 bytes + // match. But, prior to the match, src[nextEmit:s] are unmatched. Emit + // them as literal bytes. + + // Extend the 4-byte match as long as possible. + if l == 0 { + l = e.matchlenLong(s+4, t+4, src) + 4 + } else if l == maxMatchLength { + l += e.matchlenLong(s+l, t+l, src) + } + // Extend backwards + for t > 0 && s > nextEmit && src[t-1] == src[s-1] { + s-- + t-- + l++ + } + if nextEmit < s { + emitLiteral(dst, src[nextEmit:s]) + } + if debugDeflate { + if t >= s { + panic(fmt.Sprintln("s-t", s, t)) + } + if (s - t) > maxMatchOffset { + panic(fmt.Sprintln("mmo", s-t)) + } + if l < baseMatchLength { + panic("bml") + } + } + + dst.AddMatchLong(l, uint32(s-t-baseMatchOffset)) + s += l + nextEmit = s + if nextS >= s { + s = nextS + 1 + } + + if s >= sLimit { + goto emitRemainder + } + + // Store every 3rd hash in-between. + if true { + const hashEvery = 3 + i := s - l + 1 + if i < s-1 { + cv := load6432(src, i) + t := tableEntry{offset: i + e.cur} + e.table[hash4x64(cv, tableBits)] = t + eLong := &e.bTable[hash7(cv, tableBits)] + eLong.Cur, eLong.Prev = t, eLong.Cur + + // Do an long at i+1 + cv >>= 8 + t = tableEntry{offset: t.offset + 1} + eLong = &e.bTable[hash7(cv, tableBits)] + eLong.Cur, eLong.Prev = t, eLong.Cur + + // We only have enough bits for a short entry at i+2 + cv >>= 8 + t = tableEntry{offset: t.offset + 1} + e.table[hash4x64(cv, tableBits)] = t + + // Skip one - otherwise we risk hitting 's' + i += 4 + for ; i < s-1; i += hashEvery { + cv := load6432(src, i) + t := tableEntry{offset: i + e.cur} + t2 := tableEntry{offset: t.offset + 1} + eLong := &e.bTable[hash7(cv, tableBits)] + eLong.Cur, eLong.Prev = t, eLong.Cur + e.table[hash4u(uint32(cv>>8), tableBits)] = t2 + } + } + } + + // We could immediately start working at s now, but to improve + // compression we first update the hash table at s-1 and at s. + x := load6432(src, s-1) + o := e.cur + s - 1 + prevHashS := hash4x64(x, tableBits) + prevHashL := hash7(x, tableBits) + e.table[prevHashS] = tableEntry{offset: o} + eLong := &e.bTable[prevHashL] + eLong.Cur, eLong.Prev = tableEntry{offset: o}, eLong.Cur + cv = x >> 8 + } + +emitRemainder: + if int(nextEmit) < len(src) { + // If nothing was added, don't encode literals. + if dst.n == 0 { + return + } + + emitLiteral(dst, src[nextEmit:]) + } +} diff --git a/github.com/klauspost/compress/flate/level6.go b/github.com/klauspost/compress/flate/level6.go new file mode 100644 index 0000000..a52c80e --- /dev/null +++ b/github.com/klauspost/compress/flate/level6.go @@ -0,0 +1,282 @@ +package flate + +import "fmt" + +type fastEncL6 struct { + fastGen + table [tableSize]tableEntry + bTable [tableSize]tableEntryPrev +} + +func (e *fastEncL6) Encode(dst *tokens, src []byte) { + const ( + inputMargin = 12 - 1 + minNonLiteralBlockSize = 1 + 1 + inputMargin + ) + if debugDeflate && e.cur < 0 { + panic(fmt.Sprint("e.cur < 0: ", e.cur)) + } + + // Protect against e.cur wraparound. + for e.cur >= bufferReset { + if len(e.hist) == 0 { + for i := range e.table[:] { + e.table[i] = tableEntry{} + } + for i := range e.bTable[:] { + e.bTable[i] = tableEntryPrev{} + } + e.cur = maxMatchOffset + break + } + // Shift down everything in the table that isn't already too far away. + minOff := e.cur + int32(len(e.hist)) - maxMatchOffset + for i := range e.table[:] { + v := e.table[i].offset + if v <= minOff { + v = 0 + } else { + v = v - e.cur + maxMatchOffset + } + e.table[i].offset = v + } + for i := range e.bTable[:] { + v := e.bTable[i] + if v.Cur.offset <= minOff { + v.Cur.offset = 0 + v.Prev.offset = 0 + } else { + v.Cur.offset = v.Cur.offset - e.cur + maxMatchOffset + if v.Prev.offset <= minOff { + v.Prev.offset = 0 + } else { + v.Prev.offset = v.Prev.offset - e.cur + maxMatchOffset + } + } + e.bTable[i] = v + } + e.cur = maxMatchOffset + } + + s := e.addBlock(src) + + // This check isn't in the Snappy implementation, but there, the caller + // instead of the callee handles this case. + if len(src) < minNonLiteralBlockSize { + // We do not fill the token table. + // This will be picked up by caller. + dst.n = uint16(len(src)) + return + } + + // Override src + src = e.hist + nextEmit := s + + // sLimit is when to stop looking for offset/length copies. The inputMargin + // lets us use a fast path for emitLiteral in the main loop, while we are + // looking for copies. + sLimit := int32(len(src) - inputMargin) + + // nextEmit is where in src the next emitLiteral should start from. + cv := load6432(src, s) + // Repeat MUST be > 1 and within range + repeat := int32(1) + for { + const skipLog = 7 + const doEvery = 1 + + nextS := s + var l int32 + var t int32 + for { + nextHashS := hash4x64(cv, tableBits) + nextHashL := hash7(cv, tableBits) + s = nextS + nextS = s + doEvery + (s-nextEmit)>>skipLog + if nextS > sLimit { + goto emitRemainder + } + // Fetch a short+long candidate + sCandidate := e.table[nextHashS] + lCandidate := e.bTable[nextHashL] + next := load6432(src, nextS) + entry := tableEntry{offset: s + e.cur} + e.table[nextHashS] = entry + eLong := &e.bTable[nextHashL] + eLong.Cur, eLong.Prev = entry, eLong.Cur + + // Calculate hashes of 'next' + nextHashS = hash4x64(next, tableBits) + nextHashL = hash7(next, tableBits) + + t = lCandidate.Cur.offset - e.cur + if s-t < maxMatchOffset { + if uint32(cv) == load3232(src, lCandidate.Cur.offset-e.cur) { + // Long candidate matches at least 4 bytes. + + // Store the next match + e.table[nextHashS] = tableEntry{offset: nextS + e.cur} + eLong := &e.bTable[nextHashL] + eLong.Cur, eLong.Prev = tableEntry{offset: nextS + e.cur}, eLong.Cur + + // Check the previous long candidate as well. + t2 := lCandidate.Prev.offset - e.cur + if s-t2 < maxMatchOffset && uint32(cv) == load3232(src, lCandidate.Prev.offset-e.cur) { + l = e.matchlen(s+4, t+4, src) + 4 + ml1 := e.matchlen(s+4, t2+4, src) + 4 + if ml1 > l { + t = t2 + l = ml1 + break + } + } + break + } + // Current value did not match, but check if previous long value does. + t = lCandidate.Prev.offset - e.cur + if s-t < maxMatchOffset && uint32(cv) == load3232(src, lCandidate.Prev.offset-e.cur) { + // Store the next match + e.table[nextHashS] = tableEntry{offset: nextS + e.cur} + eLong := &e.bTable[nextHashL] + eLong.Cur, eLong.Prev = tableEntry{offset: nextS + e.cur}, eLong.Cur + break + } + } + + t = sCandidate.offset - e.cur + if s-t < maxMatchOffset && uint32(cv) == load3232(src, sCandidate.offset-e.cur) { + // Found a 4 match... + l = e.matchlen(s+4, t+4, src) + 4 + + // Look up next long candidate (at nextS) + lCandidate = e.bTable[nextHashL] + + // Store the next match + e.table[nextHashS] = tableEntry{offset: nextS + e.cur} + eLong := &e.bTable[nextHashL] + eLong.Cur, eLong.Prev = tableEntry{offset: nextS + e.cur}, eLong.Cur + + // Check repeat at s + repOff + const repOff = 1 + t2 := s - repeat + repOff + if load3232(src, t2) == uint32(cv>>(8*repOff)) { + ml := e.matchlen(s+4+repOff, t2+4, src) + 4 + if ml > l { + t = t2 + l = ml + s += repOff + // Not worth checking more. + break + } + } + + // If the next long is a candidate, use that... + t2 = lCandidate.Cur.offset - e.cur + if nextS-t2 < maxMatchOffset { + if load3232(src, lCandidate.Cur.offset-e.cur) == uint32(next) { + ml := e.matchlen(nextS+4, t2+4, src) + 4 + if ml > l { + t = t2 + s = nextS + l = ml + // This is ok, but check previous as well. + } + } + // If the previous long is a candidate, use that... + t2 = lCandidate.Prev.offset - e.cur + if nextS-t2 < maxMatchOffset && load3232(src, lCandidate.Prev.offset-e.cur) == uint32(next) { + ml := e.matchlen(nextS+4, t2+4, src) + 4 + if ml > l { + t = t2 + s = nextS + l = ml + break + } + } + } + break + } + cv = next + } + + // A 4-byte match has been found. We'll later see if more than 4 bytes + // match. But, prior to the match, src[nextEmit:s] are unmatched. Emit + // them as literal bytes. + + // Extend the 4-byte match as long as possible. + if l == 0 { + l = e.matchlenLong(s+4, t+4, src) + 4 + } else if l == maxMatchLength { + l += e.matchlenLong(s+l, t+l, src) + } + + // Extend backwards + for t > 0 && s > nextEmit && src[t-1] == src[s-1] { + s-- + t-- + l++ + } + if nextEmit < s { + emitLiteral(dst, src[nextEmit:s]) + } + if false { + if t >= s { + panic(fmt.Sprintln("s-t", s, t)) + } + if (s - t) > maxMatchOffset { + panic(fmt.Sprintln("mmo", s-t)) + } + if l < baseMatchLength { + panic("bml") + } + } + + dst.AddMatchLong(l, uint32(s-t-baseMatchOffset)) + repeat = s - t + s += l + nextEmit = s + if nextS >= s { + s = nextS + 1 + } + + if s >= sLimit { + // Index after match end. + for i := nextS + 1; i < int32(len(src))-8; i += 2 { + cv := load6432(src, i) + e.table[hash4x64(cv, tableBits)] = tableEntry{offset: i + e.cur} + eLong := &e.bTable[hash7(cv, tableBits)] + eLong.Cur, eLong.Prev = tableEntry{offset: i + e.cur}, eLong.Cur + } + goto emitRemainder + } + + // Store every long hash in-between and every second short. + if true { + for i := nextS + 1; i < s-1; i += 2 { + cv := load6432(src, i) + t := tableEntry{offset: i + e.cur} + t2 := tableEntry{offset: t.offset + 1} + eLong := &e.bTable[hash7(cv, tableBits)] + eLong2 := &e.bTable[hash7(cv>>8, tableBits)] + e.table[hash4x64(cv, tableBits)] = t + eLong.Cur, eLong.Prev = t, eLong.Cur + eLong2.Cur, eLong2.Prev = t2, eLong2.Cur + } + } + + // We could immediately start working at s now, but to improve + // compression we first update the hash table at s-1 and at s. + cv = load6432(src, s) + } + +emitRemainder: + if int(nextEmit) < len(src) { + // If nothing was added, don't encode literals. + if dst.n == 0 { + return + } + + emitLiteral(dst, src[nextEmit:]) + } +} diff --git a/github.com/klauspost/compress/flate/reader_test.go b/github.com/klauspost/compress/flate/reader_test.go new file mode 100644 index 0000000..5543964 --- /dev/null +++ b/github.com/klauspost/compress/flate/reader_test.go @@ -0,0 +1,106 @@ +// Copyright 2012 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package flate + +import ( + "bytes" + "io" + "io/ioutil" + "runtime" + "strings" + "testing" +) + +func TestNlitOutOfRange(t *testing.T) { + // Trying to decode this bogus flate data, which has a Huffman table + // with nlit=288, should not panic. + io.Copy(ioutil.Discard, NewReader(strings.NewReader( + "\xfc\xfe\x36\xe7\x5e\x1c\xef\xb3\x55\x58\x77\xb6\x56\xb5\x43\xf4"+ + "\x6f\xf2\xd2\xe6\x3d\x99\xa0\x85\x8c\x48\xeb\xf8\xda\x83\x04\x2a"+ + "\x75\xc4\xf8\x0f\x12\x11\xb9\xb4\x4b\x09\xa0\xbe\x8b\x91\x4c"))) +} + +const ( + digits = iota + twain + random +) + +var testfiles = []string{ + // Digits is the digits of the irrational number e. Its decimal representation + // does not repeat, but there are only 10 possible digits, so it should be + // reasonably compressible. + digits: "../testdata/e.txt", + // Twain is Project Gutenberg's edition of Mark Twain's classic English novel. + twain: "../testdata/Mark.Twain-Tom.Sawyer.txt", + // Random bytes + random: "../testdata/sharnd.out", +} + +func benchmarkDecode(b *testing.B, testfile, level, n int) { + b.ReportAllocs() + b.StopTimer() + b.SetBytes(int64(n)) + buf0, err := ioutil.ReadFile(testfiles[testfile]) + if err != nil { + b.Fatal(err) + } + if len(buf0) == 0 { + b.Fatalf("test file %q has no data", testfiles[testfile]) + } + compressed := new(bytes.Buffer) + w, err := NewWriter(compressed, level) + if err != nil { + b.Fatal(err) + } + for i := 0; i < n; i += len(buf0) { + if len(buf0) > n-i { + buf0 = buf0[:n-i] + } + io.Copy(w, bytes.NewReader(buf0)) + } + w.Close() + buf1 := compressed.Bytes() + buf0, compressed, w = nil, nil, nil + runtime.GC() + b.StartTimer() + r := NewReader(bytes.NewReader(buf1)) + res := r.(Resetter) + for i := 0; i < b.N; i++ { + res.Reset(bytes.NewReader(buf1), nil) + io.Copy(ioutil.Discard, r) + } +} + +// These short names are so that gofmt doesn't break the BenchmarkXxx function +// bodies below over multiple lines. +const ( + constant = ConstantCompression + speed = BestSpeed + default_ = DefaultCompression + compress = BestCompression +) + +func BenchmarkDecodeDigitsSpeed1e4(b *testing.B) { benchmarkDecode(b, digits, speed, 1e4) } +func BenchmarkDecodeDigitsSpeed1e5(b *testing.B) { benchmarkDecode(b, digits, speed, 1e5) } +func BenchmarkDecodeDigitsSpeed1e6(b *testing.B) { benchmarkDecode(b, digits, speed, 1e6) } +func BenchmarkDecodeDigitsDefault1e4(b *testing.B) { benchmarkDecode(b, digits, default_, 1e4) } +func BenchmarkDecodeDigitsDefault1e5(b *testing.B) { benchmarkDecode(b, digits, default_, 1e5) } +func BenchmarkDecodeDigitsDefault1e6(b *testing.B) { benchmarkDecode(b, digits, default_, 1e6) } +func BenchmarkDecodeDigitsCompress1e4(b *testing.B) { benchmarkDecode(b, digits, compress, 1e4) } +func BenchmarkDecodeDigitsCompress1e5(b *testing.B) { benchmarkDecode(b, digits, compress, 1e5) } +func BenchmarkDecodeDigitsCompress1e6(b *testing.B) { benchmarkDecode(b, digits, compress, 1e6) } +func BenchmarkDecodeTwainSpeed1e4(b *testing.B) { benchmarkDecode(b, twain, speed, 1e4) } +func BenchmarkDecodeTwainSpeed1e5(b *testing.B) { benchmarkDecode(b, twain, speed, 1e5) } +func BenchmarkDecodeTwainSpeed1e6(b *testing.B) { benchmarkDecode(b, twain, speed, 1e6) } +func BenchmarkDecodeTwainDefault1e4(b *testing.B) { benchmarkDecode(b, twain, default_, 1e4) } +func BenchmarkDecodeTwainDefault1e5(b *testing.B) { benchmarkDecode(b, twain, default_, 1e5) } +func BenchmarkDecodeTwainDefault1e6(b *testing.B) { benchmarkDecode(b, twain, default_, 1e6) } +func BenchmarkDecodeTwainCompress1e4(b *testing.B) { benchmarkDecode(b, twain, compress, 1e4) } +func BenchmarkDecodeTwainCompress1e5(b *testing.B) { benchmarkDecode(b, twain, compress, 1e5) } +func BenchmarkDecodeTwainCompress1e6(b *testing.B) { benchmarkDecode(b, twain, compress, 1e6) } +func BenchmarkDecodeRandomSpeed1e4(b *testing.B) { benchmarkDecode(b, random, speed, 1e4) } +func BenchmarkDecodeRandomSpeed1e5(b *testing.B) { benchmarkDecode(b, random, speed, 1e5) } +func BenchmarkDecodeRandomSpeed1e6(b *testing.B) { benchmarkDecode(b, random, speed, 1e6) } diff --git a/github.com/klauspost/compress/flate/stateless.go b/github.com/klauspost/compress/flate/stateless.go new file mode 100644 index 0000000..53e8991 --- /dev/null +++ b/github.com/klauspost/compress/flate/stateless.go @@ -0,0 +1,297 @@ +package flate + +import ( + "io" + "math" + "sync" +) + +const ( + maxStatelessBlock = math.MaxInt16 + // dictionary will be taken from maxStatelessBlock, so limit it. + maxStatelessDict = 8 << 10 + + slTableBits = 13 + slTableSize = 1 << slTableBits + slTableShift = 32 - slTableBits +) + +type statelessWriter struct { + dst io.Writer + closed bool +} + +func (s *statelessWriter) Close() error { + if s.closed { + return nil + } + s.closed = true + // Emit EOF block + return StatelessDeflate(s.dst, nil, true, nil) +} + +func (s *statelessWriter) Write(p []byte) (n int, err error) { + err = StatelessDeflate(s.dst, p, false, nil) + if err != nil { + return 0, err + } + return len(p), nil +} + +func (s *statelessWriter) Reset(w io.Writer) { + s.dst = w + s.closed = false +} + +// NewStatelessWriter will do compression but without maintaining any state +// between Write calls. +// There will be no memory kept between Write calls, +// but compression and speed will be suboptimal. +// Because of this, the size of actual Write calls will affect output size. +func NewStatelessWriter(dst io.Writer) io.WriteCloser { + return &statelessWriter{dst: dst} +} + +// bitWriterPool contains bit writers that can be reused. +var bitWriterPool = sync.Pool{ + New: func() interface{} { + return newHuffmanBitWriter(nil) + }, +} + +// StatelessDeflate allows to compress directly to a Writer without retaining state. +// When returning everything will be flushed. +// Up to 8KB of an optional dictionary can be given which is presumed to presumed to precede the block. +// Longer dictionaries will be truncated and will still produce valid output. +// Sending nil dictionary is perfectly fine. +func StatelessDeflate(out io.Writer, in []byte, eof bool, dict []byte) error { + var dst tokens + bw := bitWriterPool.Get().(*huffmanBitWriter) + bw.reset(out) + defer func() { + // don't keep a reference to our output + bw.reset(nil) + bitWriterPool.Put(bw) + }() + if eof && len(in) == 0 { + // Just write an EOF block. + // Could be faster... + bw.writeStoredHeader(0, true) + bw.flush() + return bw.err + } + + // Truncate dict + if len(dict) > maxStatelessDict { + dict = dict[len(dict)-maxStatelessDict:] + } + + for len(in) > 0 { + todo := in + if len(todo) > maxStatelessBlock-len(dict) { + todo = todo[:maxStatelessBlock-len(dict)] + } + in = in[len(todo):] + uncompressed := todo + if len(dict) > 0 { + // combine dict and source + bufLen := len(todo) + len(dict) + combined := make([]byte, bufLen) + copy(combined, dict) + copy(combined[len(dict):], todo) + todo = combined + } + // Compress + statelessEnc(&dst, todo, int16(len(dict))) + isEof := eof && len(in) == 0 + + if dst.n == 0 { + bw.writeStoredHeader(len(uncompressed), isEof) + if bw.err != nil { + return bw.err + } + bw.writeBytes(uncompressed) + } else if int(dst.n) > len(uncompressed)-len(uncompressed)>>4 { + // If we removed less than 1/16th, huffman compress the block. + bw.writeBlockHuff(isEof, uncompressed, len(in) == 0) + } else { + bw.writeBlockDynamic(&dst, isEof, uncompressed, len(in) == 0) + } + if len(in) > 0 { + // Retain a dict if we have more + dict = todo[len(todo)-maxStatelessDict:] + dst.Reset() + } + if bw.err != nil { + return bw.err + } + } + if !eof { + // Align, only a stored block can do that. + bw.writeStoredHeader(0, false) + } + bw.flush() + return bw.err +} + +func hashSL(u uint32) uint32 { + return (u * 0x1e35a7bd) >> slTableShift +} + +func load3216(b []byte, i int16) uint32 { + // Help the compiler eliminate bounds checks on the read so it can be done in a single read. + b = b[i:] + b = b[:4] + return uint32(b[0]) | uint32(b[1])<<8 | uint32(b[2])<<16 | uint32(b[3])<<24 +} + +func load6416(b []byte, i int16) uint64 { + // Help the compiler eliminate bounds checks on the read so it can be done in a single read. + b = b[i:] + b = b[:8] + return uint64(b[0]) | uint64(b[1])<<8 | uint64(b[2])<<16 | uint64(b[3])<<24 | + uint64(b[4])<<32 | uint64(b[5])<<40 | uint64(b[6])<<48 | uint64(b[7])<<56 +} + +func statelessEnc(dst *tokens, src []byte, startAt int16) { + const ( + inputMargin = 12 - 1 + minNonLiteralBlockSize = 1 + 1 + inputMargin + ) + + type tableEntry struct { + offset int16 + } + + var table [slTableSize]tableEntry + + // This check isn't in the Snappy implementation, but there, the caller + // instead of the callee handles this case. + if len(src)-int(startAt) < minNonLiteralBlockSize { + // We do not fill the token table. + // This will be picked up by caller. + dst.n = 0 + return + } + // Index until startAt + if startAt > 0 { + cv := load3232(src, 0) + for i := int16(0); i < startAt; i++ { + table[hashSL(cv)] = tableEntry{offset: i} + cv = (cv >> 8) | (uint32(src[i+4]) << 24) + } + } + + s := startAt + 1 + nextEmit := startAt + // sLimit is when to stop looking for offset/length copies. The inputMargin + // lets us use a fast path for emitLiteral in the main loop, while we are + // looking for copies. + sLimit := int16(len(src) - inputMargin) + + // nextEmit is where in src the next emitLiteral should start from. + cv := load3216(src, s) + + for { + const skipLog = 5 + const doEvery = 2 + + nextS := s + var candidate tableEntry + for { + nextHash := hashSL(cv) + candidate = table[nextHash] + nextS = s + doEvery + (s-nextEmit)>>skipLog + if nextS > sLimit || nextS <= 0 { + goto emitRemainder + } + + now := load6416(src, nextS) + table[nextHash] = tableEntry{offset: s} + nextHash = hashSL(uint32(now)) + + if cv == load3216(src, candidate.offset) { + table[nextHash] = tableEntry{offset: nextS} + break + } + + // Do one right away... + cv = uint32(now) + s = nextS + nextS++ + candidate = table[nextHash] + now >>= 8 + table[nextHash] = tableEntry{offset: s} + + if cv == load3216(src, candidate.offset) { + table[nextHash] = tableEntry{offset: nextS} + break + } + cv = uint32(now) + s = nextS + } + + // A 4-byte match has been found. We'll later see if more than 4 bytes + // match. But, prior to the match, src[nextEmit:s] are unmatched. Emit + // them as literal bytes. + for { + // Invariant: we have a 4-byte match at s, and no need to emit any + // literal bytes prior to s. + + // Extend the 4-byte match as long as possible. + t := candidate.offset + l := int16(matchLen(src[s+4:], src[t+4:]) + 4) + + // Extend backwards + for t > 0 && s > nextEmit && src[t-1] == src[s-1] { + s-- + t-- + l++ + } + if nextEmit < s { + emitLiteral(dst, src[nextEmit:s]) + } + + // Save the match found + dst.AddMatchLong(int32(l), uint32(s-t-baseMatchOffset)) + s += l + nextEmit = s + if nextS >= s { + s = nextS + 1 + } + if s >= sLimit { + goto emitRemainder + } + + // We could immediately start working at s now, but to improve + // compression we first update the hash table at s-2 and at s. If + // another emitCopy is not our next move, also calculate nextHash + // at s+1. At least on GOARCH=amd64, these three hash calculations + // are faster as one load64 call (with some shifts) instead of + // three load32 calls. + x := load6416(src, s-2) + o := s - 2 + prevHash := hashSL(uint32(x)) + table[prevHash] = tableEntry{offset: o} + x >>= 16 + currHash := hashSL(uint32(x)) + candidate = table[currHash] + table[currHash] = tableEntry{offset: o + 2} + + if uint32(x) != load3216(src, candidate.offset) { + cv = uint32(x >> 8) + s++ + break + } + } + } + +emitRemainder: + if int(nextEmit) < len(src) { + // If nothing was added, don't encode literals. + if dst.n == 0 { + return + } + emitLiteral(dst, src[nextEmit:]) + } +} diff --git a/github.com/klauspost/compress/flate/testdata/huffman-null-max.dyn.expect b/github.com/klauspost/compress/flate/testdata/huffman-null-max.dyn.expect new file mode 100644 index 0000000000000000000000000000000000000000..0a3c71ceb3bee4671bb61c42561246285bd50ec1 GIT binary patch literal 101 ncmaEJmwCYrD+Y!G-*azoJ9~2*kc6Z1@Y{Kl7$^iB92Q&vuC^3| literal 0 HcmV?d00001 diff --git a/github.com/klauspost/compress/flate/testdata/huffman-null-max.dyn.expect-noinput b/github.com/klauspost/compress/flate/testdata/huffman-null-max.dyn.expect-noinput new file mode 100644 index 0000000000000000000000000000000000000000..0a3c71ceb3bee4671bb61c42561246285bd50ec1 GIT binary patch literal 101 ncmaEJmwCYrD+Y!G-*azoJ9~2*kc6Z1@Y{Kl7$^iB92Q&vuC^3| literal 0 HcmV?d00001 diff --git a/github.com/klauspost/compress/flate/testdata/huffman-null-max.golden b/github.com/klauspost/compress/flate/testdata/huffman-null-max.golden new file mode 100644 index 0000000000000000000000000000000000000000..fe7b7f4fb70f74d20828ffd335ccb06696a34df5 GIT binary patch literal 8219 zcmeIuF%1AA6hy(FfB;a0B0Qmj8Xq)Bf%YU^GMiUzIeDch5iw@ppXxh}009C72oNAZ hfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5cs#iX%|VS4O9RC literal 0 HcmV?d00001 diff --git a/github.com/klauspost/compress/flate/testdata/huffman-null-max.in b/github.com/klauspost/compress/flate/testdata/huffman-null-max.in new file mode 100644 index 0000000000000000000000000000000000000000..5dfddf075bed03499414ae453f0d6f30fe79da3d GIT binary patch literal 65535 zcmeIufdBvi0Dz$VsTV1P3IhfV7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd z0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwA zz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEj zFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r z3>YwAz<>b*1`HT5V8DO@0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@ t0|pEjFkrxd0RsjM7%*VKfB^#r3>YwAz<>b*1`HT5V8DO@0|pEjFwg)F00961 literal 0 HcmV?d00001 diff --git a/github.com/klauspost/compress/flate/testdata/huffman-null-max.sync.expect b/github.com/klauspost/compress/flate/testdata/huffman-null-max.sync.expect new file mode 100644 index 0000000000000000000000000000000000000000..c08165143f2c570013c4916cbac5addfe9622a55 GIT binary patch literal 78 ZcmaEJppgLx8W#LrDZUcKq5v#l0|1+Y23i0B literal 0 HcmV?d00001 diff --git a/github.com/klauspost/compress/flate/testdata/huffman-null-max.sync.expect-noinput b/github.com/klauspost/compress/flate/testdata/huffman-null-max.sync.expect-noinput new file mode 100644 index 0000000000000000000000000000000000000000..c08165143f2c570013c4916cbac5addfe9622a55 GIT binary patch literal 78 ZcmaEJppgLx8W#LrDZUcKq5v#l0|1+Y23i0B literal 0 HcmV?d00001 diff --git a/github.com/klauspost/compress/flate/testdata/huffman-null-max.wb.expect b/github.com/klauspost/compress/flate/testdata/huffman-null-max.wb.expect new file mode 100644 index 0000000000000000000000000000000000000000..c08165143f2c570013c4916cbac5addfe9622a55 GIT binary patch literal 78 ZcmaEJppgLx8W#LrDZUcKq5v#l0|1+Y23i0B literal 0 HcmV?d00001 diff --git a/github.com/klauspost/compress/flate/testdata/huffman-null-max.wb.expect-noinput b/github.com/klauspost/compress/flate/testdata/huffman-null-max.wb.expect-noinput new file mode 100644 index 0000000000000000000000000000000000000000..c08165143f2c570013c4916cbac5addfe9622a55 GIT binary patch literal 78 ZcmaEJppgLx8W#LrDZUcKq5v#l0|1+Y23i0B literal 0 HcmV?d00001 diff --git a/github.com/klauspost/compress/flate/testdata/huffman-pi.dyn.expect b/github.com/klauspost/compress/flate/testdata/huffman-pi.dyn.expect new file mode 100644 index 0000000000000000000000000000000000000000..11756feafbe613e8979b814493a5fd41d0483395 GIT binary patch literal 1751 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 literal 0 HcmV?d00001 diff --git a/github.com/klauspost/compress/flate/testdata/huffman-rand-1k.dyn.expect-noinput b/github.com/klauspost/compress/flate/testdata/huffman-rand-1k.dyn.expect-noinput new file mode 100644 index 0000000000000000000000000000000000000000..5162399686d8b32a892409ff10092f29975928a3 GIT binary patch literal 1069 zcmV+|1k(HL9Sa~6ct0tPXrGT=NN2Sq?qXT)&{ElHx;)NBQxX@qWn)^icFN&AvsqV@ zw;LG_>n3Mj6P+o?vCg_ShmPSrMST~nIEi=HI4(`R^@1141 zY;kSu@4B#tmajUuHWSxtmPFp6&-_b8bl7VQjK&z-7a^>O)07IR$?3@Nlq>YYm!SWuB*SY++Z!OFE4P z1T_1g>BothtHk?RRAj14VcVsi0xDQN<~({R&2)A0u(hSH>R`r`?lQkf$1JHI44?CI zw4#xF9zj_9=yX7A7T2K_w_d-!CgMyiy`AG9RVq1k2Y%3qzRS?%0C`>-p9{px=&Cpk zY0(~S5t?Eu3LWsL4Z3$dn(~j|Bj?EpIz=P>xoWyB?>AFcbvN8aP1s zz^s!3zVd$mq=;K+lAan+506UJII+{~qTOz*xMvTB4ixJz6^lXYS_Y_c{tYZN180l+h&t)^!+v{tNG_ zVeIkD>B_)anNMknw5Nt#zR&`=O$vW!(J%s@VA0`e`(WWp#f5DqBkUNeIOMugSQ%h8 zZW%mHkD1x8Nx5l*Hz#)CDIsRPzDCS-ViGl^Y1xl7x7Y7FETLg~VJD8m2%(;UarlLj z^oq;ZrhuI|(h{05HiDB@ub9Z-k?c@HN0PkQ?f-^{Hx1!I!IB!cOo!~n z+lgjN27Ml#j!7me+j%&TpxmVxYBOU8Z^~fXcqY5ncLZcLX`cu4QUELFRSH%+@h^MY zrW}yAs3-QsIu|B9EWe~AdAUxA_l;RI>uwMqSGmtSK{4jmx$b&gz^z#u!E*kAMl_oH n+7w1I4AlcQ}x5eHD>U|iC=ROD8-~ViL-puE1 zjRYA__oQ{&>YEB=3*aLuz4zyXJp13Xu1};#Rhix|mTnwF zOo!rp*PZhF=TqnOy;6>9pEFaaeUqI8B!YL)2W zP7ZdtNvU6;rei#QejpQ1yJnKOE~NTM%dWXRuhSpl)r~@J@cfJn0Ny~Wi$|AEsLzhu zri&m6gnDM>m?;94<~TB71LK+=ROn-XNSxENOU6sujQmH^hn%vbF>Y9-Bf>bg4ep_N_banGD$o@)BlG0~`IFf*!A z7ZZY+$P{3oO)_oT873jzel8_va>@^q&Gy#Imx?o3b8wLzzbGT44Do}*$X0h~ljl$J4Xnb zbD&&|U+WJ#!b4}YW@ms{4#Dg|)FPD1`RJ15X*j-TWXe#-24_NUqwu$E^5|c&ujkvl zceVJ-2*h=M!1)}1Jc%#TSUTePk+ypzC+V()i{5ms{n@u^D(o_E@REe_Kn#k!Ic_d< z)NYD&D%@ZnqX*t~i*(5TV|DgDW2`fY!|?bmYqXwpi(E6b%BbX-wveIk57S|?#u}7- zL{;=f|DL5<#-Qjb!HsV;5xKrj*@u^N&pjiq)f!%|U1|gQA`KAPM`;y5?oy)&(mYZ0 z_?_gKiO6R;)m}AtC+IwYu6c3Nlk}=l5*$k#%8*z(mO5DYDWih#pN0k_;dS~5vECO-S0Dj5 literal 0 HcmV?d00001 diff --git a/github.com/klauspost/compress/flate/testdata/huffman-rand-1k.in b/github.com/klauspost/compress/flate/testdata/huffman-rand-1k.in new file mode 100644 index 0000000000000000000000000000000000000000..ce038ebb5bd911cd054b86c044fd26e6003225e2 GIT binary patch literal 1000 zcmV&K%;#;51Q|(x zM;}NPu;`xhFDh+BMJ6ccYFsSUg>Bfi<~bp&jg-~DiA=I+_Co^FF# z)zpAln0JXoILWUtGMXS8Mm=Y4*K(dtAy3BO)O!Str33Z_n`_)ElXocnv|`#I=O3$U zQA0T|pppS>bw2bp{X;JIq;=Zrn+jwL;3Fx$_veE=``@#!Pozgxncgp!ZX82QhvIzM zUrc=HkOSK=mDVB*N4QOEy(AHOADFT(|I5J=Zkm4@Lua&RXMk7^!R$cPB9zMc=#u1VIKF3O%23A!XF_hH@V9L8=wGp~=i9q?wfM^j z#C3ka`5b>di7(PvI^y_|wtFNe>8^x}-gK<}*|%vb>@sigl7#U<42rxtZZ31wZi;j& z++ZK02i|pybjbc=b@n}DtTTzj@c1ojw4QW}Tr;%FsN|WpkfHAn(_ym48kBrQRrE#w zo~2sGpy(>Wjc+s&xxP->hnI8DJtMBw8eXnlY6JNq4G`H!X%#>2QlkjcJW=%co#dE_ z$Y(j#UNv|p=sbX~d2!N{^r}%397`MJZWV9jyHT4(pZUa$D*GDWRnth5CjlnHYgKKc z`-F?ho+!fa8YJwSuDxLC6*cZcq%&Lk54QIKrUFdLkXSmFLFdZ}jN64xsEPBnj{S98 zPwn16>o}vnuyg#lRQF6UXD&FRR2aGlzw$ZN{-r_2W@fs9?`P!ZJPgXD3VE|vi;8ua W7(y>8qk`|Bh6W?yb@~Xg-WN)Vp#LfW literal 0 HcmV?d00001 diff --git a/github.com/klauspost/compress/flate/testdata/huffman-rand-1k.sync.expect b/github.com/klauspost/compress/flate/testdata/huffman-rand-1k.sync.expect new file mode 100644 index 0000000000000000000000000000000000000000..09dc798ee37df82176b8b7c9998c88a14207c1ad GIT binary patch literal 1005 zcmVlcQ}x5eHD>U|iC=ROD8-~ViL-puE1 zjRYA__oQ{&>YEB=3*aLuz4zyXJp13Xu1};#Rhix|mTnwF zOo!rp*PZhF=TqnOy;6>9pEFaaeUqI8B!YL)2W zP7ZdtNvU6;rei#QejpQ1yJnKOE~NTM%dWXRuhSpl)r~@J@cfJn0Ny~Wi$|AEsLzhu zri&m6gnDM>m?;94<~TB71LK+=ROn-XNSxENOU6sujQmH^hn%vbF>Y9-Bf>bg4ep_N_banGD$o@)BlG0~`IFf*!A z7ZZY+$P{3oO)_oT873jzel8_va>@^q&Gy#Imx?o3b8wLzzbGT44Do}*$X0h~ljl$J4Xnb zbD&&|U+WJ#!b4}YW@ms{4#Dg|)FPD1`RJ15X*j-TWXe#-24_NUqwu$E^5|c&ujkvl zceVJ-2*h=M!1)}1Jc%#TSUTePk+ypzC+V()i{5ms{n@u^D(o_E@REe_Kn#k!Ic_d< z)NYD&D%@ZnqX*t~i*(5TV|DgDW2`fY!|?bmYqXwpi(E6b%BbX-wveIk57S|?#u}7- zL{;=f|DL5<#-Qjb!HsV;5xKrj*@u^N&pjiq)f!%|U1|gQA`KAPM`;y5?oy)&(mYZ0 z_?_gKiO6R;)m}AtC+IwYu6c3Nlk}=l5*$k#%8*z(mO5DYDWih#pN0k_;dS~5vECO-S0Dj5 literal 0 HcmV?d00001 diff --git a/github.com/klauspost/compress/flate/testdata/huffman-rand-1k.sync.expect-noinput b/github.com/klauspost/compress/flate/testdata/huffman-rand-1k.sync.expect-noinput new file mode 100644 index 0000000000000000000000000000000000000000..0c24742fde2487e3a454ec3364f15e541693c37c GIT binary patch literal 1054 zcmV+(1mXJxzzaAU2mk=!nayIXbMy_f)7H$mL&SF;F?3`%k8@)&&%@Oe(UOiioadDG zS>BI}35WJ&PF@*1*&LbA=aF5pFj3x*HIFRrKcto>d1~bp8)vlgPG~al`sLh_uD4>f zwcquqQs)bz`O{dU_?0E5ZyfOj3vL$R|;Io1R(-}eKi+pE+?-hv`IeFsDFRE4SU5j~y=5(3C6?qYw^br64(dswwJMG1iwh9bz5{6%{CK{d z?OTrws1RG0;tdgAc^^}S;a;h-Le*Jl$;@?4WVbi2?}j$(yZ8P0lo@^JyA?I@?GEt7oU6m&;AhmaN!WN2o4Ue&a8T%J8g~M#1p4zh)_hxG4z2`Ogny za;mxRW4Md@6TRsPIrIrmbY`0*@-5uMh;C)*<4Qh|=G6i5GP){GL)z@9EkaXFMahfN zv?c%P&)d;?j&h!ypwqm%P^YHL3jM3}%*^0B)TTYwcr0m+>#+B{By^cDULDE6Dg;&& zO=u{r#qY9CX2q~>M2)v~oJjxXwYfA4W6UEykUq9QGg?N01rigUU44BE!qnW&8XUe) zez=s$?Lpl~RS(YSo`<)!77bHS>Gu?tEqHX60yc4tb%nr56)BI?!K^R=U-@BSOT=w5 zsVIvXfM*tHgqR0EakjC|{oW&au|@y5MGR8cGC-Yn06%^E0PC$!Cb-Z0wr}jN>)ms9 zL;@;_wIK!J>p%w{0>eRLG6F9RY`9EcFXkV~=#m(_eoQp~r+?KjZg}QSSL~iFyscF_ z+e_{^90j}~rTuecm=4dkoD6jMc=)XI@ePwzb~aU<_(Cb{iZR=;j^CkY@49GGUfJU< zh|_pVqS;)85%YqWL`@t%i6ZSgMZJLK5AGbA<2Z~&Y6y(OZ<17W7CzqwPW|%tkU??k z4*_!bQ%1vsp<0>Q04?4|yQkkrm{&#|cY?4524U<_tm@Hqt*?a07|`vlpP7J3xS#y+ zPf2l=uqk^9aS%w&GBx^|J3nR zNecGe6yILAWA?u!e(Cl<@PcA2?CSjWxPaGt_JWfJ*C8~T`^Pp$vI5uS*J~uVqo@>8 Yxt^P)DKm4sCRYuzNKydW#Fu~kAGX;UBLDyZ literal 0 HcmV?d00001 diff --git a/github.com/klauspost/compress/flate/testdata/huffman-rand-1k.wb.expect b/github.com/klauspost/compress/flate/testdata/huffman-rand-1k.wb.expect new file mode 100644 index 0000000000000000000000000000000000000000..09dc798ee37df82176b8b7c9998c88a14207c1ad GIT binary patch literal 1005 zcmVlcQ}x5eHD>U|iC=ROD8-~ViL-puE1 zjRYA__oQ{&>YEB=3*aLuz4zyXJp13Xu1};#Rhix|mTnwF zOo!rp*PZhF=TqnOy;6>9pEFaaeUqI8B!YL)2W zP7ZdtNvU6;rei#QejpQ1yJnKOE~NTM%dWXRuhSpl)r~@J@cfJn0Ny~Wi$|AEsLzhu zri&m6gnDM>m?;94<~TB71LK+=ROn-XNSxENOU6sujQmH^hn%vbF>Y9-Bf>bg4ep_N_banGD$o@)BlG0~`IFf*!A z7ZZY+$P{3oO)_oT873jzel8_va>@^q&Gy#Imx?o3b8wLzzbGT44Do}*$X0h~ljl$J4Xnb zbD&&|U+WJ#!b4}YW@ms{4#Dg|)FPD1`RJ15X*j-TWXe#-24_NUqwu$E^5|c&ujkvl zceVJ-2*h=M!1)}1Jc%#TSUTePk+ypzC+V()i{5ms{n@u^D(o_E@REe_Kn#k!Ic_d< z)NYD&D%@ZnqX*t~i*(5TV|DgDW2`fY!|?bmYqXwpi(E6b%BbX-wveIk57S|?#u}7- zL{;=f|DL5<#-Qjb!HsV;5xKrj*@u^N&pjiq)f!%|U1|gQA`KAPM`;y5?oy)&(mYZ0 z_?_gKiO6R;)m}AtC+IwYu6c3Nlk}=l5*$k#%8*z(mO5DYDWih#pN0k_;dS~5vECO-S0Dj5 literal 0 HcmV?d00001 diff --git a/github.com/klauspost/compress/flate/testdata/huffman-rand-1k.wb.expect-noinput b/github.com/klauspost/compress/flate/testdata/huffman-rand-1k.wb.expect-noinput new file mode 100644 index 0000000000000000000000000000000000000000..0c24742fde2487e3a454ec3364f15e541693c37c GIT binary patch literal 1054 zcmV+(1mXJxzzaAU2mk=!nayIXbMy_f)7H$mL&SF;F?3`%k8@)&&%@Oe(UOiioadDG zS>BI}35WJ&PF@*1*&LbA=aF5pFj3x*HIFRrKcto>d1~bp8)vlgPG~al`sLh_uD4>f zwcquqQs)bz`O{dU_?0E5ZyfOj3vL$R|;Io1R(-}eKi+pE+?-hv`IeFsDFRE4SU5j~y=5(3C6?qYw^br64(dswwJMG1iwh9bz5{6%{CK{d z?OTrws1RG0;tdgAc^^}S;a;h-Le*Jl$;@?4WVbi2?}j$(yZ8P0lo@^JyA?I@?GEt7oU6m&;AhmaN!WN2o4Ue&a8T%J8g~M#1p4zh)_hxG4z2`Ogny za;mxRW4Md@6TRsPIrIrmbY`0*@-5uMh;C)*<4Qh|=G6i5GP){GL)z@9EkaXFMahfN zv?c%P&)d;?j&h!ypwqm%P^YHL3jM3}%*^0B)TTYwcr0m+>#+B{By^cDULDE6Dg;&& zO=u{r#qY9CX2q~>M2)v~oJjxXwYfA4W6UEykUq9QGg?N01rigUU44BE!qnW&8XUe) zez=s$?Lpl~RS(YSo`<)!77bHS>Gu?tEqHX60yc4tb%nr56)BI?!K^R=U-@BSOT=w5 zsVIvXfM*tHgqR0EakjC|{oW&au|@y5MGR8cGC-Yn06%^E0PC$!Cb-Z0wr}jN>)ms9 zL;@;_wIK!J>p%w{0>eRLG6F9RY`9EcFXkV~=#m(_eoQp~r+?KjZg}QSSL~iFyscF_ z+e_{^90j}~rTuecm=4dkoD6jMc=)XI@ePwzb~aU<_(Cb{iZR=;j^CkY@49GGUfJU< zh|_pVqS;)85%YqWL`@t%i6ZSgMZJLK5AGbA<2Z~&Y6y(OZ<17W7CzqwPW|%tkU??k z4*_!bQ%1vsp<0>Q04?4|yQkkrm{&#|cY?4524U<_tm@Hqt*?a07|`vlpP7J3xS#y+ zPf2l=uqk^9aS%w&GBx^|J3nR zNecGe6yILAWA?u!e(Cl<@PcA2?CSjWxPaGt_JWfJ*C8~T`^Pp$vI5uS*J~uVqo@>8 Yxt^P)DKm4sCRYuzNKydW#Fu~kAGX;UBLDyZ literal 0 HcmV?d00001 diff --git a/github.com/klauspost/compress/flate/testdata/huffman-rand-limit.dyn.expect b/github.com/klauspost/compress/flate/testdata/huffman-rand-limit.dyn.expect new file mode 100644 index 0000000000000000000000000000000000000000..57e59322e9884ed96ccace7d6054ca9223128a33 GIT binary patch literal 252 zcmZSh&cN|Mk$QmZNB6Wc53bfJstxN8{p)?9@LIg>oXRI~IhW&XxGJNu5- o$p8QV literal 0 HcmV?d00001 diff --git a/github.com/klauspost/compress/flate/testdata/huffman-rand-limit.dyn.expect-noinput b/github.com/klauspost/compress/flate/testdata/huffman-rand-limit.dyn.expect-noinput new file mode 100644 index 0000000..008b9af --- /dev/null +++ b/github.com/klauspost/compress/flate/testdata/huffman-rand-limit.dyn.expect-noinput @@ -0,0 +1 @@ +쀚athúg{µ5³Ù ÍFköVklÍkFkÖ]wݱ3:ÔÝUǺÎfg۾϶ñÞ…–#@éïC$ðî÷,"‘KB¢Ç¿gÙsû‹žO à8¼<ì}®«à4q×Ë`äX!5i)Š»‚ŽŽà c|D?;3fôm¨`¾jɎѰ<ñ«‘ql]*î Ê—EDý'|B¬aÒ`Ë$!“wl¼†ó¿GÝ?ý€ŸõDVê›Ö‚ šÿ‹0WL¿ÈÀ˜CˆµKdöÆâá)+ňÅéŠxŽˆä \ No newline at end of file diff --git a/github.com/klauspost/compress/flate/testdata/huffman-rand-limit.golden b/github.com/klauspost/compress/flate/testdata/huffman-rand-limit.golden new file mode 100644 index 0000000000000000000000000000000000000000..7ef674504988ad857ed31f4a47a1ea7f9f99dec6 GIT binary patch literal 239 zcmZQMz?vY$$lwsj{Q6Cv<3{1#h6Wp~1zz9gN>bW(qwz*>Qh7pxxmsC51J?|NUGEZZ zGc#a-mXynVmR^ZZw`IA_Rz55<<&XB>QD{;1<^Df}U+zn| zsvBNgAQ`%wCtFl^j#=bl+ex2dZ~0xRot61EcIWxz{n?EtYE06T^tzvAzg^olEAh8P izlwt0+Ly~SZaz3L?M>8Pn|+xPf%Y#u?g?+=hy(xtQf=e_ literal 0 HcmV?d00001 diff --git a/github.com/klauspost/compress/flate/testdata/huffman-rand-limit.in b/github.com/klauspost/compress/flate/testdata/huffman-rand-limit.in new file mode 100644 index 0000000..fb5b1be --- /dev/null +++ b/github.com/klauspost/compress/flate/testdata/huffman-rand-limit.in @@ -0,0 +1,4 @@ +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +ø‹–vH +…”%€¯Âþè ë†É·ÅÞê}‹ç>ÚßÿlsÞÌçmIGH°èžò1YÞ4´[åà 0ˆ[|]o#© +¼-#¾Ùíul™ßýpfæîÙ±žnƒYÕÔ€Y˜w‰C8ɯ02š F=gn×ržN!OÆàÔ{¥ö›kÜ*“w(ý´bÚ ç«kQC9/ ’lu>ô5ýC.÷¤uÚê› diff --git a/github.com/klauspost/compress/flate/testdata/huffman-rand-limit.sync.expect b/github.com/klauspost/compress/flate/testdata/huffman-rand-limit.sync.expect new file mode 100644 index 0000000000000000000000000000000000000000..2d6527934e98300d744c7558a025250f67e0f1c9 GIT binary patch literal 229 zcmV+&C|&*fKV2Rd8oFPOxbQ)>6c^slqt_a&vbUd`qL0Dk3ZG5`Po literal 0 HcmV?d00001 diff --git a/github.com/klauspost/compress/flate/testdata/huffman-rand-limit.wb.expect-noinput b/github.com/klauspost/compress/flate/testdata/huffman-rand-limit.wb.expect-noinput new file mode 100644 index 0000000000000000000000000000000000000000..881e59c9ab9bb356c5f1b8f2e188818bd42dbcf0 GIT binary patch literal 186 zcmV;r07d^wq#oe<(LJrqgR6ClYQy?N|9W32ycTaex&7!pwpX+&C|&*fKV2Rd8oFPOxbQ)>6c^slqt_a&vbUd`qL0Dk3ZG5`Po literal 0 HcmV?d00001 diff --git a/github.com/klauspost/compress/flate/testdata/huffman-rand-max.golden b/github.com/klauspost/compress/flate/testdata/huffman-rand-max.golden new file mode 100644 index 0000000000000000000000000000000000000000..47d53c89c077d0e62aeaf818154f60921960de5c GIT binary patch literal 65540 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

-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 literal 0 HcmV?d00001 diff --git a/github.com/klauspost/compress/flate/testdata/huffman-rand-max.in b/github.com/klauspost/compress/flate/testdata/huffman-rand-max.in new file mode 100644 index 0000000000000000000000000000000000000000..8418633d2ac9791cc75a316d53c8490a328daa39 GIT binary patch literal 65535 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 literal 0 HcmV?d00001 diff --git a/github.com/klauspost/compress/flate/testdata/huffman-shifts.dyn.expect b/github.com/klauspost/compress/flate/testdata/huffman-shifts.dyn.expect new file mode 100644 index 0000000000000000000000000000000000000000..2f4fd17add552d86b47dcb321a4f50988aac86cc GIT binary patch literal 59 zcmaEJmpS2qfe6Ee&AGR?<<16^Kn4iitBcRIKKV790S0FH%{ITYgA>f1w#y6vcB~mT literal 0 HcmV?d00001 diff --git a/github.com/klauspost/compress/flate/testdata/huffman-shifts.dyn.expect-noinput b/github.com/klauspost/compress/flate/testdata/huffman-shifts.dyn.expect-noinput new file mode 100644 index 0000000000000000000000000000000000000000..2f4fd17add552d86b47dcb321a4f50988aac86cc GIT binary patch literal 59 zcmaEJmpS2qfe6Ee&AGR?<<16^Kn4iitBcRIKKV790S0FH%{ITYgA>f1w#y6vcB~mT literal 0 HcmV?d00001 diff --git a/github.com/klauspost/compress/flate/testdata/huffman-shifts.golden b/github.com/klauspost/compress/flate/testdata/huffman-shifts.golden new file mode 100644 index 0000000000000000000000000000000000000000..89c8addf0f8a4940ac23c7ac7330f5fcf22f7673 GIT binary patch literal 1826 zcmZQMz|6qV#(3nw&271A^MS-|7?RHQcNqnvAut*O!!QJ%oN$lGUc2>L)F?3;2BYZ! JcQ$yf001ub_}Tyf literal 0 HcmV?d00001 diff --git a/github.com/klauspost/compress/flate/testdata/huffman-shifts.in b/github.com/klauspost/compress/flate/testdata/huffman-shifts.in new file mode 100644 index 0000000..b9f23ee --- /dev/null +++ b/github.com/klauspost/compress/flate/testdata/huffman-shifts.in @@ -0,0 +1,2 @@ +101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010 +232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323232323 \ No newline at end of file diff --git a/github.com/klauspost/compress/flate/testdata/huffman-shifts.sync.expect b/github.com/klauspost/compress/flate/testdata/huffman-shifts.sync.expect new file mode 100644 index 0000000000000000000000000000000000000000..7812c1c62da3cbaeb6399e9aa8ab65ae7efa9b08 GIT binary patch literal 32 ocmaEJ(2|$IfP>+{UeCQBetd7^G}D{T$iTpm^J~2nL&Iw}0NYm#xc~qF literal 0 HcmV?d00001 diff --git a/github.com/klauspost/compress/flate/testdata/huffman-shifts.sync.expect-noinput b/github.com/klauspost/compress/flate/testdata/huffman-shifts.sync.expect-noinput new file mode 100644 index 0000000000000000000000000000000000000000..7812c1c62da3cbaeb6399e9aa8ab65ae7efa9b08 GIT binary patch literal 32 ocmaEJ(2|$IfP>+{UeCQBetd7^G}D{T$iTpm^J~2nL&Iw}0NYm#xc~qF literal 0 HcmV?d00001 diff --git a/github.com/klauspost/compress/flate/testdata/huffman-shifts.wb.expect b/github.com/klauspost/compress/flate/testdata/huffman-shifts.wb.expect new file mode 100644 index 0000000000000000000000000000000000000000..7812c1c62da3cbaeb6399e9aa8ab65ae7efa9b08 GIT binary patch literal 32 ocmaEJ(2|$IfP>+{UeCQBetd7^G}D{T$iTpm^J~2nL&Iw}0NYm#xc~qF literal 0 HcmV?d00001 diff --git a/github.com/klauspost/compress/flate/testdata/huffman-shifts.wb.expect-noinput b/github.com/klauspost/compress/flate/testdata/huffman-shifts.wb.expect-noinput new file mode 100644 index 0000000000000000000000000000000000000000..7812c1c62da3cbaeb6399e9aa8ab65ae7efa9b08 GIT binary patch literal 32 ocmaEJ(2|$IfP>+{UeCQBetd7^G}D{T$iTpm^J~2nL&Iw}0NYm#xc~qF literal 0 HcmV?d00001 diff --git a/github.com/klauspost/compress/flate/testdata/huffman-text-shift.dyn.expect b/github.com/klauspost/compress/flate/testdata/huffman-text-shift.dyn.expect new file mode 100644 index 0000000000000000000000000000000000000000..3a4dcc4cab48cb09c9db911a39299334b04be2e5 GIT binary patch literal 258 zcmW-Z?MlNi7)FQxEc7CbC>^ZLP%0=4>AJd2=ltlVf{2imG+}Ap5|Xki-i=q{eTk;~ zcb>!H>HYTh{xD9VZnY@6IT;SmS9}VIH5_!5NV(HmH$~)o7_WgDF2HI^p%5iBS{0-n z=abO1vJ0f3%5Xy!VPI7u+*r)hY?)_FNO$3THQkhzP#ub@25k_aZZNB;^Fja9_x2l2 zM%5;GeIu6DTgECCDl27JZ6l%3u85wsFadG=<$K9Eon%+j f+5Gxual5>`e|XGS>!+7(`*DB{f4+~7@g@2PbNEq% literal 0 HcmV?d00001 diff --git a/github.com/klauspost/compress/flate/testdata/huffman-text-shift.dyn.expect-noinput b/github.com/klauspost/compress/flate/testdata/huffman-text-shift.dyn.expect-noinput new file mode 100644 index 0000000..29788aa --- /dev/null +++ b/github.com/klauspost/compress/flate/testdata/huffman-text-shift.dyn.expect-noinput @@ -0,0 +1,2 @@ +ì`Ó@‡‚»¬…5R|@ו1Cºáš„4Ï’ÿò|Ê‚»»»»»»»»»»»´¸»ó.÷îzgEN‡L²ûøä ‘E#2¬EQ<Æ»D–¦8.IDH€Dà@. E^÷³û›ˆ®¸ @"òÒ  ‘ƒ­¶`»M +KS4åÂ*€n%P1n¤AAÐ`¬OS^.Ìûªa†JUxxç2›s˜4å%yWËç‹X+&FÖ$I…&¨)ŠI gd<l9 ˆ7ÒTCš²øYýmEŠ+T"¸d©Òeì!¡eˇëõÒ1é—Ș‰+Ä< \ No newline at end of file diff --git a/github.com/klauspost/compress/flate/testdata/huffman-text-shift.golden b/github.com/klauspost/compress/flate/testdata/huffman-text-shift.golden new file mode 100644 index 0000000000000000000000000000000000000000..80531ad983afe811bf96c8b78d005237cf827d12 GIT binary patch literal 252 zcmVkO_LjXZYOV&+7A%K9GA;yKoBnTit z7S&8bovz*xIKo_wGLxO{I;ggYsOIrh@wgyxpomVjqL}RC!YN@3A(OhPWf*QVMJ7~o zLEu1gD^7${bwSV<0&lc0#@`^eVO*oe@l6t%Hf!D@keJl6b&B1qlvMiAlCtHLdQvKt CAa`5< literal 0 HcmV?d00001 diff --git a/github.com/klauspost/compress/flate/testdata/huffman-text-shift.in b/github.com/klauspost/compress/flate/testdata/huffman-text-shift.in new file mode 100644 index 0000000..9d1c422 --- /dev/null +++ b/github.com/klauspost/compress/flate/testdata/huffman-text-shift.in @@ -0,0 +1,14 @@ +//Copyright2009ThGoAuthor.Allrightrrvd. +//UofthiourccodigovrndbyBSD-tyl +//licnthtcnbfoundinthLICENSEfil. + +pckgmin + +import"o" + +funcmin(){ + vrb=mk([]byt,65535) + f,_:=o.Crt("huffmn-null-mx.in") + f.Writ(b) +} +ABCDEFGHIJKLMNOPQRSTUVXxyz!"#¤%&/?" \ No newline at end of file diff --git a/github.com/klauspost/compress/flate/testdata/huffman-text-shift.sync.expect b/github.com/klauspost/compress/flate/testdata/huffman-text-shift.sync.expect new file mode 100644 index 0000000000000000000000000000000000000000..71ce3aeb75a86e8375d9ac4350b7d83b9229a3ed GIT binary patch literal 231 zcmVb2j)h-%-Q8H+K zIkmg!?Y-=9be1Hi$&iwP9DQ6&foC2grh=5#ja@KiZ1-F{b`bob2j)h-%-Q8H+K zIkmg!?Y-=9be1Hi$&iwP9DQ6&foC2grh=5#ja@KiZ1-F{b`bob2j)h-%-Q8H+K zIkmg!?Y-=9be1Hi$&iwP9DQ6&foC2grh=5#ja@KiZ1-F{b`bob2j)h-%-Q8H+K zIkmg!?Y-=9be1Hi$&iwP9DQ6&foC2grh=5#ja@KiZ1-F{b`boC4xc^H5L)XOBD|yvPpiMEZyve{Syr0TlzfGZI0i} ze9YP9`QQI)g;Ecb5pCyiwO-%iwIe)gY`yEWu{pLx6~X z-qeIzH-vz#9?2+bP)%UC-#=v5O_F9!ikehVUB?`1rce>M_NswUAtXFMmAjYy4qQkI zPjNJ``oLO3&xAU$=m%{a5^a+ca>*K^5fGEeh&Bf_8x@Eb=*!%AHu literal 0 HcmV?d00001 diff --git a/github.com/klauspost/compress/flate/testdata/huffman-text.dyn.expect-noinput b/github.com/klauspost/compress/flate/testdata/huffman-text.dyn.expect-noinput new file mode 100644 index 0000000..6ef6dd4 --- /dev/null +++ b/github.com/klauspost/compress/flate/testdata/huffman-text.dyn.expect-noinput @@ -0,0 +1,3 @@ +ì`ÓJô|à®b¬éâFîÃ=M/MXš+¹K¡¸»»»»»»»»»»ËŠ»;çïÞ¹û™Í`Å.&;$ +üý³A A :•°F8Tð¢ hˆ Íì˘ÍP– À"PI&@°® lG p`7ÒTd›xÈœÏD¨GA^kŠ, •  OAàU°!±®ÚAVJвQVÇ2,ãâ…ÞÀÉËj(,;]X£`ÀÄ +Šº*xqF_¨Ç2>n^€“AÆÊUmŠü ³Å’ÑâË2>¢T‡ì€ gÕO‘Ñ é¢èäU“ª+ŠÉÉ×ádÕà5Ê•×dŠŒ6_–iÀ2 \ No newline at end of file diff --git a/github.com/klauspost/compress/flate/testdata/huffman-text.golden b/github.com/klauspost/compress/flate/testdata/huffman-text.golden new file mode 100644 index 0000000000000000000000000000000000000000..b440e84d53a9d43aa0edb5c13d861d5a49f7831a GIT binary patch literal 270 zcmV+p0rCC>zy)B_KokH_9CmQH>!(-?TQa2hfKi6~aKEOP=2)cUE`{Rm?(XjH?(XjH z?ha3u!DodcHVbM3%EZQ2f)*NuIu^t`LbGfxLA-iEICnkW(bShzlQHUr>BuK#^%)|&IW`rzTfXm`8j4)CiQvri8)9ry?7)6DN z4St9NgCtRR`;PvIpwUp?>n-c`U=*cBLuaTQ2NsunHYI|(U7Dk+1~FqyN7rKv(nDgV U%Y#vrDz&zmpl-hhqdpk@2R^2E-2eap literal 0 HcmV?d00001 diff --git a/github.com/klauspost/compress/flate/testdata/huffman-text.in b/github.com/klauspost/compress/flate/testdata/huffman-text.in new file mode 100644 index 0000000..e76d564 --- /dev/null +++ b/github.com/klauspost/compress/flate/testdata/huffman-text.in @@ -0,0 +1,13 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +import "os" + +func main() { + var b = make([]byte, 65535) + f, _ := os.Create("huffman-null-max.in") + f.Write(b) +} diff --git a/github.com/klauspost/compress/flate/testdata/huffman-text.sync.expect b/github.com/klauspost/compress/flate/testdata/huffman-text.sync.expect new file mode 100644 index 0000000..d448727 --- /dev/null +++ b/github.com/klauspost/compress/flate/testdata/huffman-text.sync.expect @@ -0,0 +1 @@ +Ë_Kó0Åñëò½ê`KÇó0AasÄ›)^ˆHšþ²„¥IÉŸbß»¬—_>ç4 a˜¢=›Œ›Í-^ á1`_² 1 ìÃÌ ‘Å‘:ÁYÓà-‚F66!…A…Ž`Îa¤è©C;Aâþô°Nyr4ßœUä!™¡¤GKСøÖ#ÂóÓáør:B[G‚3Ω.òLè¥õ×¶ýbFRuM]¼š­^⇳Å(#ZìÐË ÕŸí”i…›íöÿvÉÙB¯ð…»B‡H2S]™¢u/ýÚçÖ½üÖWóT¼G›©n—œýrö \ No newline at end of file diff --git a/github.com/klauspost/compress/flate/testdata/huffman-text.sync.expect-noinput b/github.com/klauspost/compress/flate/testdata/huffman-text.sync.expect-noinput new file mode 100644 index 0000000..d448727 --- /dev/null +++ b/github.com/klauspost/compress/flate/testdata/huffman-text.sync.expect-noinput @@ -0,0 +1 @@ +Ë_Kó0Åñëò½ê`KÇó0AasÄ›)^ˆHšþ²„¥IÉŸbß»¬—_>ç4 a˜¢=›Œ›Í-^ á1`_² 1 ìÃÌ ‘Å‘:ÁYÓà-‚F66!…A…Ž`Îa¤è©C;Aâþô°Nyr4ßœUä!™¡¤GKСøÖ#ÂóÓáør:B[G‚3Ω.òLè¥õ×¶ýbFRuM]¼š­^⇳Å(#ZìÐË ÕŸí”i…›íöÿvÉÙB¯ð…»B‡H2S]™¢u/ýÚçÖ½üÖWóT¼G›©n—œýrö \ No newline at end of file diff --git a/github.com/klauspost/compress/flate/testdata/huffman-text.wb.expect b/github.com/klauspost/compress/flate/testdata/huffman-text.wb.expect new file mode 100644 index 0000000..d448727 --- /dev/null +++ b/github.com/klauspost/compress/flate/testdata/huffman-text.wb.expect @@ -0,0 +1 @@ +Ë_Kó0Åñëò½ê`KÇó0AasÄ›)^ˆHšþ²„¥IÉŸbß»¬—_>ç4 a˜¢=›Œ›Í-^ á1`_² 1 ìÃÌ ‘Å‘:ÁYÓà-‚F66!…A…Ž`Îa¤è©C;Aâþô°Nyr4ßœUä!™¡¤GKСøÖ#ÂóÓáør:B[G‚3Ω.òLè¥õ×¶ýbFRuM]¼š­^⇳Å(#ZìÐË ÕŸí”i…›íöÿvÉÙB¯ð…»B‡H2S]™¢u/ýÚçÖ½üÖWóT¼G›©n—œýrö \ No newline at end of file diff --git a/github.com/klauspost/compress/flate/testdata/huffman-text.wb.expect-noinput b/github.com/klauspost/compress/flate/testdata/huffman-text.wb.expect-noinput new file mode 100644 index 0000000..d448727 --- /dev/null +++ b/github.com/klauspost/compress/flate/testdata/huffman-text.wb.expect-noinput @@ -0,0 +1 @@ +Ë_Kó0Åñëò½ê`KÇó0AasÄ›)^ˆHšþ²„¥IÉŸbß»¬—_>ç4 a˜¢=›Œ›Í-^ á1`_² 1 ìÃÌ ‘Å‘:ÁYÓà-‚F66!…A…Ž`Îa¤è©C;Aâþô°Nyr4ßœUä!™¡¤GKСøÖ#ÂóÓáør:B[G‚3Ω.òLè¥õ×¶ýbFRuM]¼š­^⇳Å(#ZìÐË ÕŸí”i…›íöÿvÉÙB¯ð…»B‡H2S]™¢u/ýÚçÖ½üÖWóT¼G›©n—œýrö \ No newline at end of file diff --git a/github.com/klauspost/compress/flate/testdata/huffman-zero.dyn.expect b/github.com/klauspost/compress/flate/testdata/huffman-zero.dyn.expect new file mode 100644 index 0000000000000000000000000000000000000000..230433ca0c4dc164e29ff3722e5e24ba4a30ad90 GIT binary patch literal 313 RcmZQDVLbiMU=)xX0suzCJHG$` literal 0 HcmV?d00001 diff --git a/github.com/klauspost/compress/flate/testdata/huffman-zero.dyn.expect-noinput b/github.com/klauspost/compress/flate/testdata/huffman-zero.dyn.expect-noinput new file mode 100644 index 0000000..cefc1d3 --- /dev/null +++ b/github.com/klauspost/compress/flate/testdata/huffman-zero.dyn.expect-noinput @@ -0,0 +1 @@ +ì€@h¶mÛæÛ¶mÛ¶mÛ¶mÛ¶mÛ¶ÑÙ6úrk† \ No newline at end of file diff --git a/github.com/klauspost/compress/flate/testdata/huffman-zero.golden b/github.com/klauspost/compress/flate/testdata/huffman-zero.golden new file mode 100644 index 0000000000000000000000000000000000000000..f0dacf2b4947dc8d55fd159448a07ec89dd5c2da GIT binary patch literal 66 fcmZQMz|0`Pz`(E|_qN&XZMg{K1{5R$e2@nKWF`$B literal 0 HcmV?d00001 diff --git a/github.com/klauspost/compress/flate/testdata/huffman-zero.in b/github.com/klauspost/compress/flate/testdata/huffman-zero.in new file mode 100644 index 0000000..349be0e --- /dev/null +++ b/github.com/klauspost/compress/flate/testdata/huffman-zero.in @@ -0,0 +1 @@ +00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 \ No newline at end of file diff --git a/github.com/klauspost/compress/flate/testdata/huffman-zero.sync.expect b/github.com/klauspost/compress/flate/testdata/huffman-zero.sync.expect new file mode 100644 index 0000000000000000000000000000000000000000..830348a79ad9ab38d0edc449e8335c056f7d185f GIT binary patch literal 17 XcmaEJU?T$%G#D)X^D^m0zK$>eMUV%O literal 0 HcmV?d00001 diff --git a/github.com/klauspost/compress/flate/testdata/huffman-zero.sync.expect-noinput b/github.com/klauspost/compress/flate/testdata/huffman-zero.sync.expect-noinput new file mode 100644 index 0000000000000000000000000000000000000000..830348a79ad9ab38d0edc449e8335c056f7d185f GIT binary patch literal 17 XcmaEJU?T$%G#D)X^D^m0zK$>eMUV%O literal 0 HcmV?d00001 diff --git a/github.com/klauspost/compress/flate/testdata/huffman-zero.wb.expect b/github.com/klauspost/compress/flate/testdata/huffman-zero.wb.expect new file mode 100644 index 0000000000000000000000000000000000000000..dbe401c54c4b6f45f3169376185a476dcf00dde9 GIT binary patch literal 6 NcmXq#U{zse0006o0CxZY literal 0 HcmV?d00001 diff --git a/github.com/klauspost/compress/flate/testdata/huffman-zero.wb.expect-noinput b/github.com/klauspost/compress/flate/testdata/huffman-zero.wb.expect-noinput new file mode 100644 index 0000000000000000000000000000000000000000..dbe401c54c4b6f45f3169376185a476dcf00dde9 GIT binary patch literal 6 NcmXq#U{zse0006o0CxZY literal 0 HcmV?d00001 diff --git a/github.com/klauspost/compress/flate/testdata/null-long-match.dyn.expect-noinput b/github.com/klauspost/compress/flate/testdata/null-long-match.dyn.expect-noinput new file mode 100644 index 0000000000000000000000000000000000000000..14167a3344bcdc219ee9fd904418ae61298e584d GIT binary patch literal 227 pcmaEJmzm*#1p~u|?YXzj&TY%RjX-Ntw(Z^4&&V*8!2!wR3;?2K6tDmQ literal 0 HcmV?d00001 diff --git a/github.com/klauspost/compress/flate/testdata/null-long-match.sync.expect-noinput b/github.com/klauspost/compress/flate/testdata/null-long-match.sync.expect-noinput new file mode 100644 index 0000000000000000000000000000000000000000..8b92d9fc20f1ee1fea5e4cc84d18aeea26a6fdaa GIT binary patch literal 206 ccmaEJz>txFf#HzC@8#d3xFvwhAq<`X0E^!Sx&QzG literal 0 HcmV?d00001 diff --git a/github.com/klauspost/compress/flate/testdata/null-long-match.wb.expect-noinput b/github.com/klauspost/compress/flate/testdata/null-long-match.wb.expect-noinput new file mode 100644 index 0000000000000000000000000000000000000000..8b92d9fc20f1ee1fea5e4cc84d18aeea26a6fdaa GIT binary patch literal 206 ccmaEJz>txFf#HzC@8#d3xFvwhAq<`X0E^!Sx&QzG literal 0 HcmV?d00001 diff --git a/github.com/klauspost/compress/flate/testdata/regression.zip b/github.com/klauspost/compress/flate/testdata/regression.zip new file mode 100644 index 0000000000000000000000000000000000000000..a7be57703cdc61f1366600f3e1abe9fd5c25e564 GIT binary patch literal 475404 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