From ce3936e0fb39bc9a04289913c2d1aba662ef2dab Mon Sep 17 00:00:00 2001 From: Mike Hommey Date: Tue, 13 Aug 2024 15:03:42 +0000 Subject: [PATCH] Bug 1910796 - Integrate libz-rs-sys as a replacement for zlib. r=supply-chain-reviewers,firefox-build-system-reviewers,nika,sergesanspaille Nightly-only for now. Differential Revision: https://phabricator.services.mozilla.com/D218165 --- .cargo/config.toml.in | 5 + Cargo.lock | 14 + config/makefiles/rust.mk | 3 + js/src/build/moz.build | 6 +- modules/freetype2/moz.build | 3 +- moz.configure | 7 + supply-chain/audits.toml | 24 + supply-chain/config.toml | 6 + supply-chain/imports.lock | 14 + .../rust/libz-rs-sys/.cargo-checksum.json | 1 + third_party/rust/libz-rs-sys/Cargo.toml | 69 + third_party/rust/libz-rs-sys/LICENSE | 19 + third_party/rust/libz-rs-sys/README.md | 90 + .../rust/libz-rs-sys/examples/compress.rs | 295 + .../rust/libz-rs-sys/examples/crc32_bench.rs | 61 + .../rust/libz-rs-sys/examples/uncompress.rs | 111 + third_party/rust/libz-rs-sys/src/lib.rs | 673 ++ .../rust/libz-rs-sys/src/tests/deflate.rs | 1616 ++++ .../rust/libz-rs-sys/src/tests/inflate.rs | 1812 ++++ third_party/rust/libz-rs-sys/src/tests/mod.rs | 2 + .../src/tests/test-data/issue-109.gz | Bin 0 -> 42537 bytes .../src/tests/test-data/op-len-edge-case.zraw | Bin 0 -> 633 bytes .../src/tests/test-data/window-match-bug.zraw | Bin 0 -> 304 bytes third_party/rust/zlib-rs/.cargo-checksum.json | 1 + third_party/rust/zlib-rs/Cargo.toml | 63 + third_party/rust/zlib-rs/LICENSE | 19 + third_party/rust/zlib-rs/README.md | 6 + third_party/rust/zlib-rs/src/adler32.rs | 133 + third_party/rust/zlib-rs/src/adler32/avx2.rs | 258 + .../rust/zlib-rs/src/adler32/generic.rs | 136 + third_party/rust/zlib-rs/src/adler32/neon.rs | 243 + third_party/rust/zlib-rs/src/allocate.rs | 357 + third_party/rust/zlib-rs/src/c_api.rs | 228 + third_party/rust/zlib-rs/src/crc32.rs | 259 + third_party/rust/zlib-rs/src/crc32/acle.rs | 181 + third_party/rust/zlib-rs/src/crc32/braid.rs | 178 + third_party/rust/zlib-rs/src/crc32/combine.rs | 115 + .../rust/zlib-rs/src/crc32/pclmulqdq.rs | 342 + third_party/rust/zlib-rs/src/deflate.rs | 4431 ++++++++++ .../zlib-rs/src/deflate/algorithm/fast.rs | 109 + .../zlib-rs/src/deflate/algorithm/huff.rs | 45 + .../zlib-rs/src/deflate/algorithm/medium.rs | 339 + .../rust/zlib-rs/src/deflate/algorithm/mod.rs | 83 + .../zlib-rs/src/deflate/algorithm/quick.rs | 149 + .../rust/zlib-rs/src/deflate/algorithm/rle.rs | 83 + .../zlib-rs/src/deflate/algorithm/slow.rs | 160 + .../zlib-rs/src/deflate/algorithm/stored.rs | 271 + .../rust/zlib-rs/src/deflate/compare256.rs | 216 + .../rust/zlib-rs/src/deflate/hash_calc.rs | 209 + .../rust/zlib-rs/src/deflate/longest_match.rs | 318 + .../rust/zlib-rs/src/deflate/pending.rs | 95 + .../rust/zlib-rs/src/deflate/slide_hash.rs | 164 + .../src/deflate/test-data/fireworks.jpg | Bin 0 -> 123093 bytes .../deflate/test-data/inflate_buf_error.dat | Bin 0 -> 67008 bytes .../zlib-rs/src/deflate/test-data/lcet10.txt | 7519 +++++++++++++++++ .../src/deflate/test-data/paper-100k.pdf | 598 ++ .../read_buf_window_uninitialized.txt | Bin 0 -> 10119 bytes .../zlib-ng/CVE-2018-25032/default.txt | 1 + .../zlib-ng/CVE-2018-25032/fixed.txt | 1 + .../test-data/zlib-ng/GH-382/defneg3.dat | 1 + .../rust/zlib-rs/src/deflate/trees_tbl.rs | 140 + .../rust/zlib-rs/src/deflate/window.rs | 146 + third_party/rust/zlib-rs/src/inflate.rs | 2284 +++++ .../rust/zlib-rs/src/inflate/bitreader.rs | 203 + .../rust/zlib-rs/src/inflate/inffixed_tbl.rs | 555 ++ .../rust/zlib-rs/src/inflate/inftrees.rs | 358 + .../rust/zlib-rs/src/inflate/window.rs | 267 + third_party/rust/zlib-rs/src/lib.rs | 193 + third_party/rust/zlib-rs/src/read_buf.rs | 553 ++ toolkit/library/moz.build | 6 +- toolkit/library/rust/gkrust-features.mozbuild | 3 + toolkit/library/rust/shared/Cargo.toml | 2 + toolkit/library/rust/shared/lib.rs | 3 + 73 files changed, 26852 insertions(+), 3 deletions(-) create mode 100644 third_party/rust/libz-rs-sys/.cargo-checksum.json create mode 100644 third_party/rust/libz-rs-sys/Cargo.toml create mode 100644 third_party/rust/libz-rs-sys/LICENSE create mode 100644 third_party/rust/libz-rs-sys/README.md create mode 100644 third_party/rust/libz-rs-sys/examples/compress.rs create mode 100644 third_party/rust/libz-rs-sys/examples/crc32_bench.rs create mode 100644 third_party/rust/libz-rs-sys/examples/uncompress.rs create mode 100644 third_party/rust/libz-rs-sys/src/lib.rs create mode 100644 third_party/rust/libz-rs-sys/src/tests/deflate.rs create mode 100644 third_party/rust/libz-rs-sys/src/tests/inflate.rs create mode 100644 third_party/rust/libz-rs-sys/src/tests/mod.rs create mode 100644 third_party/rust/libz-rs-sys/src/tests/test-data/issue-109.gz create mode 100644 third_party/rust/libz-rs-sys/src/tests/test-data/op-len-edge-case.zraw create mode 100644 third_party/rust/libz-rs-sys/src/tests/test-data/window-match-bug.zraw create mode 100644 third_party/rust/zlib-rs/.cargo-checksum.json create mode 100644 third_party/rust/zlib-rs/Cargo.toml create mode 100644 third_party/rust/zlib-rs/LICENSE create mode 100644 third_party/rust/zlib-rs/README.md create mode 100644 third_party/rust/zlib-rs/src/adler32.rs create mode 100644 third_party/rust/zlib-rs/src/adler32/avx2.rs create mode 100644 third_party/rust/zlib-rs/src/adler32/generic.rs create mode 100644 third_party/rust/zlib-rs/src/adler32/neon.rs create mode 100644 third_party/rust/zlib-rs/src/allocate.rs create mode 100644 third_party/rust/zlib-rs/src/c_api.rs create mode 100644 third_party/rust/zlib-rs/src/crc32.rs create mode 100644 third_party/rust/zlib-rs/src/crc32/acle.rs create mode 100644 third_party/rust/zlib-rs/src/crc32/braid.rs create mode 100644 third_party/rust/zlib-rs/src/crc32/combine.rs create mode 100644 third_party/rust/zlib-rs/src/crc32/pclmulqdq.rs create mode 100644 third_party/rust/zlib-rs/src/deflate.rs create mode 100644 third_party/rust/zlib-rs/src/deflate/algorithm/fast.rs create mode 100644 third_party/rust/zlib-rs/src/deflate/algorithm/huff.rs create mode 100644 third_party/rust/zlib-rs/src/deflate/algorithm/medium.rs create mode 100644 third_party/rust/zlib-rs/src/deflate/algorithm/mod.rs create mode 100644 third_party/rust/zlib-rs/src/deflate/algorithm/quick.rs create mode 100644 third_party/rust/zlib-rs/src/deflate/algorithm/rle.rs create mode 100644 third_party/rust/zlib-rs/src/deflate/algorithm/slow.rs create mode 100644 third_party/rust/zlib-rs/src/deflate/algorithm/stored.rs create mode 100644 third_party/rust/zlib-rs/src/deflate/compare256.rs create mode 100644 third_party/rust/zlib-rs/src/deflate/hash_calc.rs create mode 100644 third_party/rust/zlib-rs/src/deflate/longest_match.rs create mode 100644 third_party/rust/zlib-rs/src/deflate/pending.rs create mode 100644 third_party/rust/zlib-rs/src/deflate/slide_hash.rs create mode 100644 third_party/rust/zlib-rs/src/deflate/test-data/fireworks.jpg create mode 100644 third_party/rust/zlib-rs/src/deflate/test-data/inflate_buf_error.dat create mode 100644 third_party/rust/zlib-rs/src/deflate/test-data/lcet10.txt create mode 100644 third_party/rust/zlib-rs/src/deflate/test-data/paper-100k.pdf create mode 100644 third_party/rust/zlib-rs/src/deflate/test-data/read_buf_window_uninitialized.txt create mode 100644 third_party/rust/zlib-rs/src/deflate/test-data/zlib-ng/CVE-2018-25032/default.txt create mode 100644 third_party/rust/zlib-rs/src/deflate/test-data/zlib-ng/CVE-2018-25032/fixed.txt create mode 100644 third_party/rust/zlib-rs/src/deflate/test-data/zlib-ng/GH-382/defneg3.dat create mode 100644 third_party/rust/zlib-rs/src/deflate/trees_tbl.rs create mode 100644 third_party/rust/zlib-rs/src/deflate/window.rs create mode 100644 third_party/rust/zlib-rs/src/inflate.rs create mode 100644 third_party/rust/zlib-rs/src/inflate/bitreader.rs create mode 100644 third_party/rust/zlib-rs/src/inflate/inffixed_tbl.rs create mode 100644 third_party/rust/zlib-rs/src/inflate/inftrees.rs create mode 100644 third_party/rust/zlib-rs/src/inflate/window.rs create mode 100644 third_party/rust/zlib-rs/src/lib.rs create mode 100644 third_party/rust/zlib-rs/src/read_buf.rs diff --git a/.cargo/config.toml.in b/.cargo/config.toml.in index 0bd2de35796a..3b618b22f758 100644 --- a/.cargo/config.toml.in +++ b/.cargo/config.toml.in @@ -50,6 +50,11 @@ git = "https://github.com/jfkthame/mapped_hyph.git" rev = "eff105f6ad7ec9b79816cfc1985a28e5340ad14b" replace-with = "vendored-sources" +[source."git+https://github.com/memorysafety/zlib-rs?rev=692b0fd5a367cf4714b0b24e9e498e2a064d673c"] +git = "https://github.com/memorysafety/zlib-rs" +rev = "692b0fd5a367cf4714b0b24e9e498e2a064d673c" +replace-with = "vendored-sources" + [source."git+https://github.com/mozilla-spidermonkey/jsparagus?rev=61f399c53a641ebd3077c1f39f054f6d396a633c"] git = "https://github.com/mozilla-spidermonkey/jsparagus" rev = "61f399c53a641ebd3077c1f39f054f6d396a633c" diff --git a/Cargo.lock b/Cargo.lock index 6683d87493e7..6e64bc40bc47 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2333,6 +2333,7 @@ dependencies = [ "kvstore", "l10nregistry", "l10nregistry-ffi", + "libz-rs-sys", "lmdb-rkv-sys", "localization-ffi", "log", @@ -3418,6 +3419,14 @@ dependencies = [ "libc", ] +[[package]] +name = "libz-rs-sys" +version = "0.2.1" +source = "git+https://github.com/memorysafety/zlib-rs?rev=692b0fd5a367cf4714b0b24e9e498e2a064d673c#692b0fd5a367cf4714b0b24e9e498e2a064d673c" +dependencies = [ + "zlib-rs", +] + [[package]] name = "line-wrap" version = "0.1.1" @@ -7228,3 +7237,8 @@ dependencies = [ "memchr", "thiserror", ] + +[[package]] +name = "zlib-rs" +version = "0.2.1" +source = "git+https://github.com/memorysafety/zlib-rs?rev=692b0fd5a367cf4714b0b24e9e498e2a064d673c#692b0fd5a367cf4714b0b24e9e498e2a064d673c" diff --git a/config/makefiles/rust.mk b/config/makefiles/rust.mk index 524bc436fdf3..b794b9329782 100644 --- a/config/makefiles/rust.mk +++ b/config/makefiles/rust.mk @@ -261,6 +261,9 @@ export IPHONEOS_SDK_DIR PATH := $(topsrcdir)/build/macosx:$(PATH) endif endif +# Use the same prefix as set through modules/zlib/src/mozzconf.h +# for libz-rs-sys, since we still use the headers from there. +export LIBZ_RS_SYS_PREFIX=MOZ_Z_ ifndef RUSTC_BOOTSTRAP RUSTC_BOOTSTRAP := mozglue_static,qcms diff --git a/js/src/build/moz.build b/js/src/build/moz.build index 49cbbb2c6c45..0a08b233e154 100644 --- a/js/src/build/moz.build +++ b/js/src/build/moz.build @@ -53,9 +53,13 @@ if CONFIG["JS_HAS_INTL_API"]: USE_LIBS += [ "fdlibm", "nspr", - "zlib", ] +if not CONFIG["USE_LIBZ_RS"]: + USE_LIBS += [ + "zlib", + ] + if CONFIG["OS_ARCH"] != "WINNT": OS_LIBS += [ "m", diff --git a/modules/freetype2/moz.build b/modules/freetype2/moz.build index dfa53dfd89c1..188c60c3402e 100644 --- a/modules/freetype2/moz.build +++ b/modules/freetype2/moz.build @@ -84,7 +84,8 @@ SOURCES += [ # zlib library DEFINES['FT_CONFIG_OPTION_SYSTEM_ZLIB'] = True CFLAGS += CONFIG['MOZ_ZLIB_CFLAGS'] -USE_LIBS += ['zlib'] +if not CONFIG["USE_LIBZ_RS"]: + USE_LIBS += ['zlib'] # png library DEFINES['FT_CONFIG_OPTION_USE_PNG'] = True diff --git a/moz.configure b/moz.configure index 0b33ce9c58fa..5470a3a3d2e4 100755 --- a/moz.configure +++ b/moz.configure @@ -896,6 +896,13 @@ pkg_check_modules("MOZ_ZLIB", "zlib >= 1.2.3", when="--with-system-zlib") set_config("MOZ_SYSTEM_ZLIB", True, when="--with-system-zlib") +@depends(with_system_zlib_option, milestone.is_nightly, when=toolkit) +def use_libz_rs(system_zlib, is_nightly): + return not system_zlib and is_nightly + + +set_config("USE_LIBZ_RS", True, when=use_libz_rs) + with only_when(cross_compiling): option( env="JS_BINARY", diff --git a/supply-chain/audits.toml b/supply-chain/audits.toml index 0e35caf73c16..4d0ce468f285 100644 --- a/supply-chain/audits.toml +++ b/supply-chain/audits.toml @@ -2769,6 +2769,12 @@ who = "Mark Hammond " criteria = "safe-to-deploy" delta = "0.27.0 -> 0.28.0" +[[audits.libz-rs-sys]] +who = "Mike Hommey " +criteria = "safe-to-deploy" +delta = "0.2.1 -> 0.2.1@git:692b0fd5a367cf4714b0b24e9e498e2a064d673c" +importable = false + [[audits.linked-hash-map]] who = "Aria Beingessner " criteria = "safe-to-deploy" @@ -5410,6 +5416,12 @@ non-1-byte-aligned type, however right now that is not the case (submitted https://github.com/zip-rs/zip2/issues/198). """ +[[audits.zlib-rs]] +who = "Mike Hommey " +criteria = "safe-to-deploy" +delta = "0.2.1 -> 0.2.1@git:692b0fd5a367cf4714b0b24e9e498e2a064d673c" +importable = false + [[trusted.aho-corasick]] criteria = "safe-to-deploy" user-id = 189 # Andrew Gallant (BurntSushi) @@ -5566,6 +5578,12 @@ user-id = 51017 # Yuki Okushi (JohnTitor) start = "2020-03-17" end = "2024-10-25" +[[trusted.libz-rs-sys]] +criteria = "safe-to-deploy" +user-id = 1303 # Ruben Nijveld (rnijveld) +start = "2024-02-23" +end = "2024-09-01" + [[trusted.linux-raw-sys]] criteria = "safe-to-deploy" user-id = 6825 # Dan Gohman (sunfishcode) @@ -5871,3 +5889,9 @@ criteria = "safe-to-deploy" user-id = 64539 # Kenny Kerr (kennykerr) start = "2021-11-15" end = "2024-09-12" + +[[trusted.zlib-rs]] +criteria = "safe-to-deploy" +user-id = 1303 # Ruben Nijveld (rnijveld) +start = "2024-02-23" +end = "2024-09-01" diff --git a/supply-chain/config.toml b/supply-chain/config.toml index 7af8497ea5c1..ee194cfe03bc 100644 --- a/supply-chain/config.toml +++ b/supply-chain/config.toml @@ -98,6 +98,9 @@ notes = "This crate has two testing-only dependencies which are specified as reg audit-as-crates-io = false notes = "This override is an api-compatible fork with an orthogonal implementation." +[policy."libz-rs-sys:0.2.1@git:692b0fd5a367cf4714b0b24e9e498e2a064d673c"] +audit-as-crates-io = true + [policy.malloc_size_of_derive] audit-as-crates-io = false notes = "This was originally servo code which Bobby Holley put on crates.io some years ago and that was moved in-tree as first-party code later on." @@ -231,6 +234,9 @@ notes = "Local override of the crates.io crate that uses a non-vendored local co [policy.wr_malloc_size_of] audit-as-crates-io = false +[policy."zlib-rs:0.2.1@git:692b0fd5a367cf4714b0b24e9e498e2a064d673c"] +audit-as-crates-io = true + [[exemptions.ahash]] version = "0.7.6" criteria = "safe-to-deploy" diff --git a/supply-chain/imports.lock b/supply-chain/imports.lock index 8fbe764d76b4..c822ac550170 100644 --- a/supply-chain/imports.lock +++ b/supply-chain/imports.lock @@ -316,6 +316,13 @@ user-id = 51017 user-login = "JohnTitor" user-name = "Yuki Okushi" +[[publisher.libz-rs-sys]] +version = "0.2.1" +when = "2024-07-08" +user-id = 1303 +user-login = "rnijveld" +user-name = "Ruben Nijveld" + [[publisher.linux-raw-sys]] version = "0.4.12" when = "2023-11-30" @@ -798,6 +805,13 @@ user-id = 48 user-login = "badboy" user-name = "Jan-Erik Rediger" +[[publisher.zlib-rs]] +version = "0.2.1" +when = "2024-07-08" +user-id = 1303 +user-login = "rnijveld" +user-name = "Ruben Nijveld" + [[audits.bytecode-alliance.wildcard-audits.arbitrary]] who = "Nick Fitzgerald " criteria = "safe-to-deploy" diff --git a/third_party/rust/libz-rs-sys/.cargo-checksum.json b/third_party/rust/libz-rs-sys/.cargo-checksum.json new file mode 100644 index 000000000000..e98231fc5229 --- /dev/null +++ b/third_party/rust/libz-rs-sys/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{"Cargo.toml":"fae5e9fa3b75aef7028e3d109e1cefbd37dd879ee8e1b9e2783786514e543b1c","LICENSE":"7d60612df8fcd9d3714871a95b4d3012563246fdea8f6710b7567f83cfa3c8ef","README.md":"e6dcd6f09a9fd73b6571826bbadb3e19afebce521a6ce87028f6bcb4240c272a","examples/compress.rs":"b4bd15580da75e6a1dab7063f5f49c801a0073f3c87a1246e11e2012bc980cc7","examples/crc32_bench.rs":"26c57ba94a3ca6353f227627a3c064e3c4812807c3a4975a63f6bf2ef26c47a2","examples/uncompress.rs":"b78027d7a3d0e82b7f77d1114aa13ea778d8d11fa178e2d44d8acd4a3a728bb6","src/lib.rs":"24b70f484fb4e43d59e97bbb7d208889da8ebaad1b8e3bcae7afb4b64b7c1519","src/tests/deflate.rs":"c51a3e281b7858cee54c28e02269be8fbac41dfb77ee63a86c1f6aad1fce0606","src/tests/inflate.rs":"17690a215a2f676f1e485081af9df434a685339f5912b8eff4080113dbf66c56","src/tests/mod.rs":"b50934837e152598f9825927eb559cbc738c8484ca21aaaacaa2a7be02b1513a","src/tests/test-data/issue-109.gz":"b34d11c665984769dfe84384130077621ac30dbf9bf1580b54cd95a2e7fa6959","src/tests/test-data/op-len-edge-case.zraw":"01fe65d328666e5f0ec685b5523198002f9ff280688a7d948b75573fbebdfb12","src/tests/test-data/window-match-bug.zraw":"40a844f32fb06b1c5a2c9896fb2bdf5e5e5dcae37d365df99519818c961c296a"},"package":null} \ No newline at end of file diff --git a/third_party/rust/libz-rs-sys/Cargo.toml b/third_party/rust/libz-rs-sys/Cargo.toml new file mode 100644 index 000000000000..2f9753c4c421 --- /dev/null +++ b/third_party/rust/libz-rs-sys/Cargo.toml @@ -0,0 +1,69 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g., crates.io) dependencies. +# +# If you are reading this file be aware that the original Cargo.toml +# will likely look very different (and much more reasonable). +# See Cargo.toml.orig for the original contents. + +[package] +edition = "2021" +rust-version = "1.75" +name = "libz-rs-sys" +version = "0.2.1" +publish = true +description = "A memory-safe zlib implementation written in rust" +homepage = "https://github.com/memorysafety/zlib-rs" +readme = "README.md" +license = "Zlib" +repository = "https://github.com/memorysafety/zlib-rs" + +[lib] +crate-type = [ + "rlib", + "cdylib", +] + +[dependencies.zlib-rs] +version = "0.2.1" +path = "../zlib-rs" +default-features = false + +[dev-dependencies] +crc32fast = "1.3.2" +libloading = "0.8.1" + +[dev-dependencies.dynamic-libz-sys] +path = "../dynamic-libz-sys" + +[dev-dependencies.libz-sys] +version = "1.1.12" +features = ["zlib-ng"] +default-features = false + +[dev-dependencies.quickcheck] +version = "1.0.3" +features = [] +default-features = false + +[dev-dependencies.zlib-rs] +version = "0.2.1" +path = "../zlib-rs" +features = [ + "std", + "__internal-test", +] +default-features = false + +[features] +c-allocator = ["zlib-rs/c-allocator"] +custom-prefix = [] +default = [ + "std", + "rust-allocator", +] +rust-allocator = ["zlib-rs/rust-allocator"] +std = ["zlib-rs/std"] diff --git a/third_party/rust/libz-rs-sys/LICENSE b/third_party/rust/libz-rs-sys/LICENSE new file mode 100644 index 000000000000..8079b948a62e --- /dev/null +++ b/third_party/rust/libz-rs-sys/LICENSE @@ -0,0 +1,19 @@ +(C) 2024 Internet Security Research Group + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any damages +arising from the use of this software. + +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it +freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + +2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + +3. This notice may not be removed or altered from any source distribution. diff --git a/third_party/rust/libz-rs-sys/README.md b/third_party/rust/libz-rs-sys/README.md new file mode 100644 index 000000000000..2df5c510208f --- /dev/null +++ b/third_party/rust/libz-rs-sys/README.md @@ -0,0 +1,90 @@ +This crate is a C API for [zlib-rs](https://docs.rs/zlib-rs/latest/zlib_rs/). The API is broadly equivalent to [`zlib-sys`](https://docs.rs/libz-sys/latest/libz_sys/) and [`zlib-ng-sys`](https://docs.rs/libz-ng-sys/latest/libz_ng_sys/), but does not currently provide the `gz*` family of functions. + +From a rust perspective, this API is not very ergonomic. Use the [`flate2`](https://crates.io/crates/flate2) crate for a more +ergonomic rust interface to zlib. + +# Features + +**`custom-prefix`** + +Add a custom prefix to all exported symbols. + +The value of the `LIBZ_RS_SYS_PREFIX` is used as a prefix for all exported symbols. For example: + +``` +> LIBZ_RS_SYS_PREFIX="MY_CUSTOM_PREFIX" cargo build -p libz-rs-sys --features=custom-prefix + Compiling libz-rs-sys v0.2.1 (/home/folkertdev/rust/zlib-rs/libz-rs-sys) + Finished `dev` profile [optimized + debuginfo] target(s) in 0.21s +> objdump -tT target/debug/liblibz_rs_sys.so | grep "uncompress" +0000000000081028 l O .got 0000000000000000 _ZN7zlib_rs7inflate10uncompress17he7d985e55c58a189E$got +000000000002c570 l F .text 00000000000001ef _ZN7zlib_rs7inflate10uncompress17he7d985e55c58a189E +0000000000024330 g F .text 000000000000008e MY_CUSTOM_PREFIXuncompress +0000000000024330 g DF .text 000000000000008e Base MY_CUSTOM_PREFIXuncompress +``` + +**`c-allocator`, `rust-allocator`** + +Pick the default allocator implementation that is used if no `zalloc` and `zfree` are configured in the input `z_stream`. + +- `c-allocator`: use `malloc`/`free` for the implementation of `zalloc` and `zfree` +- `rust-allocator`: the rust global allocator for the implementation of `zalloc` and `zfree` + +The `rust-allocator` is the default when this crate is used as a rust dependency, and slightly more efficient because alignment is handled by the allocator. When building a dynamic library, it may make sense to use `c-allocator` instead. + +**`std`** + +Assume that `std` is available. When this feature is turned off, this crate is compatible with `#![no_std]`. + +# Example + +This example compresses ("deflates") the string `"Hello, World!"` and then decompresses +("inflates") it again. + +```rust +let mut strm = libz_rs_sys::z_stream::default(); + +let version = libz_rs_sys::zlibVersion(); +let stream_size = core::mem::size_of_val(&strm) as i32; + +let level = 6; // the default compression level +let err = unsafe { libz_rs_sys::deflateInit_(&mut strm, level, version, stream_size) }; +assert_eq!(err, libz_rs_sys::Z_OK); + +let input = "Hello, World!"; +strm.avail_in = input.len() as _; +strm.next_in = input.as_ptr(); + +let mut output = [0u8; 32]; +strm.avail_out = output.len() as _; +strm.next_out = output.as_mut_ptr(); + +let err = unsafe { libz_rs_sys::deflate(&mut strm, libz_rs_sys::Z_FINISH) }; +assert_eq!(err, libz_rs_sys::Z_STREAM_END); + +let err = unsafe { libz_rs_sys::deflateEnd(&mut strm) }; +assert_eq!(err, libz_rs_sys::Z_OK); + +let deflated = &mut output[..strm.total_out as usize]; + +let mut strm = libz_rs_sys::z_stream::default(); +let err = unsafe { libz_rs_sys::inflateInit_(&mut strm, version, stream_size) }; +assert_eq!(err, libz_rs_sys::Z_OK); + +strm.avail_in = deflated.len() as _; +strm.next_in = deflated.as_ptr(); + +let mut output = [0u8; 32]; +strm.avail_out = output.len() as _; +strm.next_out = output.as_mut_ptr(); + +let err = unsafe { libz_rs_sys::inflate(&mut strm, libz_rs_sys::Z_FINISH) }; +assert_eq!(err, libz_rs_sys::Z_STREAM_END); + +let err = unsafe { libz_rs_sys::inflateEnd(&mut strm) }; +assert_eq!(err, libz_rs_sys::Z_OK); + +let inflated = &output[..strm.total_out as usize]; + +assert_eq!(inflated, input.as_bytes()) +``` + diff --git a/third_party/rust/libz-rs-sys/examples/compress.rs b/third_party/rust/libz-rs-sys/examples/compress.rs new file mode 100644 index 000000000000..5ffafcc2b317 --- /dev/null +++ b/third_party/rust/libz-rs-sys/examples/compress.rs @@ -0,0 +1,295 @@ +//! a binary just so we can look at the optimized assembly + +use std::{collections::hash_map::DefaultHasher, env::temp_dir, hash::Hash}; + +// we use the libz_sys but configure zlib-ng in zlib compat mode +use libz_sys as libz_ng_sys; + +use zlib_rs::{deflate::DeflateConfig, DeflateFlush, ReturnCode}; + +use std::ffi::{c_int, c_uint}; + +fn main() { + let mut it = std::env::args(); + + let _ = it.next().unwrap(); + + let level: i32 = it.next().unwrap().parse().unwrap(); + + let mut hasher = DefaultHasher::new(); + use std::hash::Hasher; + + match it.next().unwrap().as_str() { + "ng" => { + let path = it.next().unwrap(); + let input = std::fs::read(path).unwrap(); + + let mut dest_vec = vec![0u8; 1 << 28]; + let mut dest_len = dest_vec.len(); + + let err = compress_ng(&mut dest_vec, &mut dest_len, &input, level); + + if err != ReturnCode::Ok { + panic!("error {err:?}"); + } + + dest_vec.truncate(dest_len); + + dest_vec.hash(&mut hasher); + dbg!(hasher.finish()); + + std::fs::write(temp_dir().join("ng.txt"), &dest_vec).unwrap(); + + drop(dest_vec) + } + "rs" => { + let path = it.next().unwrap(); + let Ok(input) = std::fs::read(&path) else { + panic!("could not read file {path:?}"); + }; + + let mut dest_vec = vec![0u8; 1 << 28]; + let mut dest_len = dest_vec.len(); + + let err = compress_rs(&mut dest_vec, &mut dest_len, &input, level); + + if err != ReturnCode::Ok { + panic!("error {err:?}"); + } + + dest_vec.truncate(dest_len); + + dest_vec.hash(&mut hasher); + dbg!(hasher.finish()); + + std::fs::write(temp_dir().join("rs.txt"), &dest_vec).unwrap(); + + drop(dest_vec) + } + "xx" => { + let path = it.next().unwrap(); + let Ok(input) = std::fs::read(&path) else { + panic!("could not read file {path:?}"); + }; + + let mut dest_vec = vec![0u8; 1 << 28]; + let mut dest_len = dest_vec.len(); + + let err = compress_dynamic(&mut dest_vec, &mut dest_len, &input, level); + + if err != ReturnCode::Ok { + panic!("error {err:?}"); + } + + dest_vec.truncate(dest_len); + + dest_vec.hash(&mut hasher); + dbg!(hasher.finish()); + + std::fs::write(temp_dir().join("xx.tar.gz"), &dest_vec).unwrap(); + + drop(dest_vec) + } + "qq" => { + let ng = std::fs::read(temp_dir().join("ng.txt")).unwrap(); + let rs = std::fs::read(temp_dir().join("rs.txt")).unwrap(); + + for (i, (a, b)) in (ng.iter().zip(rs.iter())).enumerate() { + if a != b { + panic!("index {i}"); + } + } + } + other => panic!("invalid option '{other}', expected one of 'rs' or 'ng'"), + } +} + +const METHOD: i32 = zlib_rs::c_api::Z_DEFLATED; +const WINDOW_BITS: i32 = 15; +const MEM_LEVEL: i32 = 8; +const STRATEGY: i32 = zlib_rs::c_api::Z_DEFAULT_STRATEGY; + +fn compress_rs( + dest: &mut [u8], + dest_len: &mut usize, + source: &[u8], + // + level: i32, +) -> ReturnCode { + use libz_rs_sys::{deflate, deflateEnd, deflateInit2_, z_stream, zlibVersion}; + + let mut stream = z_stream { + next_in: source.as_ptr() as *mut u8, + avail_in: 0, // for special logic in the first iteration + total_in: 0, + next_out: dest.as_mut_ptr(), + avail_out: 0, // for special logic on the first iteration + total_out: 0, + msg: std::ptr::null_mut(), + state: std::ptr::null_mut(), + zalloc: Some(zlib_rs::allocate::zalloc_c), + zfree: Some(zlib_rs::allocate::zfree_c), + opaque: std::ptr::null_mut(), + data_type: 0, + adler: 0, + reserved: 0, + }; + + let err = { + let strm: *mut z_stream = &mut stream; + unsafe { + deflateInit2_( + strm, + level, + METHOD, + WINDOW_BITS, + MEM_LEVEL, + STRATEGY, + zlibVersion(), + std::mem::size_of::() as c_int, + ) + } + }; + + if ReturnCode::from(err) != ReturnCode::Ok as _ { + return ReturnCode::from(err); + } + + let max = c_uint::MAX as usize; + + let mut left = dest.len(); + let mut source_len = source.len(); + + loop { + if stream.avail_out == 0 { + stream.avail_out = Ord::min(left, max) as _; + left -= stream.avail_out as usize; + } + + if stream.avail_in == 0 { + stream.avail_in = Ord::min(source_len, max) as _; + source_len -= stream.avail_in as usize; + } + + let flush = if source_len > 0 { + DeflateFlush::NoFlush + } else { + DeflateFlush::Finish + }; + + let err = unsafe { deflate(&mut stream, flush as i32) }; + if ReturnCode::from(err) != ReturnCode::Ok { + break; + } + } + + *dest_len = stream.total_out as _; + + unsafe { deflateEnd(&mut stream) }; + + ReturnCode::Ok +} + +fn compress_ng( + dest: &mut [u8], + dest_len: &mut usize, + source: &[u8], + // + level: i32, +) -> ReturnCode { + use libz_ng_sys::{deflate, deflateEnd, deflateInit2_, z_stream, zlibVersion}; + + let mut stream = z_stream { + next_in: source.as_ptr() as *mut u8, + avail_in: 0, // for special logic in the first iteration + total_in: 0, + next_out: dest.as_mut_ptr(), + avail_out: 0, // for special logic on the first iteration + total_out: 0, + msg: std::ptr::null_mut(), + state: std::ptr::null_mut(), + zalloc: zlib_rs::allocate::zalloc_c, + zfree: zlib_rs::allocate::zfree_c, + opaque: std::ptr::null_mut(), + data_type: 0, + adler: 0, + reserved: 0, + }; + + let err = { + let strm: *mut z_stream = &mut stream; + unsafe { + deflateInit2_( + strm, + level, + METHOD, + WINDOW_BITS, + MEM_LEVEL, + STRATEGY, + zlibVersion(), + std::mem::size_of::() as c_int, + ) + } + }; + + if ReturnCode::from(err) != ReturnCode::Ok as _ { + return ReturnCode::from(err); + } + + let max = c_uint::MAX as usize; + + let mut left = dest.len(); + let mut source_len = source.len(); + + loop { + if stream.avail_out == 0 { + stream.avail_out = Ord::min(left, max) as _; + left -= stream.avail_out as usize; + } + + if stream.avail_in == 0 { + stream.avail_in = Ord::min(source_len, max) as _; + source_len -= stream.avail_in as usize; + } + + let flush = if source_len > 0 { + DeflateFlush::NoFlush + } else { + DeflateFlush::Finish + }; + + let err = unsafe { deflate(&mut stream, flush as i32) }; + if ReturnCode::from(err) != ReturnCode::Ok { + break; + } + } + + *dest_len = stream.total_out as _; + + unsafe { deflateEnd(&mut stream) }; + + ReturnCode::Ok +} + +fn compress_dynamic( + dest: &mut [u8], + dest_len: &mut usize, + source: &[u8], + // + level: i32, +) -> ReturnCode { + let config = DeflateConfig::new(level); + let (output, err) = dynamic_libz_sys::compress_slice( + dest, + source, + config.level, + config.method as i32, + config.window_bits, + config.mem_level, + config.strategy as i32, + ); + + *dest_len = output.len(); + + ReturnCode::from(err) +} diff --git a/third_party/rust/libz-rs-sys/examples/crc32_bench.rs b/third_party/rust/libz-rs-sys/examples/crc32_bench.rs new file mode 100644 index 000000000000..032c2cac4daf --- /dev/null +++ b/third_party/rust/libz-rs-sys/examples/crc32_bench.rs @@ -0,0 +1,61 @@ +//! a binary just so we can look at the optimized assembly + +pub fn main() { + let mut it = std::env::args(); + + let _ = it.next().unwrap(); + + match it.next().unwrap().as_str() { + "sse" => { + let path = it.next().unwrap(); + let input = std::fs::read(path).unwrap(); + + let mut state = zlib_rs::crc32::Crc32Fold::new(); + state.fold(&input, 0); + println!("{:#x}", state.finish()); + } + + "crc32fast" => { + let path = it.next().unwrap(); + let input = std::fs::read(path).unwrap(); + + let mut h = crc32fast::Hasher::new_with_initial(0); + h.update(&input[..]); + println!("{:#x}", h.finalize()); + } + + "sse-chunked" => { + let path = it.next().unwrap(); + let input = std::fs::read(path).unwrap(); + + let mut state = zlib_rs::crc32::Crc32Fold::new(); + + for c in input.chunks(32) { + state.fold(c, 0); + } + println!("{:#x}", state.finish()); + } + + "crc32fast-chunked" => { + let path = it.next().unwrap(); + let input = std::fs::read(path).unwrap(); + + let mut h = crc32fast::Hasher::new_with_initial(0); + + for c in input.chunks(32) { + h.update(c); + } + println!("{:#x}", h.finalize()); + } + + "adler32" => { + let path = it.next().unwrap(); + let input = std::fs::read(path).unwrap(); + + let h = zlib_rs::adler32(42, &input); + println!("{:#x}", h); + } + + other => panic!("invalid option '{other}', expected one of 'rs' or 'ng'"), + } +} diff --git a/third_party/rust/libz-rs-sys/examples/uncompress.rs b/third_party/rust/libz-rs-sys/examples/uncompress.rs new file mode 100644 index 000000000000..da9a425a025a --- /dev/null +++ b/third_party/rust/libz-rs-sys/examples/uncompress.rs @@ -0,0 +1,111 @@ +//! a binary just so we can look at the optimized assembly + +// we use the libz_sys but configure zlib-ng in zlib compat mode +use libz_sys as libz_ng_sys; + +use std::{ffi::c_ulong, path::PathBuf}; + +unsafe fn uncompress( + dest: *mut u8, + dest_len: *mut std::ffi::c_ulong, + source: *const u8, + source_len: std::ffi::c_ulong, +) -> std::ffi::c_int { + let lib = libloading::Library::new("/home/folkertdev/rust/zlib-ng/libz-ng.so").unwrap(); + + type Func = unsafe extern "C" fn( + dest: *mut u8, + dest_len: *mut std::ffi::c_ulong, + source: *const u8, + source_len: std::ffi::c_ulong, + ) -> std::ffi::c_int; + + let f: libloading::Symbol = lib.get(b"zng_uncompress").unwrap(); + + f(dest, dest_len, source, source_len) +} + +fn main() { + let mut it = std::env::args(); + + let _ = it.next().unwrap(); + + match it.next().unwrap().as_str() { + "ng" => { + let path = it.next().unwrap(); + let input = std::fs::read(&path).unwrap(); + + let mut dest_vec = vec![0u8; 1 << 28]; + + let mut dest_len = dest_vec.len() as c_ulong; + let dest = dest_vec.as_mut_ptr(); + + let source = input.as_ptr(); + let source_len = input.len() as _; + + let err = unsafe { libz_ng_sys::uncompress(dest, &mut dest_len, source, source_len) }; + + if err != 0 { + panic!("error {err}"); + } + + dest_vec.truncate(dest_len as usize); + + let path = PathBuf::from(path); + std::fs::write(path.with_extension(""), &dest_vec).unwrap(); + + drop(dest_vec) + } + "rs" => { + let path = it.next().unwrap(); + let input = std::fs::read(&path).unwrap(); + + let mut dest_vec = vec![0u8; 1 << 28]; + + let mut dest_len = dest_vec.len() as std::ffi::c_ulong; + let dest = dest_vec.as_mut_ptr(); + + let source = input.as_ptr(); + let source_len = input.len() as _; + + let err = unsafe { ::libz_rs_sys::uncompress(dest, &mut dest_len, source, source_len) }; + + if err != 0 { + panic!("error {err}"); + } + + dest_vec.truncate(dest_len as usize); + + let path = PathBuf::from(path); + std::fs::write(path.with_extension(""), &dest_vec).unwrap(); + + drop(dest_vec) + } + "xx" => { + let path = it.next().unwrap(); + let input = std::fs::read(&path).unwrap(); + + let mut dest_vec = vec![0u8; 1 << 28]; + + let mut dest_len = dest_vec.len() as std::ffi::c_ulong; + let dest = dest_vec.as_mut_ptr(); + + let source = input.as_ptr(); + let source_len = input.len() as _; + + let err = unsafe { uncompress(dest, &mut dest_len, source, source_len) }; + + if err != 0 { + panic!(); + } + + dest_vec.truncate(dest_len as usize); + + let path = PathBuf::from(path); + std::fs::write(path.with_extension(""), &dest_vec).unwrap(); + + drop(dest_vec) + } + other => panic!("invalid option '{other}', expected one of 'rs' or 'ng'"), + } +} diff --git a/third_party/rust/libz-rs-sys/src/lib.rs b/third_party/rust/libz-rs-sys/src/lib.rs new file mode 100644 index 000000000000..a67882535223 --- /dev/null +++ b/third_party/rust/libz-rs-sys/src/lib.rs @@ -0,0 +1,673 @@ +#![allow(non_camel_case_types)] +#![allow(non_snake_case)] +#![allow(clippy::missing_safety_doc)] // obviously needs to be fixed long-term +#![doc = include_str!("../README.md")] +#![cfg_attr(not(feature = "std"), no_std)] + +//! # Safety of `*mut z_stream` +//! +//! Most functions require an argument of type `*mut z_stream`. Unless +//! otherwise noted, the safety requirements on such arguments are at least that the +//! pointer must be either: +//! +//! - A `NULL` pointer +//! - A pointer to a correctly aligned, initialized value of type `z_stream`. +//! +//! In other words, it must be safe to cast the `*mut z_stream` to a `Option<&mut z_stream>`. It is +//! always safe to provide an argument of type `&mut z_stream`: rust will automatically downcast +//! the argument to `*mut z_stream`. + +#[cfg(test)] +mod tests; + +use core::mem::MaybeUninit; + +use core::ffi::{c_char, c_int, c_long, c_uchar, c_uint, c_ulong, c_void}; + +use zlib_rs::{ + deflate::{DeflateConfig, DeflateStream, Method, Strategy}, + inflate::{InflateConfig, InflateStream}, + DeflateFlush, InflateFlush, ReturnCode, +}; + +pub use zlib_rs::c_api::*; + +#[cfg(feature = "custom-prefix")] +macro_rules! prefix { + ($name:expr) => { + concat!(env!("LIBZ_RS_SYS_PREFIX"), stringify!($name)) + }; +} + +#[cfg(all(not(feature = "custom-prefix"), not(test)))] +macro_rules! prefix { + ($name:expr) => { + stringify!($name) + }; +} + +#[cfg(all(not(feature = "custom-prefix"), test))] +macro_rules! prefix { + ($name:expr) => { + concat!("LIBZ_RS_SYS_", stringify!($name)) + }; +} + +#[cfg(all(feature = "rust-allocator", feature = "c-allocator"))] +const _: () = + compile_error!("Only one of `rust-allocator` and `c-allocator` can be enabled at a time"); + +#[allow(unreachable_code)] +const DEFAULT_ZALLOC: Option = '_blk: { + // this `break 'blk'` construction exists to generate just one compile error and not other + // warnings when multiple allocators are configured. + + #[cfg(feature = "c-allocator")] + break '_blk Some(zlib_rs::allocate::zalloc_c); + + #[cfg(feature = "rust-allocator")] + break '_blk Some(zlib_rs::allocate::zalloc_rust); + + None +}; + +#[allow(unreachable_code)] +const DEFAULT_ZFREE: Option = '_blk: { + #[cfg(feature = "c-allocator")] + break '_blk Some(zlib_rs::allocate::zfree_c); + + #[cfg(feature = "rust-allocator")] + break '_blk Some(zlib_rs::allocate::zfree_rust); + + None +}; + +// In spirit this type is `libc::off_t`, but it would be our only libc dependency, and so we +// hardcode the type here. This should be correct on most operating systems. If we ever run into +// issues with it, we can either special-case or add a feature flag to force a particular width +pub type z_off_t = c_long; + +#[export_name = prefix!(crc32)] +pub unsafe extern "C" fn crc32(crc: c_ulong, buf: *const Bytef, len: uInt) -> c_ulong { + let buf = unsafe { core::slice::from_raw_parts(buf, len as usize) }; + zlib_rs::crc32(crc as u32, buf) as c_ulong +} + +#[export_name = prefix!(crc32_combine)] +pub unsafe extern "C" fn crc32_combine(crc1: c_ulong, crc2: c_ulong, len2: z_off_t) -> c_ulong { + zlib_rs::crc32_combine(crc1 as u32, crc2 as u32, len2 as u64) as c_ulong +} + +#[export_name = prefix!(adler32)] +pub unsafe extern "C" fn adler32(adler: c_ulong, buf: *const Bytef, len: uInt) -> c_ulong { + let buf = unsafe { core::slice::from_raw_parts(buf, len as usize) }; + zlib_rs::adler32(adler as u32, buf) as c_ulong +} + +#[export_name = prefix!(adler32_combine)] +pub unsafe extern "C" fn adler32_combine( + adler1: c_ulong, + adler2: c_ulong, + len2: z_off_t, +) -> c_ulong { + if let Ok(len2) = u64::try_from(len2) { + zlib_rs::adler32_combine(adler1 as u32, adler2 as u32, len2) as c_ulong + } else { + // for negative len, return invalid adler32 as a clue for debugging + 0xffffffff + } +} + +/// Inflates `source` into `dest`, and writes the final inflated size into `destLen`. +/// +/// # Safety +/// +/// Behavior is undefined if any of the following conditions are violated: +/// +/// - `source` must be [valid](https://doc.rust-lang.org/std/ptr/index.html#safety) for reads for +/// `sourceLen` bytes. The entity of `source` must be contained in one allocated object! +/// - `source` must point to `sourceLen` consecutive properly initialized values of type `u8`. +/// - `dest` must be [valid](https://doc.rust-lang.org/std/ptr/index.html#safety) for reads for +/// `*destLen` bytes. The entity of `source` must be contained in one allocated object! +/// - `dest` must point to `*destLen` consecutive properly initialized values of type `u8`. +/// - while this function runs, both read and write actions to the `source` and `dest` memory +/// ranges are forbidden +#[export_name = prefix!(uncompress)] +pub unsafe extern "C" fn uncompress( + dest: *mut u8, + destLen: *mut c_ulong, + source: *const u8, + sourceLen: c_ulong, +) -> c_int { + let data = dest; + let len = core::ptr::read(destLen) as usize; + let output = core::slice::from_raw_parts_mut(data as *mut MaybeUninit, len); + + let data = source; + let len = sourceLen as usize; + let input = core::slice::from_raw_parts(data, len); + + let (output, err) = zlib_rs::inflate::uncompress(output, input, InflateConfig::default()); + + core::ptr::write(destLen, output.len() as _); + + err as c_int +} + +#[export_name = prefix!(inflate)] +pub unsafe extern "C" fn inflate(strm: *mut z_stream, flush: i32) -> i32 { + if let Some(stream) = InflateStream::from_stream_mut(strm) { + let flush = InflateFlush::try_from(flush).unwrap_or_default(); + zlib_rs::inflate::inflate(stream, flush) as _ + } else { + ReturnCode::StreamError as _ + } +} + +#[export_name = prefix!(inflateEnd)] +pub unsafe extern "C" fn inflateEnd(strm: *mut z_stream) -> i32 { + match InflateStream::from_stream_mut(strm) { + Some(stream) => { + zlib_rs::inflate::end(stream); + ReturnCode::Ok as _ + } + None => ReturnCode::StreamError as _, + } +} + +#[export_name = prefix!(inflateBackInit_)] +pub unsafe extern "C" fn inflateBackInit_( + _strm: z_streamp, + _windowBits: c_int, + _window: *mut c_uchar, + _version: *const c_char, + _stream_size: c_int, +) -> c_int { + todo!("inflateBack is not implemented yet") +} + +#[export_name = prefix!(inflateBack)] +pub unsafe extern "C" fn inflateBack( + _strm: z_streamp, + _in: in_func, + _in_desc: *mut c_void, + _out: out_func, + _out_desc: *mut c_void, +) -> c_int { + todo!("inflateBack is not implemented yet") +} + +#[export_name = prefix!(inflateBackEnd)] +pub unsafe extern "C" fn inflateBackEnd(_strm: z_streamp) -> c_int { + todo!("inflateBack is not implemented yet") +} + +#[export_name = prefix!(inflateCopy)] +pub unsafe extern "C" fn inflateCopy(dest: *mut z_stream, source: *const z_stream) -> i32 { + if dest.is_null() { + return ReturnCode::StreamError as _; + } + + if let Some(source) = InflateStream::from_stream_ref(source) { + zlib_rs::inflate::copy(&mut *(dest as *mut MaybeUninit), source) as _ + } else { + ReturnCode::StreamError as _ + } +} + +#[export_name = prefix!(inflateMark)] +pub unsafe extern "C" fn inflateMark(strm: *const z_stream) -> c_long { + if let Some(stream) = InflateStream::from_stream_ref(strm) { + zlib_rs::inflate::mark(stream) + } else { + c_long::MIN + } +} + +#[export_name = prefix!(inflateSync)] +pub unsafe extern "C" fn inflateSync(strm: *mut z_stream) -> i32 { + if let Some(stream) = InflateStream::from_stream_mut(strm) { + zlib_rs::inflate::sync(stream) as _ + } else { + ReturnCode::StreamError as _ + } +} + +// undocumented +#[export_name = prefix!(inflateSyncPoint)] +pub unsafe extern "C" fn inflateSyncPoint(strm: *mut z_stream) -> i32 { + if let Some(stream) = InflateStream::from_stream_mut(strm) { + zlib_rs::inflate::sync_point(stream) as i32 + } else { + ReturnCode::StreamError as _ + } +} + +#[export_name = prefix!(inflateInit_)] +pub unsafe extern "C" fn inflateInit_( + strm: z_streamp, + version: *const c_char, + stream_size: c_int, +) -> c_int { + if !is_version_compatible(version, stream_size) { + ReturnCode::VersionError as _ + } else if strm.is_null() { + ReturnCode::StreamError as _ + } else { + zlib_rs::inflate::init(&mut *strm, InflateConfig::default()) as _ + } +} + +#[export_name = prefix!(inflateInit2_)] +pub unsafe extern "C" fn inflateInit2_( + strm: z_streamp, + windowBits: c_int, + version: *const c_char, + stream_size: c_int, +) -> c_int { + if !is_version_compatible(version, stream_size) { + ReturnCode::VersionError as _ + } else { + inflateInit2(strm, windowBits) + } +} + +#[export_name = prefix!(inflateInit2)] +pub unsafe extern "C" fn inflateInit2(strm: z_streamp, windowBits: c_int) -> c_int { + if strm.is_null() { + ReturnCode::StreamError as _ + } else { + let config = InflateConfig { + window_bits: windowBits, + }; + + let stream = &mut *strm; + + if stream.zalloc.is_none() { + stream.zalloc = DEFAULT_ZALLOC; + stream.opaque = core::ptr::null_mut(); + } + + if stream.zfree.is_none() { + stream.zfree = DEFAULT_ZFREE; + } + + zlib_rs::inflate::init(stream, config) as _ + } +} + +#[export_name = prefix!(inflatePrime)] +pub unsafe extern "C" fn inflatePrime(strm: *mut z_stream, bits: i32, value: i32) -> i32 { + if let Some(stream) = InflateStream::from_stream_mut(strm) { + zlib_rs::inflate::prime(stream, bits, value) as _ + } else { + ReturnCode::StreamError as _ + } +} + +#[export_name = prefix!(inflateReset)] +pub unsafe extern "C" fn inflateReset(strm: *mut z_stream) -> i32 { + if let Some(stream) = InflateStream::from_stream_mut(strm) { + zlib_rs::inflate::reset(stream) as _ + } else { + ReturnCode::StreamError as _ + } +} + +#[export_name = prefix!(inflateReset2)] +pub unsafe extern "C" fn inflateReset2(strm: *mut z_stream, windowBits: c_int) -> i32 { + if let Some(stream) = InflateStream::from_stream_mut(strm) { + let config = InflateConfig { + window_bits: windowBits, + }; + zlib_rs::inflate::reset_with_config(stream, config) as _ + } else { + ReturnCode::StreamError as _ + } +} + +#[export_name = prefix!(inflateSetDictionary)] +pub unsafe extern "C" fn inflateSetDictionary( + strm: *mut z_stream, + dictionary: *const u8, + dictLength: c_uint, +) -> c_int { + let Some(stream) = InflateStream::from_stream_mut(strm) else { + return ReturnCode::StreamError as _; + }; + + let dict = if dictLength == 0 || dictionary.is_null() { + &[] + } else { + unsafe { core::slice::from_raw_parts(dictionary, dictLength as usize) } + }; + + zlib_rs::inflate::set_dictionary(stream, dict) as _ +} + +// part of gzip +#[export_name = prefix!(inflateGetHeader)] +pub unsafe extern "C" fn inflateGetHeader(strm: z_streamp, head: gz_headerp) -> c_int { + if let Some(stream) = InflateStream::from_stream_mut(strm) { + let header = if head.is_null() { + None + } else { + Some(unsafe { &mut *(head) }) + }; + + zlib_rs::inflate::get_header(stream, header) as i32 + } else { + ReturnCode::StreamError as _ + } +} + +// undocumented but exposed function +#[export_name = prefix!(inflateUndermine)] +pub unsafe extern "C" fn inflateUndermine(strm: *mut z_stream, subvert: i32) -> c_int { + if let Some(stream) = InflateStream::from_stream_mut(strm) { + zlib_rs::inflate::undermine(stream, subvert) as i32 + } else { + ReturnCode::StreamError as _ + } +} + +// undocumented but exposed function +#[export_name = prefix!(inflateResetKeep)] +pub unsafe extern "C" fn inflateResetKeep(strm: *mut z_stream) -> i32 { + if let Some(stream) = InflateStream::from_stream_mut(strm) { + zlib_rs::inflate::reset_keep(stream) as _ + } else { + ReturnCode::StreamError as _ + } +} + +// undocumented but exposed function +#[export_name = prefix!(inflateCodesUsed)] +pub unsafe extern "C" fn inflateCodesUsed(_strm: *mut z_stream) -> c_ulong { + todo!() +} + +#[export_name = prefix!(deflate)] +pub unsafe extern "C" fn deflate(strm: *mut z_stream, flush: i32) -> i32 { + if let Some(stream) = DeflateStream::from_stream_mut(strm) { + match DeflateFlush::try_from(flush) { + Ok(flush) => zlib_rs::deflate::deflate(stream, flush) as _, + Err(()) => ReturnCode::StreamError as _, + } + } else { + ReturnCode::StreamError as _ + } +} + +#[export_name = prefix!(deflateSetHeader)] +pub unsafe extern "C" fn deflateSetHeader(strm: *mut z_stream, head: gz_headerp) -> i32 { + if let Some(stream) = DeflateStream::from_stream_mut(strm) { + zlib_rs::deflate::set_header( + stream, + if head.is_null() { + None + } else { + Some(&mut *head) + }, + ) as _ + } else { + ReturnCode::StreamError as _ + } +} + +#[export_name = prefix!(deflateBound)] +pub unsafe extern "C" fn deflateBound(strm: *mut z_stream, sourceLen: c_ulong) -> c_ulong { + zlib_rs::deflate::bound(DeflateStream::from_stream_mut(strm), sourceLen as usize) as c_ulong +} + +#[export_name = prefix!(compress)] +pub unsafe extern "C" fn compress( + dest: *mut Bytef, + destLen: *mut c_ulong, + source: *const Bytef, + sourceLen: c_ulong, +) -> c_int { + compress2( + dest, + destLen, + source, + sourceLen, + DeflateConfig::default().level, + ) +} + +#[export_name = prefix!(compress2)] +pub unsafe extern "C" fn compress2( + dest: *mut Bytef, + destLen: *mut c_ulong, + source: *const Bytef, + sourceLen: c_ulong, + level: c_int, +) -> c_int { + let data = dest; + let len = core::ptr::read(destLen) as usize; + let output = core::slice::from_raw_parts_mut(data as *mut MaybeUninit, len); + + let data = source; + let len = sourceLen as usize; + let input = core::slice::from_raw_parts(data, len); + + let config = DeflateConfig::new(level); + let (output, err) = zlib_rs::deflate::compress(output, input, config); + + core::ptr::write(destLen, output.len() as _); + + err as c_int +} + +#[export_name = prefix!(compressBound)] +pub extern "C" fn compressBound(sourceLen: c_ulong) -> c_ulong { + zlib_rs::deflate::compress_bound(sourceLen as usize) as c_ulong +} + +#[export_name = prefix!(deflateEnd)] +pub unsafe extern "C" fn deflateEnd(strm: *mut z_stream) -> i32 { + match DeflateStream::from_stream_mut(strm) { + Some(stream) => match zlib_rs::deflate::end(stream) { + Ok(_) => ReturnCode::Ok as _, + Err(_) => ReturnCode::DataError as _, + }, + None => ReturnCode::StreamError as _, + } +} + +#[export_name = prefix!(deflateReset)] +pub unsafe extern "C" fn deflateReset(strm: *mut z_stream) -> i32 { + match DeflateStream::from_stream_mut(strm) { + Some(stream) => zlib_rs::deflate::reset(stream) as _, + None => ReturnCode::StreamError as _, + } +} + +#[export_name = prefix!(deflateParams)] +pub unsafe extern "C" fn deflateParams(strm: z_streamp, level: c_int, strategy: c_int) -> c_int { + let Ok(strategy) = Strategy::try_from(strategy) else { + return ReturnCode::StreamError as _; + }; + + match DeflateStream::from_stream_mut(strm) { + Some(stream) => zlib_rs::deflate::params(stream, level, strategy) as _, + None => ReturnCode::StreamError as _, + } +} + +#[export_name = prefix!(deflateSetDictionary)] +pub unsafe extern "C" fn deflateSetDictionary( + strm: z_streamp, + dictionary: *const Bytef, + dictLength: uInt, +) -> c_int { + let dictionary = core::slice::from_raw_parts(dictionary, dictLength as usize); + + match DeflateStream::from_stream_mut(strm) { + Some(stream) => zlib_rs::deflate::set_dictionary(stream, dictionary) as _, + None => ReturnCode::StreamError as _, + } +} + +#[export_name = prefix!(deflatePrime)] +pub unsafe extern "C" fn deflatePrime(strm: z_streamp, bits: c_int, value: c_int) -> c_int { + match DeflateStream::from_stream_mut(strm) { + Some(stream) => zlib_rs::deflate::prime(stream, bits, value) as _, + None => ReturnCode::StreamError as _, + } +} + +#[export_name = prefix!(deflatePending)] +pub unsafe extern "C" fn deflatePending( + strm: z_streamp, + pending: *mut c_uint, + bits: *mut c_int, +) -> c_int { + match DeflateStream::from_stream_mut(strm) { + Some(stream) => { + let (current_pending, current_bits) = stream.pending(); + + if !pending.is_null() { + *pending = current_pending as c_uint; + } + + if !bits.is_null() { + *bits = current_bits as c_int; + } + + ReturnCode::Ok as _ + } + None => ReturnCode::StreamError as _, + } +} + +#[export_name = prefix!(deflateCopy)] +pub unsafe extern "C" fn deflateCopy(dest: z_streamp, source: z_streamp) -> c_int { + let dest = if dest.is_null() { + return ReturnCode::StreamError as _; + } else { + &mut *(dest as *mut MaybeUninit<_>) + }; + + match DeflateStream::from_stream_mut(source) { + Some(source) => zlib_rs::deflate::copy(dest, source) as _, + None => ReturnCode::StreamError as _, + } +} + +#[export_name = prefix!(deflateInit_)] +pub unsafe extern "C" fn deflateInit_( + strm: z_streamp, + level: c_int, + version: *const c_char, + stream_size: c_int, +) -> c_int { + if !is_version_compatible(version, stream_size) { + ReturnCode::VersionError as _ + } else if strm.is_null() { + ReturnCode::StreamError as _ + } else { + let stream = &mut *strm; + + if stream.zalloc.is_none() { + stream.zalloc = DEFAULT_ZALLOC; + stream.opaque = core::ptr::null_mut(); + } + + if stream.zfree.is_none() { + stream.zfree = DEFAULT_ZFREE; + } + + zlib_rs::deflate::init(stream, DeflateConfig::new(level)) as _ + } +} + +#[export_name = prefix!(deflateInit2_)] +pub unsafe extern "C" fn deflateInit2_( + strm: z_streamp, + level: c_int, + method: c_int, + windowBits: c_int, + memLevel: c_int, + strategy: c_int, + version: *const c_char, + stream_size: c_int, +) -> c_int { + if !is_version_compatible(version, stream_size) { + ReturnCode::VersionError as _ + } else if strm.is_null() { + ReturnCode::StreamError as _ + } else { + let Ok(method) = Method::try_from(method) else { + return ReturnCode::StreamError as _; + }; + + let Ok(strategy) = Strategy::try_from(strategy) else { + return ReturnCode::StreamError as _; + }; + + let config = DeflateConfig { + level, + method, + window_bits: windowBits, + mem_level: memLevel, + strategy, + }; + + let stream = &mut *strm; + + if stream.zalloc.is_none() { + stream.zalloc = DEFAULT_ZALLOC; + stream.opaque = core::ptr::null_mut(); + } + + if stream.zfree.is_none() { + stream.zfree = DEFAULT_ZFREE; + } + + zlib_rs::deflate::init(stream, config) as _ + } +} + +#[export_name = prefix!(deflateTune)] +pub unsafe extern "C" fn deflateTune( + strm: z_streamp, + good_length: c_int, + max_lazy: c_int, + nice_length: c_int, + max_chain: c_int, +) -> c_int { + match DeflateStream::from_stream_mut(strm) { + Some(stream) => zlib_rs::deflate::tune( + stream, + good_length as usize, + max_lazy as usize, + nice_length as usize, + max_chain as usize, + ) as _, + None => ReturnCode::StreamError as _, + } +} + +// the first part of this version specifies the zlib that we're compatible with (in terms of +// supported functions). In practice in most cases only the major version is checked, unless +// specific functions that were added later are used. +const LIBZ_RS_SYS_VERSION: &str = concat!("1.3.0-zlib-rs-", env!("CARGO_PKG_VERSION"), "\0"); + +unsafe fn is_version_compatible(version: *const c_char, stream_size: i32) -> bool { + if version.is_null() { + return false; + } + + let expected_major_version = core::ptr::read(version); + if expected_major_version as u8 != LIBZ_RS_SYS_VERSION.as_bytes()[0] { + return false; + } + + core::mem::size_of::() as i32 == stream_size +} + +pub const extern "C" fn zlibVersion() -> *const c_char { + LIBZ_RS_SYS_VERSION.as_ptr() as *const c_char +} diff --git a/third_party/rust/libz-rs-sys/src/tests/deflate.rs b/third_party/rust/libz-rs-sys/src/tests/deflate.rs new file mode 100644 index 000000000000..93485f26cc89 --- /dev/null +++ b/third_party/rust/libz-rs-sys/src/tests/deflate.rs @@ -0,0 +1,1616 @@ +use std::{ffi::CString, mem::MaybeUninit}; + +// we use the libz_sys but configure zlib-ng in zlib compat mode +use libz_sys as libz_ng_sys; + +use crate as libz_rs_sys; + +use core::ffi::{c_char, c_int, c_ulong}; + +use libz_rs_sys::{ + deflate, deflateEnd, deflateInit2_, inflate, inflateEnd, inflateInit2_, Z_DEFLATED, Z_FILTERED, + Z_NO_FLUSH, +}; +use zlib_rs::{ + c_api::Z_BEST_COMPRESSION, + deflate::{DeflateConfig, Method, Strategy}, + inflate::InflateConfig, + DeflateFlush, ReturnCode, +}; + +const VERSION: *const c_char = libz_rs_sys::zlibVersion(); +const STREAM_SIZE: c_int = core::mem::size_of::() as c_int; + +pub mod quick { + use super::*; + + #[rustfmt::skip] + const BI_VALID_INPUT: [u8; 554] = [ + 0x8d, 0xff, 0xff, 0xff, 0xa2, 0x00, 0x00, 0xff, 0x00, 0x15, 0x1b, 0x1b, 0xa2, 0xa2, 0xaf, 0xa2, + 0xa2, 0x00, 0x00, 0x00, 0x02, 0x00, 0x1b, 0x3f, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x0b, + 0x00, 0xab, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x2b, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x01, 0x1e, 0x00, 0x00, 0x01, 0x40, 0x00, 0x00, 0x00, 0x07, 0x01, 0x18, 0x00, 0x22, 0x00, + 0x00, 0x00, 0xfd, 0x39, 0xff, 0x00, 0x00, 0x00, 0x1b, 0xfd, 0x3b, 0x00, 0x68, 0x00, 0x00, 0x01, + 0xff, 0xff, 0xff, 0x57, 0xf8, 0x1e, 0x00, 0x00, 0xf2, 0xf2, 0xf2, 0xf2, 0xfa, 0xff, 0xff, 0xff, + 0xff, 0x7e, 0x00, 0x00, 0x4a, 0x00, 0xc5, 0x00, 0x41, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, + 0x00, 0x02, 0x01, 0x01, 0x00, 0xa2, 0x08, 0x00, 0x00, 0x00, 0x00, 0x27, 0x4a, 0x4a, 0x4a, 0x32, + 0x00, 0xf9, 0xff, 0x00, 0x02, 0x9a, 0xff, 0x00, 0x00, 0x3f, 0x50, 0x00, 0x03, 0x00, 0x00, 0x00, + 0x3d, 0x00, 0x08, 0x2f, 0x20, 0x00, 0x23, 0x00, 0x00, 0x00, 0x00, 0x23, 0x00, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0x7a, 0x7a, 0x9e, 0xff, 0xff, 0x00, 0x1b, 0x1b, 0x04, 0x00, 0x1b, 0x1b, + 0x1b, 0x1b, 0x00, 0x00, 0x00, 0xaf, 0xad, 0xaf, 0x00, 0x00, 0xa8, 0x00, 0x00, 0x00, 0x2e, 0xff, + 0xff, 0x2e, 0xc1, 0x00, 0x10, 0x00, 0x00, 0x00, 0x06, 0x70, 0x00, 0x00, 0x00, 0xda, 0x67, 0x01, + 0x47, 0x00, 0x00, 0x00, 0x0c, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x01, 0x00, 0x3f, + 0x54, 0x00, 0x00, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x5c, 0x00, 0x00, 0x34, 0x3e, 0xc5, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x7a, 0x00, 0x00, 0x00, 0x0a, 0x01, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x7a, 0x7a, 0x7a, 0x7a, 0x7a, 0x00, 0x00, 0x00, 0x40, 0x1b, 0x1b, 0x88, 0x1b, 0x1b, + 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1f, 0x1b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, + 0x00, 0x04, 0x00, 0x00, 0x50, 0x3e, 0x7a, 0x7a, 0x00, 0x00, 0x40, 0x00, 0x40, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x08, 0x87, 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x00, 0xff, 0x3d, 0x00, 0x11, 0x4d, 0x00, 0x00, 0x01, 0xd4, 0xd4, 0xd4, 0xd4, 0x2d, 0xd4, + 0xd4, 0xff, 0xff, 0xff, 0xfa, 0x01, 0xd4, 0x00, 0xd4, 0x00, 0x00, 0xd4, 0xd4, 0xd4, 0xd4, 0xd4, + 0xd4, 0x1e, 0x1e, 0x1e, 0x1e, 0x00, 0x00, 0xfe, 0xf9, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x00, + 0x16, 0xd4, 0xd4, 0xd4, 0xd4, 0xd4, 0xd4, 0xd4, 0xd4, 0xd4, 0x00, 0x00, 0x80, 0x20, 0x00, 0x00, + 0xff, 0x2b, 0x2b, 0x2b, 0x2b, 0x35, 0xd4, 0xd4, 0x47, 0x3f, 0xd4, 0xd4, 0xd6, 0xd4, 0xd4, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x32, 0x4a, 0x4a, 0x4a, 0x4a, 0x71, 0x00, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, + 0x1f, 0x1b, 0x1b, 0x1b, 0x57, 0x57, 0x57, 0x57, 0x00, 0x00, 0x1b, 0x08, 0x2b, 0x16, 0xc3, 0x00, + 0x00, 0x00, 0x29, 0x30, 0x03, 0xff, 0x03, 0x03, 0x03, 0x03, 0x07, 0x00, 0x00, 0x01, 0x0b, 0xff, + 0xff, 0xf5, 0xf5, 0xf5, 0x00, 0x00, 0xfe, 0xfa, 0x0f, 0x0f, 0x08, 0x00, 0xff, 0x00, 0x53, 0x3f, + 0x00, 0x04, 0x5d, 0xa8, 0x2e, 0xff, 0xff, 0x00, 0x2f, 0x2f, 0x05, 0xff, 0xff, 0xff, 0x2f, 0x2f, + 0x2f, 0x0a, 0x0a, 0x0a, 0x0a, 0x30, 0xff, 0xff, 0xff, 0xf0, 0x0a, 0x0a, 0x0a, 0x00, 0xff, 0x3f, + 0x4f, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x71, 0x00, 0x2e, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x71, 0x71, 0x00, 0x71, 0x71, 0x71, 0xf5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0xff, + 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0xdb, 0x3f, 0x00, 0xfa, 0x71, 0x71, 0x71, 0x00, 0x00, + 0x00, 0x01, 0x00, 0x00, 0x00, 0x71, 0x71, 0x71, 0x71, 0x71 + ]; + + #[test] + fn bi_valid() { + let mut stream = libz_rs_sys::z_stream { + next_in: std::ptr::null_mut(), + avail_in: 0, + total_in: 0, + next_out: std::ptr::null_mut(), + avail_out: 0, + total_out: 0, + msg: std::ptr::null_mut(), + state: std::ptr::null_mut(), + zalloc: None, + zfree: None, + opaque: std::ptr::null_mut(), + data_type: 0, + adler: 0, + reserved: 0, + }; + + let err = unsafe { + deflateInit2_( + &mut stream, + 1, + Z_DEFLATED, + 31, + 1, + Z_FILTERED, + VERSION, + STREAM_SIZE, + ) + }; + + assert_eq!(ReturnCode::from(err), ReturnCode::Ok); + + stream.next_in = &BI_VALID_INPUT as *const u8 as *mut u8; + let mut next_out = [0u8; 1236]; + stream.next_out = next_out.as_mut_ptr(); + + stream.avail_in = 554; + stream.avail_out = 31; + + let err = unsafe { deflate(&mut stream, DeflateFlush::Finish as i32) }; + assert_eq!(ReturnCode::from(err), ReturnCode::Ok); + + stream.avail_in = 0; + stream.avail_out = 498; + let err = unsafe { deflate(&mut stream, DeflateFlush::Finish as i32) }; + assert_eq!(ReturnCode::from(err), ReturnCode::StreamEnd); + + let err = unsafe { deflateEnd(&mut stream) }; + assert_eq!(ReturnCode::from(err), ReturnCode::Ok); + } + + #[rustfmt::skip] + const BLOCK_OPEN_INPUT: [u8; 495] = [ + 0x1d, 0x1d, 0x00, 0x00, 0x00, 0x4a, 0x4a, 0x4a, 0xaf, 0xaf, 0xaf, 0xaf, 0x4a, 0x4a, 0x4a, 0x4a, + 0x3f, 0x3e, 0xaf, 0xff, 0xff, 0xff, 0x11, 0xff, 0xff, 0xff, 0xff, 0xdf, 0x00, 0x00, 0x00, 0x01, + 0x3f, 0x7d, 0x00, 0x50, 0x00, 0x00, 0xc8, 0x01, 0x2b, 0x60, 0xc8, 0x00, 0x24, 0x06, 0xff, 0xff, + 0x4a, 0x4e, 0x4a, 0x7d, 0xc8, 0x01, 0xf1, 0x2b, 0x28, 0xb2, 0xb2, 0x60, 0x25, 0xc8, 0x06, 0x00, + 0x00, 0x00, 0x31, 0x00, 0x01, 0xb2, 0xb2, 0xb2, 0xff, 0xff, 0xfd, 0xb2, 0xb2, 0x40, 0xff, 0x7d, + 0x3b, 0x34, 0x3e, 0xff, 0xff, 0x4a, 0x4a, 0x01, 0xf1, 0xff, 0x02, 0xff, 0x3f, 0xff, 0x02, 0xff, + 0xff, 0xff, 0xbf, 0x0a, 0xff, 0x00, 0x01, 0x3f, 0xb3, 0xff, 0x26, 0x00, 0x00, 0x13, 0x00, 0xc8, + 0x3e, 0x3e, 0x3e, 0x4a, 0x76, 0x4a, 0x4a, 0x2e, 0x7d, 0x3e, 0x3e, 0x3e, 0x3e, 0x1d, 0x1d, 0x1d, + 0xfe, 0xea, 0xef, 0x80, 0x01, 0x00, 0x00, 0x40, 0x00, 0x00, 0xba, 0x00, 0x06, 0xfa, 0xb9, 0x11, + 0xbf, 0x98, 0xee, 0x45, 0x7e, 0x04, 0x00, 0xff, 0xff, 0xff, 0x67, 0xc3, 0xc3, 0xc3, 0xc3, 0x00, + 0x1d, 0x1d, 0xe1, 0xe3, 0x00, 0xc3, 0x1d, 0x98, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0xe8, 0x00, 0x00, 0x1d, 0x1d, 0x1d, 0xfa, 0x1e, 0x12, 0xff, 0xff, 0xff, + 0x00, 0x01, 0xa7, 0xff, 0xff, 0xff, 0x1d, 0x1d, 0x1d, 0x63, 0xff, 0xff, 0xff, 0x1f, 0x00, 0x00, + 0x10, 0x40, 0x00, 0x00, 0xad, 0xff, 0xff, 0x3f, 0x51, 0x00, 0xf8, 0xff, 0xff, 0x8a, 0x01, 0x05, + 0x00, 0x00, 0x03, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x05, 0x40, 0x1f, 0x08, 0x0a, 0x00, 0xff, + 0xff, 0x01, 0x00, 0x12, 0x00, 0x00, 0x01, 0x00, 0x3f, 0x40, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, + 0x21, 0x00, 0x1d, 0x00, 0x00, 0x00, 0xe4, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0xe6, 0xe6, 0x34, + 0xe6, 0xe6, 0xe6, 0xe6, 0xff, 0x2b, 0xee, 0x1d, 0x1d, 0x1d, 0x93, 0x1d, 0x1d, 0x1d, 0xee, 0x2b, + 0xee, 0x01, 0x81, 0x1d, 0x00, 0x00, 0x58, 0x00, 0x00, 0x01, 0x14, 0x00, 0x1b, 0x00, 0x00, 0x2c, + 0x00, 0x00, 0x00, 0xdb, 0x00, 0x45, 0x7e, 0x00, 0x00, 0x00, 0xfb, 0xbd, 0x00, 0x06, 0x21, 0xd3, + 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x49, 0x49, 0xc9, 0x49, 0x3d, 0x00, 0x34, 0x01, 0x00, + 0x00, 0x6a, 0x2b, 0x00, 0x00, 0x50, 0x40, 0xf0, 0xf0, 0xf0, 0xf0, 0xa3, 0xa3, 0xa3, 0xa3, 0xf0, + 0xf0, 0x06, 0xfa, 0xa9, 0x01, 0x10, 0xbf, 0x98, 0x9d, 0x2b, 0xee, 0x2d, 0x21, 0x01, 0xdb, 0x00, + 0x45, 0x10, 0x00, 0x00, 0x7e, 0x00, 0x00, 0xe7, 0x00, 0xff, 0xff, 0x00, 0xf6, 0x00, 0x00, 0x00, + 0xf9, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0xe2, 0x00, 0x00, 0x00, 0x2d, 0x00, 0x00, 0x00, + 0x2f, 0x00, 0x3f, 0x54, 0x1d, 0x1d, 0x1d, 0x4c, 0x4c, 0x4c, 0x4c, 0x2a, 0x4c, 0x4c, 0x10, 0xff, + 0xff, 0x1a, 0x00, 0x00, 0x01, 0xff, 0x00, 0xff, 0xf9, 0x00, 0x3f, 0x53, 0xcc, 0xcc, 0xcc, 0xcc, + 0x6e, 0x00, 0x00, 0x01, 0xf8, 0xff, 0xff, 0xff, 0x49, 0x04, 0x2c, 0x01, 0x00, 0x1d, 0x00, 0x07, + 0x01, 0xff, 0x00, 0x00, 0x00, 0xf8, 0xff, 0x09, 0x00, 0x27, 0x00, 0x08, 0x21, 0x1c, 0x00, 0x00, + 0x00, 0x00, 0x1d, 0x05, 0x00, 0x00, 0x00, 0x2c, 0x53, 0x3f, 0x00, 0x01, 0x00, 0x00, 0xe6, 0xff, + 0xff, 0xff, 0x6a, 0x2b, 0xee, 0xe6, 0x6a, 0x2b, 0xee, 0x2b, 0xee, 0xee, 0x2b, 0xee, 0x00 + ]; + + #[test] + fn block_open_quick() { + let mut stream = libz_rs_sys::z_stream { + next_in: std::ptr::null_mut(), + avail_in: 0, + total_in: 0, + next_out: std::ptr::null_mut(), + avail_out: 0, + total_out: 0, + msg: std::ptr::null_mut(), + state: std::ptr::null_mut(), + zalloc: None, + zfree: None, + opaque: std::ptr::null_mut(), + data_type: 0, + adler: 0, + reserved: 0, + }; + + const MAX_WBITS: i32 = 15; // 32kb LZ77 window + + let err = unsafe { + deflateInit2_( + &mut stream, + 1, + Z_DEFLATED, + -MAX_WBITS, + 1, + Z_FILTERED, + VERSION, + STREAM_SIZE, + ) + }; + + assert_eq!(ReturnCode::from(err), ReturnCode::Ok); + + stream.next_in = &BLOCK_OPEN_INPUT as *const u8 as *mut u8; + let mut next_out = [0u8; 1116]; + stream.next_out = next_out.as_mut_ptr(); + + stream.avail_in = BLOCK_OPEN_INPUT.len() as _; + loop { + let written = stream.next_out as usize - next_out.as_mut_ptr() as usize; + stream.avail_out = (next_out.len() - written) as _; + + if stream.avail_out > 38 { + stream.avail_out = 38; + } + + let err = unsafe { deflate(&mut stream, DeflateFlush::Finish as i32) }; + if ReturnCode::from(err) == ReturnCode::StreamEnd { + break; + } + + assert_eq!(ReturnCode::from(err), ReturnCode::Ok); + } + + let compressed_size = stream.next_out as usize - next_out.as_mut_ptr() as usize; + + let err = unsafe { deflateEnd(&mut stream) }; + assert_eq!(ReturnCode::from(err), ReturnCode::Ok); + + let mut stream = libz_rs_sys::z_stream { + next_in: std::ptr::null_mut(), + avail_in: 0, + total_in: 0, + next_out: std::ptr::null_mut(), + avail_out: 0, + total_out: 0, + msg: std::ptr::null_mut(), + state: std::ptr::null_mut(), + zalloc: None, + zfree: None, + opaque: std::ptr::null_mut(), + data_type: 0, + adler: 0, + reserved: 0, + }; + + let err = unsafe { inflateInit2_(&mut stream, -MAX_WBITS, VERSION, STREAM_SIZE) }; + assert_eq!(ReturnCode::from(err), ReturnCode::Ok); + + stream.next_in = next_out.as_mut_ptr(); + stream.avail_in = compressed_size as _; + + let mut uncompressed = [0u8; BLOCK_OPEN_INPUT.len()]; + stream.next_out = uncompressed.as_mut_ptr(); + stream.avail_out = uncompressed.len() as _; + + let err = unsafe { inflate(&mut stream, Z_NO_FLUSH) }; + assert_eq!(ReturnCode::from(err), ReturnCode::StreamEnd); + + let err = unsafe { inflateEnd(&mut stream) }; + assert_eq!(ReturnCode::from(err), ReturnCode::Ok); + + assert_eq!(uncompressed, BLOCK_OPEN_INPUT); + } + + #[test] + fn block_open_fast() { + let mut stream = libz_rs_sys::z_stream { + next_in: std::ptr::null_mut(), + avail_in: 0, + total_in: 0, + next_out: std::ptr::null_mut(), + avail_out: 0, + total_out: 0, + msg: std::ptr::null_mut(), + state: std::ptr::null_mut(), + zalloc: None, + zfree: None, + opaque: std::ptr::null_mut(), + data_type: 0, + adler: 0, + reserved: 0, + }; + + const MAX_WBITS: i32 = 15; // 32kb LZ77 window + + let err = unsafe { + deflateInit2_( + &mut stream, + 2, // fast + Z_DEFLATED, + -MAX_WBITS, + 1, + Z_FILTERED, + VERSION, + STREAM_SIZE, + ) + }; + + assert_eq!(ReturnCode::from(err), ReturnCode::Ok); + + stream.next_in = &BLOCK_OPEN_INPUT as *const u8 as *mut u8; + let mut next_out = [0u8; 1116]; + stream.next_out = next_out.as_mut_ptr(); + + stream.avail_in = BLOCK_OPEN_INPUT.len() as _; + loop { + let written = stream.next_out as usize - next_out.as_mut_ptr() as usize; + stream.avail_out = (next_out.len() - written) as _; + + if stream.avail_out > 38 { + stream.avail_out = 38; + } + + let err = unsafe { deflate(&mut stream, DeflateFlush::Finish as i32) }; + if ReturnCode::from(err) == ReturnCode::StreamEnd { + break; + } + + assert_eq!(ReturnCode::from(err), ReturnCode::Ok); + } + + let compressed_size = stream.next_out as usize - next_out.as_mut_ptr() as usize; + + let err = unsafe { deflateEnd(&mut stream) }; + assert_eq!(ReturnCode::from(err), ReturnCode::Ok); + + let mut stream = libz_rs_sys::z_stream { + next_in: std::ptr::null_mut(), + avail_in: 0, + total_in: 0, + next_out: std::ptr::null_mut(), + avail_out: 0, + total_out: 0, + msg: std::ptr::null_mut(), + state: std::ptr::null_mut(), + zalloc: None, + zfree: None, + opaque: std::ptr::null_mut(), + data_type: 0, + adler: 0, + reserved: 0, + }; + + let err = unsafe { inflateInit2_(&mut stream, -MAX_WBITS, VERSION, STREAM_SIZE) }; + assert_eq!(ReturnCode::from(err), ReturnCode::Ok); + + stream.next_in = next_out.as_mut_ptr(); + stream.avail_in = compressed_size as _; + + let mut uncompressed = [0u8; BLOCK_OPEN_INPUT.len()]; + stream.next_out = uncompressed.as_mut_ptr(); + stream.avail_out = uncompressed.len() as _; + + let err = unsafe { inflate(&mut stream, Z_NO_FLUSH) }; + assert_eq!(ReturnCode::from(err), ReturnCode::StreamEnd); + + let err = unsafe { inflateEnd(&mut stream) }; + assert_eq!(ReturnCode::from(err), ReturnCode::Ok); + + assert_eq!(uncompressed, BLOCK_OPEN_INPUT); + } + + #[test] + fn block_open_slow() { + let mut stream = libz_rs_sys::z_stream { + next_in: std::ptr::null_mut(), + avail_in: 0, + total_in: 0, + next_out: std::ptr::null_mut(), + avail_out: 0, + total_out: 0, + msg: std::ptr::null_mut(), + state: std::ptr::null_mut(), + zalloc: None, + zfree: None, + opaque: std::ptr::null_mut(), + data_type: 0, + adler: 0, + reserved: 0, + }; + + const MAX_WBITS: i32 = 15; // 32kb LZ77 window + + let err = unsafe { + deflateInit2_( + &mut stream, + 9, // fast + Z_DEFLATED, + -MAX_WBITS, + 1, + Z_FILTERED, + VERSION, + STREAM_SIZE, + ) + }; + + assert_eq!(ReturnCode::from(err), ReturnCode::Ok); + + stream.next_in = &BLOCK_OPEN_INPUT as *const u8 as *mut u8; + let mut next_out = [0u8; 1116]; + stream.next_out = next_out.as_mut_ptr(); + + stream.avail_in = BLOCK_OPEN_INPUT.len() as _; + loop { + let written = stream.next_out as usize - next_out.as_mut_ptr() as usize; + stream.avail_out = (next_out.len() - written) as _; + + if stream.avail_out > 38 { + stream.avail_out = 38; + } + + let err = unsafe { deflate(&mut stream, DeflateFlush::Finish as i32) }; + if ReturnCode::from(err) == ReturnCode::StreamEnd { + break; + } + + assert_eq!(ReturnCode::from(err), ReturnCode::Ok); + } + + let compressed_size = stream.next_out as usize - next_out.as_mut_ptr() as usize; + + let err = unsafe { deflateEnd(&mut stream) }; + assert_eq!(ReturnCode::from(err), ReturnCode::Ok); + + let mut stream = libz_rs_sys::z_stream { + next_in: std::ptr::null_mut(), + avail_in: 0, + total_in: 0, + next_out: std::ptr::null_mut(), + avail_out: 0, + total_out: 0, + msg: std::ptr::null_mut(), + state: std::ptr::null_mut(), + zalloc: None, + zfree: None, + opaque: std::ptr::null_mut(), + data_type: 0, + adler: 0, + reserved: 0, + }; + + let err = unsafe { inflateInit2_(&mut stream, -MAX_WBITS, VERSION, STREAM_SIZE) }; + assert_eq!(ReturnCode::from(err), ReturnCode::Ok); + + stream.next_in = next_out.as_mut_ptr(); + stream.avail_in = compressed_size as _; + + let mut uncompressed = [0u8; BLOCK_OPEN_INPUT.len()]; + stream.next_out = uncompressed.as_mut_ptr(); + stream.avail_out = uncompressed.len() as _; + + let err = unsafe { inflate(&mut stream, Z_NO_FLUSH) }; + assert_eq!(ReturnCode::from(err), ReturnCode::StreamEnd); + + let err = unsafe { inflateEnd(&mut stream) }; + assert_eq!(ReturnCode::from(err), ReturnCode::Ok); + + assert_eq!(uncompressed, BLOCK_OPEN_INPUT); + } +} + +#[test] +fn test_deflate_tune() { + let mut compr = [0; 128]; + + let good_length = 3; + let max_lazy = 5; + let nice_length = 18; + let max_chain = 6; + + let mut c_stream = MaybeUninit::zeroed(); + + let err = unsafe { + libz_rs_sys::deflateTune( + c_stream.as_mut_ptr(), + good_length, + max_lazy, + nice_length, + max_chain, + ) + }; + assert_eq!(err, libz_rs_sys::Z_STREAM_ERROR); + + let err = unsafe { + libz_rs_sys::deflateInit_( + c_stream.as_mut_ptr(), + libz_rs_sys::Z_BEST_COMPRESSION, + VERSION, + core::mem::size_of::() as _, + ) + }; + assert_eq!(err, libz_rs_sys::Z_OK); + + let c_stream = unsafe { c_stream.assume_init_mut() }; + + let err = unsafe { + libz_rs_sys::deflateTune(c_stream, good_length, max_lazy, nice_length, max_chain) + }; + assert_eq!(err, libz_rs_sys::Z_OK); + + let input = "Hello, World!\n"; + + c_stream.next_in = input.as_ptr() as *mut u8; + c_stream.next_out = compr.as_mut_ptr(); + + while c_stream.total_in as usize != input.len() && (c_stream.total_out as usize) < compr.len() { + c_stream.avail_in = 1; + c_stream.avail_out = 1; /* force small buffers */ + + let err = unsafe { libz_rs_sys::deflate(c_stream, Z_NO_FLUSH) }; + assert_eq!(err, libz_rs_sys::Z_OK); + } + + /* Finish the stream, still forcing small buffers: */ + loop { + c_stream.avail_out = 1; + let err = unsafe { libz_rs_sys::deflate(c_stream, libz_ng_sys::Z_FINISH) }; + if err == libz_ng_sys::Z_STREAM_END { + break; + }; + assert_eq!(err, libz_rs_sys::Z_OK); + } + + let err = unsafe { libz_rs_sys::deflateEnd(c_stream) }; + assert_eq!(err, libz_rs_sys::Z_OK); +} + +#[test] +fn deflate_medium_fizzle_bug() { + const EXPECTED: &[u8] = &[ + 120, 156, 99, 96, 128, 3, 73, 6, 26, 3, 71, 218, 2, 28, 182, 214, 17, 225, 50, 85, 100, 30, + 0, 132, 7, 24, 220, + ]; + + const INPUT: &str = "\0\0\0\0\0\0\0\0\0\0\0\u{19}\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\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\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\0AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\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\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\0\0\0\0\0\0"; + + let mut output = [0; EXPECTED.len()]; + + let config = DeflateConfig::new(6); + let (output, err) = zlib_rs::deflate::compress_slice(&mut output, INPUT.as_bytes(), config); + assert_eq!(err, ReturnCode::Ok); + + assert_eq!(output, EXPECTED); +} + +fn deflate_bound_correct_help( + (config, source_len): (DeflateConfig, c_ulong), +) -> (c_ulong, c_ulong) { + let rs_bound = unsafe { + let mut strm = MaybeUninit::zeroed(); + + // first validate the config + let err = libz_rs_sys::deflateInit2_( + strm.as_mut_ptr(), + config.level, + config.method as i32, + config.window_bits, + config.mem_level, + config.strategy as i32, + VERSION, + STREAM_SIZE, + ); + + assert_eq!(ReturnCode::from(err), ReturnCode::Ok); + + libz_rs_sys::deflateBound(strm.as_mut_ptr(), source_len) + }; + + let ng_bound = unsafe { + let mut strm = MaybeUninit::zeroed(); + + // first validate the config + let err = libz_ng_sys::deflateInit2_( + strm.as_mut_ptr(), + config.level, + config.method as i32, + config.window_bits, + config.mem_level, + config.strategy as i32, + libz_ng_sys::zlibVersion(), + core::mem::size_of::() as _, + ); + + assert_eq!(ReturnCode::from(err), ReturnCode::Ok); + + libz_ng_sys::deflateBound(strm.as_mut_ptr(), source_len) + }; + + (rs_bound, ng_bound) +} + +#[test] +fn deflate_bound_correct() { + ::quickcheck::quickcheck(test as fn(_) -> _); + + fn test(input: (DeflateConfig, c_ulong)) -> bool { + let (rs, ng) = deflate_bound_correct_help(input); + + rs == ng + } +} + +#[test] +fn deflate_bound_correct_windows() { + // on windows, c_ulong is just 32 bits wide. That leads to rounding that is different to what + // we'd get when using usize in rust + + let config = DeflateConfig { + level: 9, + method: Method::Deflated, + window_bits: -13, + mem_level: 5, + strategy: Strategy::Filtered, + }; + + // this value is dangerously close to u32::MAX, and the calculation will run into overflow + // u32::MAX = 4294967296 + let source_len = 4294967233; + + let (rs, ng) = deflate_bound_correct_help((config, source_len)); + + assert_eq!(rs, ng); + + let config = DeflateConfig { + level: 0, + method: Method::Deflated, + window_bits: 15, + mem_level: 5, + strategy: Strategy::HuffmanOnly, + }; + // this value is dangerously close to u32::MAX, and the calculation will run into overflow + // u32::MAX = 4294967296 + let source_len = 4294967289; + + let (rs, ng) = deflate_bound_correct_help((config, source_len)); + + assert_eq!(rs, ng); +} + +fn deflate_bound_gzip_header_help( + (config, source_len, extra, name, comment): (DeflateConfig, c_ulong, CString, CString, CString), +) -> bool { + let rs_bound = unsafe { + let mut strm = MaybeUninit::zeroed(); + + // first validate the config + let err = libz_rs_sys::deflateInit2_( + strm.as_mut_ptr(), + config.level, + config.method as i32, + config.window_bits, + config.mem_level, + config.strategy as i32, + VERSION, + STREAM_SIZE, + ); + + if err != 0 { + return true; + } + + let mut header = libz_rs_sys::gz_header { + text: 0, + time: 0, + xflags: 0, + os: 0, + extra: extra.as_ptr() as *mut _, + extra_len: extra.as_bytes().len() as _, + extra_max: 0, + name: name.as_ptr() as *mut _, + name_max: 0, + comment: comment.as_ptr() as *mut _, + comm_max: 0, + hcrc: 1, + done: 0, + }; + + // this may fail if the config is not set up for gzip + let _err = libz_rs_sys::deflateSetHeader(strm.as_mut_ptr(), &mut header); + + libz_rs_sys::deflateBound(strm.as_mut_ptr(), source_len) + }; + + let ng_bound = unsafe { + let mut strm = MaybeUninit::zeroed(); + + // first validate the config + let err = libz_ng_sys::deflateInit2_( + strm.as_mut_ptr(), + config.level, + config.method as i32, + config.window_bits, + config.mem_level, + config.strategy as i32, + libz_ng_sys::zlibVersion(), + core::mem::size_of::() as _, + ); + + assert_eq!(err, 0); + + let mut header = libz_ng_sys::gz_header { + text: 0, + time: 0, + xflags: 0, + os: 0, + extra: extra.as_ptr() as *mut _, + extra_len: extra.as_bytes().len() as _, + extra_max: 0, + name: name.as_ptr() as *mut _, + name_max: 0, + comment: comment.as_ptr() as *mut _, + comm_max: 0, + hcrc: 1, + done: 0, + }; + + // this may fail if the config is not set up for gzip + let _err = libz_ng_sys::deflateSetHeader(strm.as_mut_ptr(), &mut header); + + libz_ng_sys::deflateBound(strm.as_mut_ptr(), source_len) + }; + + assert_eq!(rs_bound, ng_bound); + + rs_bound == ng_bound +} + +#[test] +fn deflate_bound_gzip_header() { + ::quickcheck::quickcheck(deflate_bound_gzip_header_help as fn(_) -> _); +} + +#[test] +fn test_compress_bound_windows() { + let source_len = 4294967289 as core::ffi::c_ulong; + + let rs_bound = libz_rs_sys::compressBound(source_len as _); + let ng_bound = unsafe { libz_ng_sys::compressBound(source_len as _) }; + + assert_eq!(rs_bound, ng_bound as _); +} + +#[test] +fn test_compress_bound() { + ::quickcheck::quickcheck(test as fn(_) -> _); + + fn test(source_len: core::ffi::c_ulong) -> bool { + let rs_bound = libz_rs_sys::compressBound(source_len as _); + let ng_bound = unsafe { libz_ng_sys::compressBound(source_len as _) }; + + assert_eq!(rs_bound, ng_bound as _); + + rs_bound == ng_bound as _ + } +} + +#[test] +fn test_compress_param() { + let mut output_rs = [0; 1024]; + let mut output_ng = [0; 1024]; + + let config = DeflateConfig::new(2); + + let input = + "Scheduling and executing async tasks is a job handled by an async runtime, such as\0"; + + let n_rs = unsafe { + let mut strm = MaybeUninit::zeroed(); + + // first validate the config + let err = libz_rs_sys::deflateInit2_( + strm.as_mut_ptr(), + config.level, + config.method as i32, + config.window_bits, + config.mem_level, + config.strategy as i32, + VERSION, + STREAM_SIZE, + ); + assert_eq!(err, 0); + + let stream = strm.assume_init_mut(); + + stream.next_out = output_rs.as_mut_ptr(); + stream.avail_out = output_rs.len() as _; + + let offset = input.len() / 2; + + stream.next_in = input.as_ptr() as *mut u8; + stream.avail_in = offset as _; + + let err = libz_rs_sys::deflate(stream, DeflateFlush::NoFlush as i32); + assert_eq!(err, 0); + + let err = libz_rs_sys::deflateParams(stream, 8, Strategy::Rle as i32); + assert_eq!(err, 0); + + assert_eq!(stream.next_in as usize - input.as_ptr() as usize, offset); + + stream.avail_in = (input.len() - offset) as _; + + let err = libz_rs_sys::deflate(stream, DeflateFlush::Finish as i32); + assert_eq!(err, ReturnCode::StreamEnd as i32); + + let err = libz_rs_sys::deflateEnd(stream); + assert_eq!(err, 0); + + stream.total_out as usize + }; + + let n_ng = unsafe { + let mut strm = MaybeUninit::zeroed(); + + let err = libz_ng_sys::deflateParams(strm.as_mut_ptr(), 8, Strategy::Rle as i32); + assert_eq!(err, ReturnCode::StreamError as i32); + + // first validate the config + let err = libz_ng_sys::deflateInit2_( + strm.as_mut_ptr(), + config.level, + config.method as i32, + config.window_bits, + config.mem_level, + config.strategy as i32, + libz_ng_sys::zlibVersion(), + core::mem::size_of::() as _, + ); + assert_eq!(err, 0); + + let err = libz_ng_sys::deflateParams(strm.as_mut_ptr(), -1, 100); + assert_eq!(err, ReturnCode::StreamError as i32); + + let err = libz_ng_sys::deflateParams(strm.as_mut_ptr(), 100, Strategy::Rle as i32); + assert_eq!(err, ReturnCode::StreamError as i32); + + let stream = strm.assume_init_mut(); + + stream.next_out = output_ng.as_mut_ptr(); + stream.avail_out = output_ng.len() as _; + + let offset = input.len() / 2; + + stream.next_in = input.as_ptr() as *mut u8; + stream.avail_in = offset as _; + + let err = libz_ng_sys::deflate(stream, DeflateFlush::NoFlush as i32); + assert_eq!(err, 0); + + let err = libz_ng_sys::deflateParams(stream, 8, Strategy::Rle as i32); + assert_eq!(err, 0); + + assert_eq!(stream.next_in as usize - input.as_ptr() as usize, offset); + + stream.avail_in = (input.len() - offset) as _; + + let err = libz_ng_sys::deflate(stream, DeflateFlush::Finish as i32); + assert_eq!(err, ReturnCode::StreamEnd as i32); + + let err = libz_ng_sys::deflateEnd(stream); + assert_eq!(err, 0); + + stream.total_out as usize + }; + + assert_eq!(&output_rs[..n_rs], &output_ng[..n_ng]); +} + +#[test] +fn test_dict_deflate() { + let config = DeflateConfig { + level: Z_BEST_COMPRESSION, + ..Default::default() + }; + + const DICTIONARY: &str = "hello"; + const HELLO: &str = "hello, hello!\0"; + + let output_rs = unsafe { + let mut strm = MaybeUninit::zeroed(); + + // first validate the config + let err = libz_rs_sys::deflateInit2_( + strm.as_mut_ptr(), + config.level, + config.method as i32, + config.window_bits, + config.mem_level, + config.strategy as i32, + VERSION, + STREAM_SIZE, + ); + + assert_eq!(ReturnCode::from(err), ReturnCode::Ok); + + let strm = strm.assume_init_mut(); + + let err = + libz_rs_sys::deflateSetDictionary(strm, DICTIONARY.as_ptr(), DICTIONARY.len() as _); + + assert_eq!(ReturnCode::from(err), ReturnCode::Ok); + + let dictId = strm.adler; + let mut compr = [0; 32]; + strm.next_out = compr.as_mut_ptr(); + strm.avail_out = compr.len() as _; + + strm.next_in = HELLO.as_ptr() as *mut u8; + strm.avail_in = HELLO.len() as _; + + let err = deflate(strm, DeflateFlush::Finish as i32); + assert_eq!(ReturnCode::from(err), ReturnCode::StreamEnd); + + let err = deflateEnd(strm); + assert_eq!(ReturnCode::from(err), ReturnCode::Ok); + + (dictId, compr) + }; + + let output_ng = unsafe { + let mut strm = MaybeUninit::zeroed(); + + // first validate the config + let err = libz_ng_sys::deflateInit2_( + strm.as_mut_ptr(), + config.level, + config.method as i32, + config.window_bits, + config.mem_level, + config.strategy as i32, + libz_ng_sys::zlibVersion(), + core::mem::size_of::() as _, + ); + + assert_eq!(ReturnCode::from(err), ReturnCode::Ok); + + let strm = strm.assume_init_mut(); + + let err = + libz_ng_sys::deflateSetDictionary(strm, DICTIONARY.as_ptr(), DICTIONARY.len() as _); + + assert_eq!(ReturnCode::from(err), ReturnCode::Ok); + + let dictId = strm.adler; + let mut compr = [0; 32]; + strm.next_out = compr.as_mut_ptr(); + strm.avail_out = compr.len() as _; + + strm.next_in = HELLO.as_ptr() as *mut u8; + strm.avail_in = HELLO.len() as _; + + let err = libz_ng_sys::deflate(strm, DeflateFlush::Finish as i32); + assert_eq!(ReturnCode::from(err), ReturnCode::StreamEnd); + + let err = libz_ng_sys::deflateEnd(strm); + assert_eq!(ReturnCode::from(err), ReturnCode::Ok); + + (dictId, compr) + }; + + assert_eq!(output_rs.0, output_ng.0 as c_ulong); + assert_eq!(output_rs.1, output_ng.1); +} + +#[test] +fn test_deflate_prime() { + unsafe fn deflate_prime_32(stream: &mut libz_rs_sys::z_stream, value: i32) -> i32 { + // zlib's deflatePrime() takes at most 16 bits + let err = libz_rs_sys::deflatePrime(stream, 16, value & 0xffff); + if err != libz_rs_sys::Z_OK { + return err; + } + + libz_rs_sys::deflatePrime(stream, 16, value >> 16) + } + + let config = DeflateConfig { + level: -1, + method: Method::Deflated, + window_bits: -15, // deflate as raw bytes + mem_level: 8, + strategy: Strategy::Default, + }; + + unsafe { + let mut strm = MaybeUninit::zeroed(); + + // first validate the config + let err = libz_rs_sys::deflateInit2_( + strm.as_mut_ptr(), + config.level, + config.method as i32, + config.window_bits, + config.mem_level, + config.strategy as i32, + VERSION, + STREAM_SIZE, + ); + assert_eq!(err, 0); + + let strm = strm.assume_init_mut(); + + /* Gzip magic number */ + use libz_rs_sys::deflatePrime; + let mut err; + err = deflatePrime(strm, 16, 0x8b1f); + assert_eq!(ReturnCode::from(err), ReturnCode::Ok); + /* Gzip compression method (deflate) */ + err = deflatePrime(strm, 8, 0x08); + assert_eq!(ReturnCode::from(err), ReturnCode::Ok); + /* Gzip flags (one byte, using two odd bit calls) */ + err = deflatePrime(strm, 3, 0x0); + assert_eq!(ReturnCode::from(err), ReturnCode::Ok); + err = deflatePrime(strm, 5, 0x0); + assert_eq!(ReturnCode::from(err), ReturnCode::Ok); + /* Gzip modified time */ + err = deflate_prime_32(strm, 0); + assert_eq!(ReturnCode::from(err), ReturnCode::Ok); + /* Gzip extra flags */ + err = deflatePrime(strm, 8, 0x0); + assert_eq!(ReturnCode::from(err), ReturnCode::Ok); + /* Gzip operating system */ + err = deflatePrime(strm, 8, 255); + assert_eq!(ReturnCode::from(err), ReturnCode::Ok); + + const HELLO: &str = "hello, hello!\0"; + + strm.next_in = HELLO.as_ptr() as *mut u8; + strm.avail_in = HELLO.len() as _; + + let mut compr = [0xAA; 64]; + strm.next_out = compr.as_mut_ptr(); + strm.avail_out = compr.len() as _; + + err = libz_rs_sys::deflate(strm, DeflateFlush::Finish as i32); + assert_eq!(err, ReturnCode::StreamEnd as i32); + + dbg!(strm.total_out); + + /* Gzip uncompressed data crc32 */ + let crc = libz_rs_sys::crc32(0, HELLO.as_ptr(), HELLO.len() as _); + dbg!(crc.to_le_bytes()); + err = deflate_prime_32(strm, crc as _); + assert_eq!(err, 0); + /* Gzip uncompressed data length */ + err = deflate_prime_32(strm, HELLO.len() as _); + assert_eq!(err, 0); + + let total_out = strm.total_out; + + err = libz_rs_sys::deflateEnd(strm); + assert_eq!(err, 0); // inflate with gzip header + + // now inflate it again + let inflate_config = InflateConfig { + window_bits: 15 + 32, + }; + + let mut strm = MaybeUninit::zeroed(); + + let err = libz_rs_sys::inflateInit2_( + strm.as_mut_ptr(), + inflate_config.window_bits, + VERSION, + STREAM_SIZE, + ); + assert_eq!(ReturnCode::from(err), ReturnCode::Ok); + + let strm = strm.assume_init_mut(); + + strm.next_in = compr.as_mut_ptr(); + strm.avail_in = total_out as _; + + let mut uncompr = vec![0; 32]; + strm.next_out = uncompr.as_mut_ptr(); + strm.avail_out = uncompr.len() as _; + + // the crc checksum is not actually in the buffer, so the check of the checksum will error + // out with a BufError because there is insufficient input. + let err = libz_rs_sys::inflate(strm, DeflateFlush::Finish as i32); + assert_eq!(ReturnCode::from(err), ReturnCode::BufError); + assert_eq!(&uncompr[..strm.total_out as usize], HELLO.as_bytes()) + } +} + +#[test] +fn small_window() { + let deflate_config = DeflateConfig { + level: Z_BEST_COMPRESSION, + method: Method::Deflated, + window_bits: -9, + mem_level: 8, + strategy: Strategy::Default, + }; + + let inflate_config = InflateConfig { + window_bits: deflate_config.window_bits, + }; + + let plain: [u8; 128] = std::array::from_fn(|i| i as u8); + let dictionary1 = vec![b'a'; (1 << 9) - plain.len() / 2]; + + let output_rs = unsafe { + let mut strm = MaybeUninit::zeroed(); + + // first validate the config + let err = libz_rs_sys::deflateInit2_( + strm.as_mut_ptr(), + deflate_config.level, + deflate_config.method as i32, + deflate_config.window_bits, + deflate_config.mem_level, + deflate_config.strategy as i32, + VERSION, + STREAM_SIZE, + ); + assert_eq!(ReturnCode::from(err), ReturnCode::Ok); + + let strm = strm.assume_init_mut(); + + let err = + libz_rs_sys::deflateSetDictionary(strm, dictionary1.as_ptr(), dictionary1.len() as _); + assert_eq!(ReturnCode::from(err), ReturnCode::Ok); + + let err = libz_rs_sys::deflateSetDictionary(strm, plain.as_ptr(), plain.len() as _); + assert_eq!(ReturnCode::from(err), ReturnCode::Ok); + + strm.next_in = plain.as_ptr() as *mut u8; + strm.avail_in = plain.len() as _; + + let mut compr = [0; 32]; + strm.next_out = compr.as_mut_ptr(); + strm.avail_out = compr.len() as _; + + let err = deflate(strm, DeflateFlush::Finish as i32); + assert_eq!(ReturnCode::from(err), ReturnCode::StreamEnd); + + let err = deflateEnd(strm); + assert_eq!(ReturnCode::from(err), ReturnCode::Ok); + + // now inflate it again + let mut strm = MaybeUninit::zeroed(); + + let err = libz_rs_sys::inflateInit2_( + strm.as_mut_ptr(), + inflate_config.window_bits, + VERSION, + STREAM_SIZE, + ); + assert_eq!(ReturnCode::from(err), ReturnCode::Ok); + + let strm = strm.assume_init_mut(); + + let err = + libz_rs_sys::inflateSetDictionary(strm, dictionary1.as_ptr(), dictionary1.len() as _); + assert_eq!(ReturnCode::from(err), ReturnCode::Ok); + + let err = libz_rs_sys::inflateSetDictionary(strm, plain.as_ptr(), plain.len() as _); + assert_eq!(ReturnCode::from(err), ReturnCode::Ok); + + strm.next_in = compr.as_mut_ptr(); + strm.avail_in = compr.len() as _; + + let mut plain_again = vec![0; plain.len()]; + strm.next_out = plain_again.as_mut_ptr(); + strm.avail_out = plain_again.len() as _; + + let err = libz_rs_sys::inflate(strm, DeflateFlush::NoFlush as i32); + assert_eq!(ReturnCode::from(err), ReturnCode::StreamEnd); + + let err = libz_rs_sys::inflateEnd(strm); + assert_eq!(ReturnCode::from(err), ReturnCode::Ok); + + compr + }; + + let output_ng = unsafe { + let mut strm = MaybeUninit::zeroed(); + + // first validate the config + let err = libz_ng_sys::deflateInit2_( + strm.as_mut_ptr(), + deflate_config.level, + deflate_config.method as i32, + deflate_config.window_bits, + deflate_config.mem_level, + deflate_config.strategy as i32, + libz_ng_sys::zlibVersion(), + core::mem::size_of::() as _, + ); + assert_eq!(ReturnCode::from(err), ReturnCode::Ok); + + let strm = strm.assume_init_mut(); + + let err = + libz_ng_sys::deflateSetDictionary(strm, dictionary1.as_ptr(), dictionary1.len() as _); + assert_eq!(ReturnCode::from(err), ReturnCode::Ok); + + let err = libz_ng_sys::deflateSetDictionary(strm, plain.as_ptr(), plain.len() as _); + assert_eq!(ReturnCode::from(err), ReturnCode::Ok); + + strm.next_in = plain.as_ptr() as *mut u8; + strm.avail_in = plain.len() as _; + + let mut compr = [0; 32]; + strm.next_out = compr.as_mut_ptr(); + strm.avail_out = compr.len() as _; + + let err = libz_ng_sys::deflate(strm, DeflateFlush::Finish as i32); + assert_eq!(ReturnCode::from(err), ReturnCode::StreamEnd); + + let err = libz_ng_sys::deflateEnd(strm); + assert_eq!(ReturnCode::from(err), ReturnCode::Ok); + + // now inflate it again + let mut strm = MaybeUninit::zeroed(); + + let err = libz_ng_sys::inflateInit2_( + strm.as_mut_ptr(), + inflate_config.window_bits, + libz_ng_sys::zlibVersion(), + core::mem::size_of::() as _, + ); + assert_eq!(ReturnCode::from(err), ReturnCode::Ok); + + let strm = strm.assume_init_mut(); + + let err = + libz_ng_sys::inflateSetDictionary(strm, dictionary1.as_ptr(), dictionary1.len() as _); + assert_eq!(ReturnCode::from(err), ReturnCode::Ok); + + let err = libz_ng_sys::inflateSetDictionary(strm, plain.as_ptr(), plain.len() as _); + assert_eq!(ReturnCode::from(err), ReturnCode::Ok); + + strm.next_in = compr.as_mut_ptr(); + strm.avail_in = compr.len() as _; + + let mut plain_again = vec![0; plain.len()]; + strm.next_out = plain_again.as_mut_ptr(); + strm.avail_out = plain_again.len() as _; + + let err = libz_ng_sys::inflate(strm, DeflateFlush::NoFlush as i32); + assert_eq!(ReturnCode::from(err), ReturnCode::StreamEnd); + + let err = libz_ng_sys::inflateEnd(strm); + assert_eq!(ReturnCode::from(err), ReturnCode::Ok); + + compr + }; + + assert_eq!(output_rs, output_ng); +} + +#[test] +fn test_deflate_pending() { + const HELLO: &str = "hello, hello!\0"; + + let config = DeflateConfig::default(); + + let mut strm = MaybeUninit::zeroed(); + + unsafe { + // first validate the config + let err = libz_rs_sys::deflateInit2_( + strm.as_mut_ptr(), + config.level, + config.method as i32, + config.window_bits, + config.mem_level, + config.strategy as i32, + VERSION, + STREAM_SIZE, + ); + assert_eq!(err, 0); + + let strm = strm.assume_init_mut(); + + let mut compr = [0; 32]; + strm.next_in = HELLO.as_ptr() as *mut u8; + strm.next_out = compr.as_mut_ptr(); + + let it_in = HELLO.as_bytes().chunks(1); + let mut it_out = compr.chunks(1); + + for (_, _) in it_in.zip(&mut it_out) { + strm.avail_in = 1; + strm.avail_out = 1; + let err = deflate(strm, DeflateFlush::NoFlush as i32); + assert_eq!(err, 0); + } + + let mut ped = 0; + let mut bits = 0; + + let err = libz_rs_sys::deflatePending(strm, std::ptr::null_mut(), std::ptr::null_mut()); + assert_eq!(err, 0); + + let err = libz_rs_sys::deflatePending(strm, &mut ped, std::ptr::null_mut()); + assert_eq!(err, 0); + + let err = libz_rs_sys::deflatePending(strm, std::ptr::null_mut(), &mut bits); + assert_eq!(err, 0); + + let err = libz_rs_sys::deflatePending(strm, &mut ped, &mut bits); + assert_eq!(err, 0); + + assert!(bits >= 0); + assert!(bits <= 7); + + /* Finish the stream, still forcing small buffers: */ + for _ in it_out { + strm.avail_out = 1; + let err = deflate(strm, libz_rs_sys::Z_FINISH); + if err == libz_rs_sys::Z_STREAM_END { + break; + }; + assert_eq!(err, 0); + } + + let err = deflateEnd(strm); + assert_eq!(err, 0); + } +} + +/// test deflate() with DeflateFlush::Full +#[test] +fn test_flush() { + let config = DeflateConfig::default(); + + const HELLO: &str = "hello, hello!\0"; + let mut compr = [0; 32]; + + unsafe { + let mut strm = MaybeUninit::zeroed(); + + // first validate the config + let err = libz_rs_sys::deflateInit2_( + strm.as_mut_ptr(), + config.level, + config.method as i32, + config.window_bits, + config.mem_level, + config.strategy as i32, + VERSION, + STREAM_SIZE, + ); + assert_eq!(ReturnCode::from(err), ReturnCode::Ok); + + let stream = strm.assume_init_mut(); + + stream.next_in = HELLO.as_ptr() as *mut u8; + stream.next_out = compr.as_mut_ptr(); + + stream.avail_in = 3; + stream.avail_out = compr.len() as _; + + let err = libz_rs_sys::deflate(stream, DeflateFlush::FullFlush as i32); + assert_eq!(ReturnCode::from(err), ReturnCode::Ok); + + // force an error in the first compressed block + compr[3] += 1; + stream.avail_in = (HELLO.len() - 3) as _; + + let err = libz_rs_sys::deflate(stream, DeflateFlush::Finish as i32); + assert_eq!(ReturnCode::from(err), ReturnCode::StreamEnd); + + let err = libz_rs_sys::deflateEnd(stream); + assert_eq!(ReturnCode::from(err), ReturnCode::Ok); + } + + test_sync(&compr) +} + +// test inflateSync() +fn test_sync(compr: &[u8]) { + let mut uncompr = [0xAA; 32]; + + let mut stream = MaybeUninit::zeroed(); + + let config = InflateConfig::default(); + + unsafe { + let err = libz_rs_sys::inflateInit2_( + stream.as_mut_ptr(), + config.window_bits, + VERSION, + STREAM_SIZE, + ); + assert_eq!(ReturnCode::from(err), ReturnCode::Ok); + + let stream = stream.assume_init_mut(); + + stream.next_in = compr.as_ptr() as *mut u8; + stream.avail_in = 2; // read just the zlib header + + stream.next_out = uncompr.as_mut_ptr(); + stream.avail_out = uncompr.len() as _; + + let err = libz_rs_sys::inflate(stream, DeflateFlush::NoFlush as i32); + assert_eq!(ReturnCode::from(err), ReturnCode::Ok); + + stream.avail_in = (compr.len() - 2) as _; // read all compressed data + let err = libz_rs_sys::inflateSync(stream); // but skip the damaged part (at index 3) + assert_eq!(ReturnCode::from(err), ReturnCode::Ok); + + let err = libz_rs_sys::inflate(stream, DeflateFlush::Finish as i32); + assert_eq!(ReturnCode::from(err), ReturnCode::StreamEnd); + + let err = libz_rs_sys::inflateEnd(stream); + assert_eq!(ReturnCode::from(err), ReturnCode::Ok); + } +} + +#[test] +fn test_deflate_hash_head_0() { + use libz_rs_sys::{ + deflate, deflateEnd, deflateInit2_, deflateParams, Z_DEFLATED, Z_FINISH, Z_FULL_FLUSH, + Z_HUFFMAN_ONLY, Z_SYNC_FLUSH, + }; + + const MAX_WBITS: i32 = 15; + + let mut strm = MaybeUninit::zeroed(); + let mut err; + + err = unsafe { + deflateInit2_( + strm.as_mut_ptr(), + 1, + Z_DEFLATED, + -15, + 4, + Z_HUFFMAN_ONLY, + VERSION, + STREAM_SIZE, + ) + }; + assert_eq!(ReturnCode::from(err), ReturnCode::Ok); + + let strm = unsafe { strm.assume_init_mut() }; + + let mut next_in = [0x30; 9698]; + + next_in[8193] = 0x00; + next_in[8194] = 0x00; + next_in[8195] = 0x00; + next_in[8199] = 0x8a; + + strm.next_in = next_in.as_mut_ptr(); + let mut next_out = [0u8; 21572]; + strm.next_out = next_out.as_mut_ptr(); + + strm.avail_in = 0; + strm.avail_out = 1348; + err = unsafe { deflateParams(strm, 3, Z_FILTERED) }; + assert_eq!(ReturnCode::from(err), ReturnCode::Ok); + + strm.avail_in = 6728; + strm.avail_out = 2696; + err = unsafe { deflate(strm, Z_SYNC_FLUSH) }; + assert_eq!(ReturnCode::from(err), ReturnCode::Ok); + + strm.avail_in = 15; + strm.avail_out = 1348; + err = unsafe { deflateParams(strm, 9, Z_FILTERED) }; + assert_eq!(ReturnCode::from(err), ReturnCode::Ok); + + strm.avail_in = 1453; + strm.avail_out = 1348; + err = unsafe { deflate(strm, Z_FULL_FLUSH) }; + + assert_eq!(ReturnCode::from(err), ReturnCode::Ok); + + strm.avail_in = (next_in.as_mut_ptr() as usize + next_in.len() - strm.next_in as usize) as _; + strm.avail_out = (next_out.as_ptr() as usize + next_out.len() - strm.next_out as usize) as _; + err = unsafe { deflate(strm, Z_FINISH) }; + assert_eq!(ReturnCode::from(err), ReturnCode::StreamEnd); + + let compressed_size = strm.next_out as usize - next_out.as_ptr() as usize; + + err = unsafe { deflateEnd(strm) }; + + assert_eq!(ReturnCode::from(err), ReturnCode::Ok); + + let mut strm = MaybeUninit::zeroed(); + + err = unsafe { inflateInit2_(strm.as_mut_ptr(), -MAX_WBITS, VERSION, STREAM_SIZE) }; + assert_eq!(ReturnCode::from(err), ReturnCode::Ok); + + let strm = unsafe { strm.assume_init_mut() }; + + strm.next_in = next_out.as_mut_ptr(); + strm.avail_in = compressed_size as _; + let mut uncompressed = [0; 9698]; + assert_eq!(next_in.len(), uncompressed.len()); + + strm.next_out = uncompressed.as_mut_ptr(); + strm.avail_out = uncompressed.len() as _; + + err = unsafe { inflate(strm, Z_NO_FLUSH) }; + assert_eq!(ReturnCode::from(err), ReturnCode::StreamEnd); + + err = unsafe { inflateEnd(strm) }; + assert_eq!(ReturnCode::from(err), ReturnCode::Ok); + + assert_eq!(uncompressed, next_in); +} + +#[test] +fn test_deflate_copy() { + const HELLO: &str = "hello, hello!\0"; + + let config = DeflateConfig::default(); + + let mut strm = MaybeUninit::zeroed(); + + unsafe { + // first validate the config + let err = libz_rs_sys::deflateInit2_( + strm.as_mut_ptr(), + config.level, + config.method as i32, + config.window_bits, + config.mem_level, + config.strategy as i32, + VERSION, + STREAM_SIZE, + ); + assert_eq!(err, 0); + + let strm = strm.assume_init_mut(); + + let mut compr = [0; 32]; + strm.next_in = HELLO.as_ptr() as *mut u8; + strm.next_out = compr.as_mut_ptr(); + + for _ in HELLO.as_bytes() { + strm.avail_in = 1; + strm.avail_out = 1; + + let err = libz_rs_sys::deflate(strm, DeflateFlush::NoFlush as i32); + assert_eq!(err, 0); + } + + loop { + strm.avail_out = 1; + let err = libz_rs_sys::deflate(strm, DeflateFlush::Finish as i32); + + if ReturnCode::from(err) == ReturnCode::StreamEnd { + break; + } + + assert_eq!(err, 0); + } + + let mut copy = MaybeUninit::uninit(); + let err = libz_rs_sys::deflateCopy(copy.as_mut_ptr(), strm); + assert_eq!(err, 0); + + assert_eq!( + *(strm.state as *const u8), + *(((*copy.as_mut_ptr()).state) as *const u8), + ); + + let err = libz_rs_sys::deflateEnd(strm); + assert_eq!(err, 0); + + let err = libz_rs_sys::deflateEnd(copy.as_mut_ptr()); + assert_eq!(err, 0); + } +} + +#[test] +fn version_error() { + use libz_rs_sys::{deflateInit_, z_stream, zlibVersion, Z_OK, Z_VERSION_ERROR}; + + let mut stream = core::mem::MaybeUninit::zeroed(); + + let ret = unsafe { + deflateInit_( + stream.as_mut_ptr(), + 1, + zlibVersion(), + core::mem::size_of::() as i32, + ) + }; + assert_eq!(ret, Z_OK); + + // invalid stream size + let ret = unsafe { deflateInit_(stream.as_mut_ptr(), 1, zlibVersion(), 1) }; + assert_eq!(ret, Z_VERSION_ERROR); + + // version is null + let ret = unsafe { + deflateInit_( + stream.as_mut_ptr(), + 1, + core::ptr::null(), + core::mem::size_of::() as i32, + ) + }; + assert_eq!(ret, Z_VERSION_ERROR); + + // version is invalid + let ret = unsafe { + deflateInit_( + stream.as_mut_ptr(), + 1, + b"!\0".as_ptr() as *const c_char, + core::mem::size_of::() as i32, + ) + }; + assert_eq!(ret, Z_VERSION_ERROR); + + // version is invalid, deflateInit2_ + let ret = unsafe { + deflateInit2_( + stream.as_mut_ptr(), + 1, + 0, + 0, + 0, + 0, + b"!\0".as_ptr() as *const c_char, + core::mem::size_of::() as i32, + ) + }; + assert_eq!(ret, Z_VERSION_ERROR); +} diff --git a/third_party/rust/libz-rs-sys/src/tests/inflate.rs b/third_party/rust/libz-rs-sys/src/tests/inflate.rs new file mode 100644 index 000000000000..b4212def3542 --- /dev/null +++ b/third_party/rust/libz-rs-sys/src/tests/inflate.rs @@ -0,0 +1,1812 @@ +use core::mem::ManuallyDrop; + +use crate as libz_rs_sys; + +use libz_rs_sys::*; +use std::ffi::CStr; +use zlib_rs::deflate::compress_slice; +use zlib_rs::inflate::{set_mode_dict, uncompress_slice, INFLATE_STATE_SIZE}; +use zlib_rs::MAX_WBITS; + +const VERSION: *const c_char = libz_rs_sys::zlibVersion(); +const STREAM_SIZE: c_int = core::mem::size_of::() as c_int; + +#[derive(Clone, Copy)] +struct MemItem { + ptr: *mut c_void, + size: usize, +} + +struct MemZone { + items: Vec, + total: usize, + highwater: usize, + limit: usize, + not_lifo: usize, + rogue: usize, +} + +unsafe extern "C" fn mem_alloc(mem: *mut c_void, count: u32, size: u32) -> *mut c_void { + let count = count as usize; + let size = size as usize; + let len = count * size; + + // induced allocation failure + if mem.is_null() { + return std::ptr::null_mut(); + } + + let mut zone = ManuallyDrop::new(unsafe { Box::from_raw(mem as *mut MemZone) }); + + // induced allocation failure + if zone.limit != 0 && zone.total + len > zone.limit { + return std::ptr::null_mut(); + } + + extern "C" { + fn malloc(size: usize) -> *mut c_void; + } + + // perform the allocation + let ptr = unsafe { malloc(len) }; + if ptr.is_null() { + return std::ptr::null_mut(); + } + + // fill the memory to make sure that the code does not depend on zeros + unsafe { std::ptr::write_bytes(ptr, 0xa5, len) }; + + // create a new item for the list + let item = MemItem { ptr, size: len }; + + // update the statistics + zone.total += item.size; + if zone.total > zone.highwater { + zone.highwater = zone.total; + } + + // insert item + zone.items.push(item); + + // return the allocated memory + ptr +} + +unsafe extern "C" fn mem_free(mem: *mut c_void, ptr: *mut c_void) { + extern "C" { + fn free(p: *mut c_void); + } + + if mem.is_null() { + unsafe { free(ptr) }; + return; + } + + let mut zone = ManuallyDrop::new(unsafe { Box::from_raw(mem as *mut MemZone) }); + + let last = zone.items.pop(); + let mut found = None; + + if let Some(last) = last { + if last.ptr == ptr { + // this is it + found = Some(last); + } else { + zone.items.push(last); + + let index = zone.items.iter().position(|item| item.ptr == ptr); + + if let Some(index) = index { + let last = zone.items.remove(index); + found = Some(last); + zone.not_lifo += 1; + } + } + } + + if let Some(item) = found { + zone.total -= item.size; + } else { + zone.rogue += 1; + } + + unsafe { free(ptr) } +} + +fn mem_setup() -> z_stream { + let zone = MemZone { + items: Vec::new(), + total: 0, + highwater: 0, + limit: 0, + not_lifo: 0, + rogue: 0, + }; + let zone = Box::new(zone); + + let stream = z_stream { + next_in: std::ptr::null_mut(), + avail_in: 0, + total_in: 0, + next_out: std::ptr::null_mut(), + avail_out: 0, + total_out: 0, + msg: std::ptr::null_mut(), + state: std::ptr::null_mut(), + zalloc: Some(mem_alloc), + zfree: Some(mem_free), + opaque: Box::leak(zone) as *mut _ as *mut c_void, + data_type: 0, + adler: 0, + reserved: 0, + }; + + stream +} + +fn mem_limit(stream: &mut z_stream, limit: usize) { + assert!(!stream.opaque.is_null()); + + let mut zone = ManuallyDrop::new(unsafe { Box::from_raw(stream.opaque as *mut MemZone) }); + zone.limit = limit; +} + +fn mem_done(stream: &mut z_stream) { + assert!(!stream.opaque.is_null()); + + extern "C" { + fn free(p: *mut c_void); + } + + // zone not wrapped in ManuallyDrop so it is free'd + let mut zone = unsafe { Box::from_raw(stream.opaque as *mut MemZone) }; + + let count = zone.items.len(); + + for item in zone.items.drain(..) { + unsafe { free(item.ptr) }; + } + + assert_eq!( + (count, zone.total), + (0, 0), + "{} bytes in {count} blocks not freed", + zone.total + ); + assert_eq!(zone.not_lifo, 0, "{} frees not LIFO", zone.not_lifo); + assert_eq!(zone.rogue, 0, "{} frees not recognized", zone.rogue); + + stream.opaque = std::ptr::null_mut(); + stream.zalloc = None; + stream.zfree = None; +} + +#[test] +fn gzip_header_check() { + let input: &[u8] = &[ + 0x1f, 0x8b, 0x08, 0x1f, 0x44, 0x0a, 0x45, 0x65, 0x00, 0x03, 0x0e, 0x00, 0x54, 0x47, 0x0a, + 0x00, 0x45, 0x58, 0x54, 0x52, 0x41, 0x20, 0x44, 0x41, 0x54, 0x41, 0x74, 0x65, 0x73, 0x74, + 0x2e, 0x74, 0x78, 0x74, 0x00, 0x41, 0x20, 0x63, 0x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x74, 0x00, + 0x3b, 0x92, + ]; + + let _what = "gzip header parsing"; + let step = 0; + let len = 1; + let err = Z_OK; + + let err = Some(err); + let mut stream = mem_setup(); + + let init_err = unsafe { inflateInit2_(&mut stream, 47, VERSION, STREAM_SIZE) }; + if init_err != Z_OK { + mem_done(&mut stream); + return; + } + + let mut out = vec![0u8; len]; + let extra: [u8; 14] = [0; 14]; + let name: [u8; 9] = [0; 9]; + let comment: [u8; 10] = [0; 10]; + + // Set header + // See: https://www.zlib.net/manual.html + let mut header = gz_header { + text: 0, + time: 0, + xflags: 0, + os: 0, + extra: extra.as_ptr() as *mut u8, + extra_len: 0, + extra_max: 14, + name: name.as_ptr() as *mut u8, + name_max: 9, // How / where should this be set? + comment: comment.as_ptr() as *mut u8, + comm_max: 10, + hcrc: 0, + done: 0, + }; + + let ret = unsafe { inflateGetHeader(&mut stream, &mut header) }; + assert_eq!(ReturnCode::from(ret), ReturnCode::Ok); + + let have = input.len(); + let step = if step == 0 || step > have { have } else { step }; + + stream.avail_in = step as _; + stream.next_in = input.as_ptr() as *mut _; + + stream.avail_out = len as _; + stream.next_out = out.as_mut_ptr(); + + let ret = unsafe { inflate(&mut stream, InflateFlush::NoFlush as _) }; + + if let Some(err) = err { + if err != 9 { + assert_eq!(ret, err) + } + } + + assert_eq!(header.text, 1); + assert_eq!(header.time, 1699023428); + assert_eq!(header.os, 3); + assert_eq!(header.hcrc, 1); + assert_eq!(header.done, 1); + + // Check the header comment + let comment_string = match std::str::from_utf8(&comment) { + Ok(s) => s, + Err(_) => panic!("Invalid string found in comment"), + }; + assert_eq!("A comment\0", comment_string); + + // Check header original filename + let name_string = match std::str::from_utf8(&name) { + Ok(s) => s, + Err(_) => panic!("Invalid string found in name"), + }; + assert_eq!("test.txt\0", name_string); + + // Check header extra + let extra_bytes = [84, 71, 10, 0, 69, 88, 84, 82, 65, 32, 68, 65, 84, 65]; + assert_eq!(extra_bytes, extra); + + let ret = unsafe { inflateReset2(&mut stream, -8) }; + assert_eq!(ret, Z_OK); + + let ret = unsafe { inflateEnd(&mut stream) }; + assert_eq!(ret, Z_OK); + + mem_done(&mut stream); +} + +fn inf(input: &[u8], _what: &str, step: usize, win: i32, len: usize, err: c_int) { + let mut err = Some(err); + + let mut stream = mem_setup(); + + let init_err = unsafe { inflateInit2_(&mut stream, win, VERSION, STREAM_SIZE) }; + if init_err != Z_OK { + mem_done(&mut stream); + return; + } + + let mut out = vec![0u8; len]; + + let extra: [u8; 1024] = [0; 1024]; + let name: [u8; 64] = [0; 64]; + let comment: [u8; 64] = [0; 64]; + + // Set header + // See: https://www.zlib.net/manual.html + let mut header = gz_header { + text: 0, + time: 0, + xflags: 0, + os: 0, + extra: extra.as_ptr() as *mut u8, + extra_len: 0, + extra_max: 1024, + name: name.as_ptr() as *mut u8, + name_max: 64, // How / where should this be set? + comment: comment.as_ptr() as *mut u8, + comm_max: 64, + hcrc: 0, + done: 0, + }; + + if win == 47 { + let err = unsafe { inflateGetHeader(&mut stream, &mut header) }; + assert_eq!(ReturnCode::from(err), ReturnCode::Ok); + } + + let mut have = input.len(); + let step = if step == 0 || step > have { have } else { step }; + + stream.avail_in = step as _; + have -= step; + stream.next_in = input.as_ptr() as *mut _; + + loop { + stream.avail_out = len as _; + stream.next_out = out.as_mut_ptr(); + + let ret = unsafe { inflate(&mut stream, InflateFlush::NoFlush as _) }; + + if let Some(err) = err { + assert_eq!(ret, err) + } + + if !matches!(ret, Z_OK | Z_BUF_ERROR | Z_NEED_DICT) { + break; + } + + if matches!(ret, Z_NEED_DICT) { + let ret = unsafe { inflateSetDictionary(&mut stream, input.as_ptr(), 1) }; + println!("{:?}", ret); + assert_eq!(ret, Z_DATA_ERROR); + + mem_limit(&mut stream, 1); + let ret = unsafe { inflateSetDictionary(&mut stream, input.as_ptr(), 0) }; + assert_eq!(ret, Z_MEM_ERROR); + mem_limit(&mut stream, 0); + + unsafe { set_mode_dict(&mut stream) } + let ret = unsafe { inflateSetDictionary(&mut stream, out.as_ptr(), 0) }; + assert_eq!(ret, Z_OK); + + let ret = unsafe { inflate(&mut stream, InflateFlush::NoFlush as _) }; + assert_eq!(ret, Z_BUF_ERROR); + } + + let mut copy = z_stream::default(); + let ret = unsafe { inflateCopy(&mut copy, &stream) }; + assert_eq!(ret, Z_OK); + + let ret = unsafe { inflateEnd(&mut copy) }; + assert_eq!(ret, Z_OK); + + // only care about this error on the first iteration + err = None; + + have += stream.avail_in as usize; + stream.avail_in = if step > have { have } else { step } as _; + have -= stream.avail_in as usize; + + if stream.avail_in == 0 { + break; + } + } + + let ret = unsafe { inflateReset2(&mut stream, -8) }; + assert_eq!(ret, Z_OK); + + let ret = unsafe { inflateEnd(&mut stream) }; + assert_eq!(ret, Z_OK); + + mem_done(&mut stream); +} + +#[test] +fn support() { + let mut stream = mem_setup(); + + let ret = unsafe { + inflateInit_( + &mut stream, + zlibVersion(), + core::mem::size_of::() as i32, + ) + }; + assert_eq!(ret, Z_OK); + + let ret = unsafe { inflateSetDictionary(&mut stream, std::ptr::null(), 0) }; + assert_eq!(ret, Z_STREAM_ERROR); + + let ret = unsafe { inflateEnd(&mut stream) }; + assert_eq!(ret, Z_OK); + + mem_done(&mut stream); +} + +#[test] +fn force_window_allocation() { + inf(&[0x63, 0x00], "force window allocation", 0, -15, 1, Z_OK); +} + +#[test] +fn force_window_replacement() { + inf( + &[0x63, 0x18, 0x05], + "force window replacement", + 0, + -8, + 259, + Z_OK, + ); +} + +#[test] +fn force_split_window_update() { + inf( + &[0x63, 0x18, 0x68, 0x30, 0xd0, 0x0, 0x0], + "force split window update", + 4, + -8, + 259, + Z_OK, + ); +} + +#[test] +fn use_fixed_blocks() { + inf(&[0x03, 0x00], "use fixed blocks", 0, -15, 1, Z_STREAM_END); +} + +#[test] +fn bad_window_size() { + inf(&[], "bad window size", 0, 1, 0, Z_STREAM_ERROR); +} + +#[test] +fn cover_wrap() { + assert_eq!(unsafe { inflate(std::ptr::null_mut(), 0) }, Z_STREAM_ERROR); + assert_eq!(unsafe { inflateEnd(std::ptr::null_mut()) }, Z_STREAM_ERROR); + + let mut strm = mem_setup(); + strm.avail_in = 0; + strm.next_in = std::ptr::null_mut(); + let mut ret = unsafe { inflateInit2_(&mut strm, -8, VERSION, STREAM_SIZE) }; + let mut input = [0x63, 0x00]; + strm.avail_in = input.len() as _; + strm.next_in = input.as_mut_ptr().cast(); + strm.avail_out = 1; + strm.next_out = (&mut ret) as *mut _ as *mut u8; + mem_limit(&mut strm, 1); + ret = unsafe { inflate(&mut strm, InflateFlush::NoFlush as _) }; + assert_eq!(ret, Z_MEM_ERROR); + ret = unsafe { inflate(&mut strm, InflateFlush::NoFlush as _) }; + assert_eq!(ret, Z_MEM_ERROR); + mem_limit(&mut strm, 0); + + let dict = [0u8; 257]; + ret = unsafe { inflateSetDictionary(&mut strm, dict.as_ptr(), 257) }; + assert_eq!(ret, Z_OK); + + // ------------------------------ + + let size = 2 * INFLATE_STATE_SIZE + 256; + mem_limit(&mut strm, size); + + ret = unsafe { inflatePrime(&mut strm, 16, 0) }; + assert_eq!(ret, Z_OK); + + let mut input = [0x80u8, 0x00]; + strm.avail_in = input.len() as _; + strm.next_in = input.as_mut_ptr(); + ret = unsafe { inflateSync(&mut strm) }; + assert_eq!(ret, Z_DATA_ERROR); + + ret = unsafe { inflate(&mut strm, InflateFlush::NoFlush as _) }; + assert_eq!(ret, Z_STREAM_ERROR); + + let mut input = [0u8, 0, 0xFF, 0xFF]; + strm.avail_in = input.len() as _; + strm.next_in = input.as_mut_ptr(); + ret = unsafe { inflateSync(&mut strm) }; + assert_eq!(ret, Z_OK); + let _ = unsafe { inflateSyncPoint(&mut strm) }; + + let mut copy = z_stream::default(); + ret = unsafe { inflateCopy(&mut copy, &strm) }; + assert_eq!(ret, Z_MEM_ERROR); + + mem_limit(&mut strm, 0); + ret = unsafe { inflateUndermine(&mut strm, 1) }; + assert_eq!(ret, Z_OK); + + let _ = unsafe { inflateMark(&strm) }; + ret = unsafe { inflateEnd(&mut strm) }; + assert_eq!(ret, Z_OK); + mem_done(&mut strm); +} + +#[test] +fn bad_gzip_method() { + inf( + &[0x1f, 0x8b, 0x00, 0x00], + "bad gzip method", + 0, + 31, + 0, + Z_DATA_ERROR, + ) +} +#[test] +fn bad_gzip_flags() { + inf( + &[0x1f, 0x8b, 0x08, 0x80], + "bad gzip flags", + 0, + 31, + 0, + Z_DATA_ERROR, + ) +} +#[test] +fn bad_zlib_method() { + inf(&[0x77, 0x85], "bad zlib method", 0, 15, 0, Z_DATA_ERROR) +} +#[test] +fn set_window_size_from_header() { + inf(&[0x08, 0x99], "set window size from header", 0, 0, 0, Z_OK) +} +#[test] +fn bad_zlib_window_size() { + inf(&[0x78, 0x9c], "bad zlib window size", 0, 8, 0, Z_DATA_ERROR) +} +#[test] +fn check_adler32() { + inf( + &[0x78, 0x9c, 0x63, 0x0, 0x0, 0x0, 0x1, 0x0, 0x1], + "check adler32", + 0, + 15, + 1, + Z_STREAM_END, + ) +} +#[test] +fn bad_header_crc() { + inf( + &[ + 0x1f, 0x8b, 0x8, 0x1e, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x00, + ], + "bad header crc", + 0, + 47, + 1, + Z_DATA_ERROR, + ) +} + +#[test] +fn check_gzip_length() { + inf( + &[ + 0x1f, 0x8b, 0x8, 0x2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1d, 0x26, 0x3, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + ], + "check gzip length", + 0, + 47, + 0, + Z_STREAM_END, + ) +} + +#[test] +fn bad_zlib_header_check() { + inf( + &[0x78, 0x90], + "bad zlib header check", + 0, + 47, + 0, + Z_DATA_ERROR, + ) +} + +#[test] +fn good_zlib_header_check() { + inf( + &[ + 0x1f, 0x8b, 0x08, 0x1f, 0x44, 0x0a, 0x45, 0x65, 0x00, 0x03, 0x0e, 0x00, 0x54, 0x47, + 0x0a, 0x00, 0x45, 0x58, 0x54, 0x52, 0x41, 0x20, 0x44, 0x41, 0x54, 0x41, 0x74, 0x65, + 0x73, 0x74, 0x2e, 0x74, 0x78, 0x74, 0x00, 0x41, 0x20, 0x63, 0x6f, 0x6d, 0x6d, 0x65, + 0x6e, 0x74, 0x00, 0x3b, 0x92, + ], + "good zlib header check", + 0, + 47, + 0, + Z_OK, + ) +} + +#[test] +fn need_dictionary() { + inf( + &[0x08, 0xb8, 0x0, 0x0, 0x0, 0x1], + "need dictionary", + 0, + 8, + 0, + Z_NEED_DICT, + ) +} + +#[test] +fn compute_adler32() { + inf(&[0x78, 0x9c, 0x63, 0x0], "compute adler32", 0, 15, 1, Z_OK) +} + +/* do a raw inflate of data in hexadecimal with both inflate and inflateBack */ +fn try_inflate(input: &[u8], err: c_int) -> c_int { + let len = input.len(); + + /* allocate work areas */ + let size = len << 3; + let mut out = vec![0; size]; + // let mut win = vec![0; 32768]; + + // /* first with inflate */ + // strcpy(prefix, id); + // strcat(prefix, "-late"); + + let mut strm = mem_setup(); + strm.avail_in = 0; + strm.next_in = std::ptr::null_mut(); + + let mut ret = unsafe { + inflateInit2_( + &mut strm, + if err < 0 { 47 } else { -15 }, + VERSION, + STREAM_SIZE, + ) + }; + assert_eq!(ret, Z_OK); + strm.avail_in = len as _; + strm.next_in = input.as_ptr() as *mut u8; + + loop { + strm.avail_out = size as _; + strm.next_out = out.as_mut_ptr(); + + ret = unsafe { inflate(&mut strm, InflateFlush::Trees as _) }; + assert!(!matches!(ret, Z_STREAM_ERROR | Z_MEM_ERROR)); + + if matches!(ret, Z_DATA_ERROR | Z_NEED_DICT) { + break; + } + + if !(strm.avail_in > 0 || strm.avail_out == 0) { + break; + } + } + + if err != Z_OK { + assert_eq!(ret, Z_DATA_ERROR); + } + + unsafe { inflateEnd(&mut strm) }; + mem_done(&mut strm); + + // /* then with inflateBack */ + // if (err >= 0) { + // strcpy(prefix, id); + // strcat(prefix, "-back"); + // mem_setup(&strm); + // ret = PREFIX(inflateBackInit)(&strm, 15, win); + // assert(ret == Z_OK); + // strm.avail_in = len; + // strm.next_in = in; + // ret = PREFIX(inflateBack)(&strm, pull, NULL, push, NULL); + // assert(ret != Z_STREAM_ERROR); + // if (err && ret != Z_BUF_ERROR) { + // assert(ret == Z_DATA_ERROR); + // assert(strcmp(id, strm.msg) == 0); + // } + // PREFIX(inflateBackEnd)(&strm); + // mem_done(&strm, prefix); + // } + + ret +} + +#[test] +fn invalid_stored_block_length() { + try_inflate(&[0, 0, 0, 0, 0], Z_STREAM_END); +} + +#[test] +fn fixed() { + try_inflate(&[3, 0], Z_OK); +} + +#[test] +fn invalid_block_type() { + try_inflate(&[6], Z_STREAM_END); +} +#[test] +fn stored() { + try_inflate(&[0x1, 0x1, 0x0, 0xfe, 0xff, 0x0], Z_OK); +} + +#[test] +fn too_many_length_or_distance_symbols() { + try_inflate(&[0xfc, 0x0, 0x0], Z_STREAM_END); +} + +#[test] +fn invalid_code_lengths_set() { + try_inflate(&[0x4, 0x0, 0xfe, 0xff], Z_STREAM_END); +} +#[test] +fn invalid_bit_length_repeat_1() { + try_inflate(&[0x4, 0x0, 0x24, 0x49, 0x0], Z_STREAM_END); +} +#[test] +fn invalid_bit_length_repeat_2() { + try_inflate(&[0x4, 0x0, 0x24, 0xe9, 0xff, 0xff], Z_STREAM_END); +} +#[test] +fn invalid_code_missing_end_of_block() { + try_inflate(&[0x4, 0x0, 0x24, 0xe9, 0xff, 0x6d], Z_STREAM_END); +} +#[test] +fn invalid_literal_lengths_set() { + try_inflate( + &[ + 0x4, 0x80, 0x49, 0x92, 0x24, 0x49, 0x92, 0x24, 0x71, 0xff, 0xff, 0x93, 0x11, 0x0, + ], + Z_STREAM_END, + ); +} +#[test] +fn invalid_distances_set() { + try_inflate( + &[ + 0x4, 0x80, 0x49, 0x92, 0x24, 0x49, 0x92, 0x24, 0xf, 0xb4, 0xff, 0xff, 0xc3, 0x84, + ], + Z_STREAM_END, + ); +} +#[test] +fn invalid_literal_length_code() { + try_inflate( + &[ + 0x4, 0xc0, 0x81, 0x8, 0x0, 0x0, 0x0, 0x0, 0x20, 0x7f, 0xeb, 0xb, 0x0, 0x0, + ], + Z_STREAM_END, + ); +} +#[test] +fn invalid_distance_code() { + try_inflate(&[0x2, 0x7e, 0xff, 0xff], Z_STREAM_END); +} +#[test] +fn invalid_distance_too_far_back() { + try_inflate( + &[ + 0xc, 0xc0, 0x81, 0x0, 0x0, 0x0, 0x0, 0x0, 0x90, 0xff, 0x6b, 0x4, 0x0, + ], + Z_STREAM_END, + ); +} + +#[test] +fn incorrect_data_check() { + try_inflate( + &[ + 0x1f, 0x8b, 0x8, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3, 0x0, 0x0, 0x0, 0x0, 0x1, + ], + Z_ERRNO, + ); +} +#[test] +fn incorrect_length_check() { + try_inflate( + &[ + 0x1f, 0x8b, 0x8, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x1, + ], + Z_ERRNO, + ); +} + +#[test] +fn zlib_ng_pull_17() { + try_inflate( + &[ + 0x5, 0xc0, 0x21, 0xd, 0x0, 0x0, 0x0, 0x80, 0xb0, 0xfe, 0x6d, 0x2f, 0x91, 0x6c, + ], + Z_OK, + ); +} +#[test] +fn long_code() { + try_inflate( + &[ + 0x5, 0xe0, 0x81, 0x91, 0x24, 0xcb, 0xb2, 0x2c, 0x49, 0xe2, 0xf, 0x2e, 0x8b, 0x9a, 0x47, + 0x56, 0x9f, 0xfb, 0xfe, 0xec, 0xd2, 0xff, 0x1f, + ], + Z_OK, + ); +} +#[test] +fn length_extra() { + try_inflate( + &[ + 0xed, 0xc0, 0x1, 0x1, 0x0, 0x0, 0x0, 0x40, 0x20, 0xff, 0x57, 0x1b, 0x42, 0x2c, 0x4f, + ], + Z_OK, + ); +} +#[test] +fn long_distance_and_extra() { + try_inflate( + &[ + 0xed, 0xcf, 0xc1, 0xb1, 0x2c, 0x47, 0x10, 0xc4, 0x30, 0xfa, 0x6f, 0x35, 0x1d, 0x1, + 0x82, 0x59, 0x3d, 0xfb, 0xbe, 0x2e, 0x2a, 0xfc, 0xf, 0xc, + ], + Z_OK, + ); +} +#[test] +fn window_end() { + try_inflate( + &[ + 0xed, 0xc0, 0x81, 0x0, 0x0, 0x0, 0x0, 0x80, 0xa0, 0xfd, 0xa9, 0x17, 0xa9, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x6, + ], + Z_OK, + ); +} + +#[test] +fn inflate_fast_type_return() { + inf( + &[0x2, 0x8, 0x20, 0x80, 0x0, 0x3, 0x0], + "inflate_fast TYPE return", + 0, + -15, + 258, + Z_STREAM_END, + ); +} +#[test] +fn window_wrap() { + inf( + &[0x63, 0x18, 0x5, 0x40, 0xc, 0x0], + "window wrap", + 3, + -8, + 300, + Z_OK, + ); +} + +#[test] +fn fast_length_extra_bits() { + inf( + &[ + 0xe5, 0xe0, 0x81, 0xad, 0x6d, 0xcb, 0xb2, 0x2c, 0xc9, 0x01, 0x1e, 0x59, 0x63, 0xae, + 0x7d, 0xee, 0xfb, 0x4d, 0xfd, 0xb5, 0x35, 0x41, 0x68, 0xff, 0x7f, 0x0f, 0x0, 0x0, 0x0, + ], + "fast length extra bits", + 0, + -8, + 258, + Z_DATA_ERROR, + ); +} +#[test] +fn fast_distance_extra_bits() { + inf( + &[ + 0x25, 0xfd, 0x81, 0xb5, 0x6d, 0x59, 0xb6, 0x6a, 0x49, 0xea, 0xaf, 0x35, 0x6, 0x34, + 0xeb, 0x8c, 0xb9, 0xf6, 0xb9, 0x1e, 0xef, 0x67, 0x49, 0x50, 0xfe, 0xff, 0xff, 0x3f, + 0x0, 0x0, + ], + "fast distance extra bits", + 0, + -8, + 258, + Z_DATA_ERROR, + ) +} +#[test] +fn fast_invalid_distance_code() { + inf( + &[0x3, 0x7e, 0x0, 0x0, 0x0, 0x0, 0x0], + "fast invalid distance code", + 0, + -8, + 258, + Z_DATA_ERROR, + ); +} +#[test] +fn fast_invalid_literal_length_code() { + inf( + &[0x1b, 0x7, 0x0, 0x0, 0x0, 0x0, 0x0], + "fast invalid literal/length code", + 0, + -8, + 258, + Z_DATA_ERROR, + ); +} +#[test] +fn fast_2nd_level_codes_and_too_far_back() { + inf( + &[ + 0xd, 0xc7, 0x1, 0xae, 0xeb, 0x38, 0xc, 0x4, 0x41, 0xa0, 0x87, 0x72, 0xde, 0xdf, 0xfb, + 0x1f, 0xb8, 0x36, 0xb1, 0x38, 0x5d, 0xff, 0xff, 0x0, + ], + "fast 2nd level codes and too far back", + 0, + -8, + 258, + Z_DATA_ERROR, + ); +} +#[test] +fn very_common_case() { + inf( + &[0x63, 0x18, 0x5, 0x8c, 0x10, 0x8, 0x0, 0x0, 0x0, 0x0], + "very common case", + 0, + -8, + 259, + Z_OK, + ); +} +#[test] +fn contiguous_and_wrap_around_window() { + inf( + &[ + 0x63, 0x60, 0x60, 0x18, 0xc9, 0x0, 0x8, 0x18, 0x18, 0x18, 0x26, 0xc0, 0x28, 0x0, 0x29, + 0x0, 0x0, 0x0, + ], + "contiguous and wrap around window", + 6, + -8, + 259, + Z_OK, + ); +} +#[test] +fn copy_direct_from_output() { + inf( + &[0x63, 0x0, 0x3, 0x0, 0x0, 0x0, 0x0, 0x0], + "copy direct from output", + 0, + -8, + 259, + Z_STREAM_END, + ); +} + +#[test] +fn cover_cve_2022_37434() { + inf( + &[ + 0x1f, 0x8b, 0x08, 0x04, 0x61, 0x62, 0x63, 0x64, 0x61, 0x62, 0x52, 0x51, 0x1f, 0x8b, + 0x08, 0x04, 0x61, 0x62, 0x63, 0x64, 0x61, 0x62, 0x52, 0x51, 0x1f, 0x8b, 0x08, 0x04, + 0x61, 0x62, 0x63, 0x64, 0x61, 0x62, 0x52, 0x51, 0x1f, 0x8b, 0x08, 0x04, 0x61, 0x62, + 0x63, 0x64, 0x61, 0x62, 0x52, 0x51, + ], + "wtf", + 13, + 47, + 12, + Z_OK, + ); +} + +fn uncompress_help(input: &[u8]) -> Vec { + let mut dest_vec = vec![0u8; 1 << 16]; + + let mut dest_len = dest_vec.len() as c_ulong; + let dest = dest_vec.as_mut_ptr(); + + let source = input.as_ptr(); + let source_len = input.len() as _; + + let err = unsafe { uncompress(dest, &mut dest_len, source, source_len) }; + + if err != 0 { + panic!("error {:?}", libz_rs_sys::ReturnCode::from(err)); + } + + dest_vec.truncate(dest_len as usize); + + dest_vec +} + +#[test] +fn hello_world_uncompressed() { + // "Hello World!" compressed at level 0 + let deflated = [ + 0x78, 0x01, 0x01, 0x0d, 0x00, 0xf2, 0xff, 0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x20, 0x57, 0x6f, + 0x72, 0x6c, 0x64, 0x21, 0x0a, 0x20, 0x91, 0x04, 0x48, + ]; + + let output = uncompress_help(&deflated); + assert_eq!(String::from_utf8(output).unwrap(), "Hello World!\n"); +} + +#[test] +fn copy_direct_from_next_in_to_next_out() { + let deflated = [120, 1, 1, 2, 0, 253, 255, 6, 10, 0, 24, 0, 17]; + + let output = uncompress_help(&deflated); + assert_eq!(String::from_utf8(output).unwrap(), "\u{6}\n"); +} + +#[test] +fn hello_world_fixed() { + // "Hello World!" compressed with `minideflate -k -f -9` + let deflated = [ + 0x78, 0x01, 0xf3, 0x48, 0xcd, 0xc9, 0xc9, 0x57, 0x08, 0xcf, 0x2f, 0xca, 0x49, 0x51, 0xe4, + 0x02, 0x00, 0x20, 0x91, 0x04, 0x48, + ]; + let output = uncompress_help(&deflated); + assert_eq!(String::from_utf8(output).unwrap(), "Hello World!\n"); +} + +#[test] +fn hello_world_dynamic() { + // smallest input that the fuzzer found that triggers a dynamic block + let input = "\n\0\0\0\0l\0\nl\0l\0l\u{1}llll\n"; + let deflated = [ + 120, 156, 5, 193, 177, 1, 0, 0, 8, 195, 160, 184, 246, 86, 254, 159, 133, 85, 105, 146, + 131, 61, 24, 141, 3, 128, + ]; + + let output = uncompress_help(&deflated); + assert_eq!(String::from_utf8(output).unwrap(), input); +} + +#[test] +fn inflate_adler() { + const ORIGINAL: &str = "The quick brown fox jumped over the lazy dog\0"; + + const COMPRESSED: [u8; 52] = [ + 0x78, 0x9c, 0x0b, 0xc9, 0x48, 0x55, 0x28, 0x2c, 0xcd, 0x4c, 0xce, 0x56, 0x48, 0x2a, 0xca, + 0x2f, 0xcf, 0x53, 0x48, 0xcb, 0xaf, 0x50, 0xc8, 0x2a, 0xcd, 0x2d, 0x48, 0x4d, 0x51, 0xc8, + 0x2f, 0x4b, 0x2d, 0x52, 0x28, 0xc9, 0x48, 0x55, 0xc8, 0x49, 0xac, 0xaa, 0x54, 0x48, 0xc9, + 0x4f, 0x07, 0x00, 0x6b, 0x93, 0x10, 0x30, + ]; + + let mut stream = z_stream { + next_in: std::ptr::null_mut(), + avail_in: 0, + total_in: 0, + next_out: std::ptr::null_mut(), + avail_out: 0, + total_out: 0, + msg: std::ptr::null_mut(), + state: std::ptr::null_mut(), + zalloc: None, + zfree: None, + opaque: std::ptr::null_mut(), + data_type: 0, + adler: 0, + reserved: 0, + }; + + let err = unsafe { inflateInit2(&mut stream, 32 + MAX_WBITS) }; + assert_eq!(err, Z_OK); + + let mut uncompressed = [0u8; 1024]; + + stream.next_in = COMPRESSED.as_ptr() as *mut u8; + stream.avail_in = COMPRESSED.len() as _; + stream.next_out = uncompressed.as_mut_ptr(); + stream.avail_out = uncompressed.len() as _; + + let err = unsafe { inflate(&mut stream, Z_NO_FLUSH) }; + assert_eq!(err, Z_STREAM_END); + + assert_eq!(stream.adler, 0x6b931030); + + let err = unsafe { inflateEnd(&mut stream) }; + assert_eq!(err, Z_OK); + + let length = Ord::min(stream.total_out as usize, ORIGINAL.len()); + assert_eq!(&uncompressed[..length], &ORIGINAL.as_bytes()[..length]) +} + +#[test] +fn inflate_get_header_non_gzip_stream() { + let mut stream = mem_setup(); + + let win = 15; // i.e. zlib compression (and not gzip) + let init_err = unsafe { inflateInit2_(&mut stream, win, VERSION, STREAM_SIZE) }; + if init_err != Z_OK { + mem_done(&mut stream); + return; + } + + let mut header = gz_header::default(); + + assert_eq!( + unsafe { inflateGetHeader(&mut stream, &mut header) }, + ReturnCode::StreamError as i32 + ); +} + +#[test] +fn inflate_window_bits_0_is_15() { + let input = b"Hello World!\n"; + + let mut compressed = [0; 64]; + let (compressed, err) = compress_slice(&mut compressed, input, DeflateConfig::new(6)); + assert_eq!(err, ReturnCode::Ok); + + let config = InflateConfig { window_bits: 15 }; + let mut output_15 = [0; 64]; + let (output_15, err) = uncompress_slice(&mut output_15, compressed, config); + assert_eq!(err, ReturnCode::Ok); + + let config = InflateConfig { window_bits: 0 }; + let mut output_0 = [0; 64]; + let (output_0, err) = uncompress_slice(&mut output_0, compressed, config); + assert_eq!(err, ReturnCode::Ok); + + // for window size 0, the default of 15 is picked + // NOTE: the window size does not actually influence + // the output for an input this small. + assert_eq!(output_15, output_0); + + assert_eq!(output_15, input); +} + +#[test] +fn uncompress_edge_cases() { + let config = InflateConfig { window_bits: 15 }; + + let (result, err) = uncompress_slice(&mut [], &[], config); + assert_eq!(err, ReturnCode::DataError); + assert!(result.is_empty()); + + let mut output = [0; 1]; + let (result, err) = uncompress_slice(&mut output, &[], config); + assert_eq!(err, ReturnCode::DataError); + assert!(result.is_empty()); + + let input = b"Hello World!\n"; + + let mut compressed = [0; 64]; + let (compressed, err) = compress_slice(&mut compressed, input, DeflateConfig::new(6)); + assert_eq!(err, ReturnCode::Ok); + + let (result, err) = uncompress_slice(&mut [], compressed, config); + assert_eq!(err, ReturnCode::DataError); + assert!(result.is_empty()); +} + +#[test] +fn gzip_chunked_1_byte() { + gzip_chunked(1); +} + +#[test] +fn gzip_chunked_2_bytes() { + gzip_chunked(2); +} + +#[test] +fn gzip_chunked_32_bytes() { + gzip_chunked(32); +} + +#[test] +fn gzip_chunked_512_bytes() { + gzip_chunked(512); +} + +fn gzip_chunked(chunk_size: usize) { + let input = b"Hello World\n"; + + let extra = + "Scheduling and executing async tasks is a job handled by an async runtime, such as\0"; + let name = + "tokio, async-std, and smol. You’ve probably used them at some point, either directly or\0"; + let comment = + "indirectly. They, along with many frameworks that require async, do their best to hide\0"; + + let config = DeflateConfig { + window_bits: 31, + ..Default::default() + }; + + let mut stream = MaybeUninit::::zeroed(); + + const VERSION: *const c_char = libz_rs_sys::zlibVersion(); + const STREAM_SIZE: c_int = core::mem::size_of::() as c_int; + + let err = unsafe { + libz_rs_sys::deflateInit2_( + stream.as_mut_ptr(), + config.level, + config.method as i32, + config.window_bits, + config.mem_level, + config.strategy as i32, + VERSION, + STREAM_SIZE, + ) + }; + assert_eq!(err, 0); + + let stream = unsafe { stream.assume_init_mut() }; + + let mut header = libz_rs_sys::gz_header { + text: 0, + time: 0, + xflags: 0, + os: 0, + extra: extra.as_ptr() as *mut _, + extra_len: extra.len() as _, + extra_max: 0, + name: name.as_ptr() as *mut _, + name_max: 0, + comment: comment.as_ptr() as *mut _, + comm_max: 0, + hcrc: 1, + done: 0, + }; + + let err = unsafe { libz_rs_sys::deflateSetHeader(stream, &mut header) }; + assert_eq!(err, 0); + + let mut output_rs = [0u8; 512]; + stream.next_out = output_rs.as_mut_ptr(); + stream.avail_out = output_rs.len() as _; + + for chunk in input.chunks(chunk_size) { + stream.next_in = chunk.as_ptr() as *mut u8; + stream.avail_in = chunk.len() as _; + + let err = unsafe { deflate(stream, InflateFlush::NoFlush as _) }; + + assert_eq!(err, ReturnCode::Ok as i32, "{:?}", stream.msg); + } + + let err = unsafe { libz_rs_sys::deflate(stream, InflateFlush::Finish as _) }; + assert_eq!(ReturnCode::from(err), ReturnCode::StreamEnd); + + let output_rs = &mut output_rs[..stream.total_out as usize]; + + let err = unsafe { libz_rs_sys::deflateEnd(stream) }; + assert_eq!(ReturnCode::from(err), ReturnCode::Ok); + + { + #[allow(unused_imports)] // to switch to libz_ng_sys easily + use libz_rs_sys::{ + gz_header, inflate, inflateEnd, inflateGetHeader, inflateInit2_, z_stream, + }; + + let mut stream = MaybeUninit::::zeroed(); + + const VERSION: *const c_char = libz_rs_sys::zlibVersion(); + const STREAM_SIZE: c_int = core::mem::size_of::() as c_int; + + let err = unsafe { + inflateInit2_( + stream.as_mut_ptr(), + config.window_bits, + VERSION, + STREAM_SIZE, + ) + }; + assert_eq!(err, 0); + + let stream = unsafe { stream.assume_init_mut() }; + + let mut output = [0u8; 64]; + stream.next_out = output.as_mut_ptr(); + stream.avail_out = output.len() as _; + + let mut extra_buf = [0u8; 64]; + let mut name_buf = [0u8; 64]; + let mut comment_buf = [0u8; 256]; + + let mut header = gz_header { + text: 0, + time: 0, + xflags: 0, + os: 0, + extra: extra_buf.as_mut_ptr(), + extra_len: 0, + extra_max: extra_buf.len() as _, + name: name_buf.as_mut_ptr(), + name_max: name_buf.len() as _, + comment: comment_buf.as_mut_ptr(), + comm_max: comment_buf.len() as _, + hcrc: 0, + done: 0, + }; + + let err = unsafe { inflateGetHeader(stream, &mut header) }; + assert_eq!(err, 0); + + for chunk in output_rs.chunks_mut(chunk_size) { + stream.next_in = chunk.as_mut_ptr(); + stream.avail_in = chunk.len() as _; + + let err = unsafe { inflate(stream, InflateFlush::NoFlush as _) }; + + if err == ReturnCode::StreamEnd as i32 { + break; + } + + assert_eq!(err, ReturnCode::Ok as i32); + } + + let err = unsafe { inflateEnd(stream) }; + assert_eq!(err, ReturnCode::Ok as i32); + + assert!(!header.extra.is_null()); + assert_eq!( + std::str::from_utf8(&extra_buf).unwrap(), + &extra[..extra_buf.len()] + ); + + assert!(!header.name.is_null()); + assert_eq!( + std::str::from_utf8(&name_buf).unwrap(), + &name[..name_buf.len()] + ); + + assert!(!header.comment.is_null()); + assert_eq!( + unsafe { CStr::from_ptr(comment_buf.as_ptr().cast()) } + .to_str() + .unwrap(), + comment.trim_end_matches('\0') + ); + } +} + +#[test] +fn chunked_output_rs() { + let input = [99u8, 96, 192, 11, 24, 25, 0]; + + let mut stream = MaybeUninit::::zeroed(); + + let err = unsafe { inflateInit2_(stream.as_mut_ptr(), -15, VERSION, STREAM_SIZE) }; + assert_eq!(ReturnCode::from(err), ReturnCode::Ok); + + let stream = unsafe { stream.assume_init_mut() }; + + stream.next_in = input.as_ptr() as *mut u8; + stream.avail_in = input.len() as _; + + let mut output = [0; 33]; + + stream.next_out = output.as_mut_ptr(); + stream.avail_out = 32; + + let err = unsafe { inflate(stream, InflateFlush::NoFlush as _) }; + assert_eq!(ReturnCode::from(err), ReturnCode::Ok); + + assert_eq!(stream.avail_out, 0); + assert_eq!(stream.total_out, 32); + + stream.avail_out = 1; + + let err = unsafe { inflate(stream, InflateFlush::Finish as _) }; + assert_eq!(ReturnCode::from(err), ReturnCode::StreamEnd); + + assert_eq!(stream.total_out, 33); +} + +#[test] +fn version_error() { + let mut stream = core::mem::MaybeUninit::zeroed(); + + let ret = unsafe { + inflateInit_( + stream.as_mut_ptr(), + zlibVersion(), + core::mem::size_of::() as i32, + ) + }; + assert_eq!(ret, Z_OK); + + // invalid stream size + let ret = unsafe { inflateInit_(stream.as_mut_ptr(), zlibVersion(), 1) }; + assert_eq!(ret, Z_VERSION_ERROR); + + // version is null + let ret = unsafe { + inflateInit_( + stream.as_mut_ptr(), + core::ptr::null(), + core::mem::size_of::() as i32, + ) + }; + assert_eq!(ret, Z_VERSION_ERROR); + + // version is invalid + let ret = unsafe { + inflateInit_( + stream.as_mut_ptr(), + b"!\0".as_ptr() as *const c_char, + core::mem::size_of::() as i32, + ) + }; + assert_eq!(ret, Z_VERSION_ERROR); + + // version is invalid, inflateInit2_ + let ret = unsafe { + inflateInit2_( + stream.as_mut_ptr(), + 1, + b"!\0".as_ptr() as *const c_char, + core::mem::size_of::() as i32, + ) + }; + assert_eq!(ret, Z_VERSION_ERROR); +} + +#[test] +fn issue_109() { + let input = &include_bytes!("test-data/issue-109.gz")[10..][..32758]; + + let mut output_rs: Vec = Vec::with_capacity(1 << 15); + let mut output_ng: Vec = Vec::with_capacity(1 << 15); + + let window_bits = -15; + + let mut buf = [0; 8192]; + + { + let mut stream = MaybeUninit::::zeroed(); + + let err = unsafe { + inflateInit2_( + stream.as_mut_ptr(), + window_bits, + zlibVersion(), + core::mem::size_of::() as c_int, + ) + }; + assert_eq!(ReturnCode::from(err), ReturnCode::Ok); + + let stream = unsafe { stream.assume_init_mut() }; + + stream.next_in = input.as_ptr() as *mut u8; + stream.avail_in = input.len() as _; + + while stream.avail_in != 0 { + stream.next_out = buf.as_mut_ptr(); + stream.avail_out = buf.len() as _; + + let err = unsafe { inflate(stream, InflateFlush::NoFlush as _) }; + + if ReturnCode::from(err) == ReturnCode::BufError { + output_rs.extend(&buf[..stream.avail_out as usize]); + stream.avail_out = buf.len() as _; + continue; + } + } + } + + { + use libz_sys::*; + + let mut stream = MaybeUninit::::zeroed(); + + let err = unsafe { + inflateInit2_( + stream.as_mut_ptr(), + window_bits, + zlibVersion(), + core::mem::size_of::() as c_int, + ) + }; + assert_eq!(ReturnCode::from(err), ReturnCode::Ok); + + let stream = unsafe { stream.assume_init_mut() }; + + stream.next_in = input.as_ptr() as *mut u8; + stream.avail_in = input.len() as _; + + while stream.avail_in != 0 { + stream.next_out = buf.as_mut_ptr(); + stream.avail_out = buf.len() as _; + + let err = unsafe { inflate(stream, InflateFlush::NoFlush as _) }; + + if ReturnCode::from(err) == ReturnCode::BufError { + output_ng.extend(&buf[..stream.avail_out as usize]); + stream.avail_out = buf.len() as _; + continue; + } + } + } + + assert_eq!(output_rs, output_ng); +} + +#[test] +fn window_match_bug() { + // this hit some invalid logic in the inflate `match_` function where invalid bytes were copied + // to the current output position. + let input = &include_bytes!("test-data/window-match-bug.zraw"); + + let window_bits = -10; + + let mut output_rs: Vec = Vec::with_capacity(1 << 15); + let mut output_ng: Vec = Vec::with_capacity(1 << 15); + + let mut buf = [0; 402]; + + { + let mut stream = MaybeUninit::::zeroed(); + + let err = unsafe { + inflateInit2_( + stream.as_mut_ptr(), + window_bits, + zlibVersion(), + core::mem::size_of::() as c_int, + ) + }; + assert_eq!(ReturnCode::from(err), ReturnCode::Ok); + + let stream = unsafe { stream.assume_init_mut() }; + + stream.next_in = input.as_ptr() as *mut u8; + stream.avail_in = input.len() as _; + + loop { + stream.next_out = buf.as_mut_ptr(); + stream.avail_out = buf.len() as _; + + let err = unsafe { inflate(stream, InflateFlush::Finish as _) }; + + output_rs.extend(&buf[..buf.len() - stream.avail_out as usize]); + + match ReturnCode::from(err) { + ReturnCode::BufError => { + assert_eq!(stream.avail_out, 0); + stream.avail_out = buf.len() as _; + } + ReturnCode::StreamEnd => break, + other => panic!("unexpected {:?}", other), + } + } + } + + { + use libz_sys::*; + + let mut stream = MaybeUninit::::zeroed(); + + let err = unsafe { + inflateInit2_( + stream.as_mut_ptr(), + window_bits, + zlibVersion(), + core::mem::size_of::() as c_int, + ) + }; + assert_eq!(ReturnCode::from(err), ReturnCode::Ok); + + let stream = unsafe { stream.assume_init_mut() }; + + stream.next_in = input.as_ptr() as *mut u8; + stream.avail_in = input.len() as _; + + while stream.avail_in != 0 { + stream.next_out = buf.as_mut_ptr(); + stream.avail_out = buf.len() as _; + + let err = unsafe { inflate(stream, InflateFlush::Finish as _) }; + + output_ng.extend(&buf[..buf.len() - stream.avail_out as usize]); + + match ReturnCode::from(err) { + ReturnCode::BufError => { + assert_eq!(stream.avail_out, 0); + stream.avail_out = buf.len() as _; + } + ReturnCode::StreamEnd => break, + other => panic!("unexpected {:?}", other), + } + } + } + + assert_eq!(output_rs, output_ng); +} + +#[test] +fn op_len_edge_case() { + let window_bits = -9; + + let input = &include_bytes!("test-data/op-len-edge-case.zraw"); + + let mut output_rs: Vec = Vec::with_capacity(1 << 15); + let mut output_ng: Vec = Vec::with_capacity(1 << 15); + + let mut buf = [0; 266]; + + { + let mut stream = MaybeUninit::::zeroed(); + + let err = unsafe { + inflateInit2_( + stream.as_mut_ptr(), + window_bits, + zlibVersion(), + core::mem::size_of::() as c_int, + ) + }; + assert_eq!(ReturnCode::from(err), ReturnCode::Ok); + + let stream = unsafe { stream.assume_init_mut() }; + + stream.next_in = input.as_ptr() as *mut u8; + stream.avail_in = input.len() as _; + + while stream.avail_in != 0 { + stream.next_out = buf.as_mut_ptr(); + stream.avail_out = buf.len() as _; + + let err = unsafe { inflate(stream, InflateFlush::NoFlush as _) }; + + if ReturnCode::from(err) == ReturnCode::BufError { + output_rs.extend(&buf[..stream.avail_out as usize]); + stream.avail_out = buf.len() as _; + continue; + } + } + } + + { + use libz_sys::*; + + let mut stream = MaybeUninit::::zeroed(); + + let err = unsafe { + inflateInit2_( + stream.as_mut_ptr(), + window_bits, + zlibVersion(), + core::mem::size_of::() as c_int, + ) + }; + assert_eq!(ReturnCode::from(err), ReturnCode::Ok); + + let stream = unsafe { stream.assume_init_mut() }; + + stream.next_in = input.as_ptr() as *mut u8; + stream.avail_in = input.len() as _; + + while stream.avail_in != 0 { + stream.next_out = buf.as_mut_ptr(); + stream.avail_out = buf.len() as _; + + let err = unsafe { inflate(stream, InflateFlush::NoFlush as _) }; + + if ReturnCode::from(err) == ReturnCode::BufError { + output_ng.extend(&buf[..stream.avail_out as usize]); + stream.avail_out = buf.len() as _; + continue; + } + } + } + + assert_eq!(output_rs, output_ng); +} + +// Fills the provided buffer with pseudorandom bytes based on the given seed +// Duplicates bytes by `step` in a row +fn prng_bytes(seed: u64, bytes: &mut [u8], step: usize) { + const M: u64 = 2u64.pow(32); + const A: u64 = 1664525; + const C: u64 = 1013904223; + let mut state = seed; + for chunk in bytes.chunks_mut(4 * step) { + state = (A * state + C) % M; + let rand_bytes = state.to_le_bytes(); + for (i, byte) in chunk.iter_mut().enumerate() { + *byte = rand_bytes[i / step]; + } + } +} + +#[test] +fn test_inflate_flush_block() { + let window_bits = -15; // Raw + const CHUNK: usize = 16384; + + // Create a compressed vector of random data that's bigger then the zlib block size + let mut data = vec![0u8; 160000]; + prng_bytes(314159, &mut data, 4); + let config = DeflateConfig { + window_bits, + ..DeflateConfig::default() + }; + let mut output = vec![0u8; 80000]; + // Compress the data + let (compressed_data, return_code) = compress_slice(&mut output, &data, config); + assert_eq!(return_code, ReturnCode::Ok); + + // Log the stream positions and data_type output from libz + let mut zlib_log = Vec::new(); + { + let mut stream = MaybeUninit::::zeroed(); + + let ret = unsafe { + libz_sys::inflateInit2_( + stream.as_mut_ptr(), + window_bits, + libz_sys::zlibVersion(), + core::mem::size_of::() as c_int, + ) + }; + assert_eq!(ReturnCode::from(ret), ReturnCode::Ok); + + let mut output = vec![0u8; CHUNK * 2]; + let stream = unsafe { stream.assume_init_mut() }; + stream.next_in = compressed_data.as_ptr() as *mut u8; + stream.avail_in = compressed_data.len() as _; + loop { + stream.next_out = output.as_mut_ptr(); + stream.avail_out = output.len() as _; + + let ret = unsafe { libz_sys::inflate(stream, InflateFlush::Block as i32) }; + + let log = format!( + "In:{} Out:{} DT:{}", + stream.avail_in, stream.avail_out, stream.data_type + ); + zlib_log.push(log); + + assert_eq!(ReturnCode::from(ret), ReturnCode::Ok); + + if stream.avail_in == 0 { + break; + } + } + } + + // Log the stream positions and data_type output from libz_rs and compare + { + let mut stream = MaybeUninit::::zeroed(); + + let ret = unsafe { + inflateInit2_( + stream.as_mut_ptr(), + window_bits, + zlibVersion(), + core::mem::size_of::() as c_int, + ) + }; + assert_eq!(ReturnCode::from(ret), ReturnCode::Ok); + + let mut output = vec![0u8; CHUNK * 2]; + let stream = unsafe { stream.assume_init_mut() }; + stream.next_in = compressed_data.as_ptr() as *mut u8; + stream.avail_in = compressed_data.len() as _; + loop { + stream.next_out = output.as_mut_ptr(); + stream.avail_out = output.len() as _; + + let ret = unsafe { inflate(stream, InflateFlush::Block as i32) }; + + let log = format!( + "In:{} Out:{} DT:{}", + stream.avail_in, stream.avail_out, stream.data_type + ); + // Compare log entries + assert_eq!(zlib_log.remove(0), log); + + assert_eq!(ReturnCode::from(ret), ReturnCode::Ok); + + if stream.avail_in == 0 { + break; + } + } + } +} diff --git a/third_party/rust/libz-rs-sys/src/tests/mod.rs b/third_party/rust/libz-rs-sys/src/tests/mod.rs new file mode 100644 index 000000000000..febf69f2d636 --- /dev/null +++ b/third_party/rust/libz-rs-sys/src/tests/mod.rs @@ -0,0 +1,2 @@ +mod deflate; +mod inflate; diff --git a/third_party/rust/libz-rs-sys/src/tests/test-data/issue-109.gz b/third_party/rust/libz-rs-sys/src/tests/test-data/issue-109.gz new file mode 100644 index 0000000000000000000000000000000000000000..f32305a0266432c50e8f149adc4f7a0feeb4fcca GIT binary patch literal 42537 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%0Af`Gj*AjRKWw>6u3+cY@8(I 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 VK9$yT&EU#E{4bLMGT4sn0RZy7$a(+( literal 0 HcmV?d00001 diff --git a/third_party/rust/libz-rs-sys/src/tests/test-data/op-len-edge-case.zraw b/third_party/rust/libz-rs-sys/src/tests/test-data/op-len-edge-case.zraw new file mode 100644 index 0000000000000000000000000000000000000000..05deecb09dae9cdb7ad3c1588ac0f80becba3e4b GIT binary patch literal 633 zcmV-<0*3v~kFRgrP!Pv^d&n~gEHVhNqAH;Eq~L;1dZ1{kj4CU*3i4kNbzmf9G%z3_ zDjf@mf)5NBOjSYIq@c8DptHWa_rs2xE(z_&$$NMA?#K7O2cOH^{>RZJu3M9JIi7s| z1WPIZZy$bK3Pc3lV-HIHM86n>V^~{CSPcFN6mh{x%uMoH6y`ZyQc{4lMQPou(LQJ} zna`NY57QFUi;JnzbS>xovx#6xW|W=h6@=t`F*gJB>y{v!GBk$-Bx(X(NO7Y|ykrDd zMP8;x=2)$8CxfIe9t;M^+L+CZ2twWjhj_H-0`HAQnFbZxgnu;aMc}ZILYP43mVwY;9n{DR@sg!Tlk?V{Z zT~J8M_fhpzkGW2^n^~LcEK{b$$f`iqmW}&J*v$H3PrI>MIz^wa+I=nxyTo#NWpj}^ zRx8}uafkGzKl`751M@d*Cz(LNu@Mb_klRA}kPXL0zY7YLsv?R)Qt_)aR|XDAmeCf{x>uvM T(mLPZ#*4z8{Pl##jmZ2>xB=dP$W8gvmK%xRXNRUIw@?(3 z<*unR*FNIeIcLnNdGSVpG2XY6n^pT-fJhLLpl;T$LkRUEepmc%_oADzDoP$_S(J2? z>(25oC)sVMJDkx!-uBij-gx&7Eu|DOB05#ud#^F?MMzVs8`i1Nh%XCu_b@rq=F?AP C!IeY+ literal 0 HcmV?d00001 diff --git a/third_party/rust/zlib-rs/.cargo-checksum.json b/third_party/rust/zlib-rs/.cargo-checksum.json new file mode 100644 index 000000000000..bbbc86ecf345 --- /dev/null +++ b/third_party/rust/zlib-rs/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{"Cargo.toml":"ec3eadbc9e13ef2ceae8ff8feed443b9e6fd9ceaf3a98e0e0cf245964b4e594f","LICENSE":"7d60612df8fcd9d3714871a95b4d3012563246fdea8f6710b7567f83cfa3c8ef","README.md":"9938581c82330440be5f3b6b9125cc02c0874b250dc62093f167bf2158dbe29a","src/adler32.rs":"8a8f70daf888f55625ce316b5ff3432eb1713fd101f8b3f88ee4c3f08cbfe6bb","src/adler32/avx2.rs":"d4ef3e0729a5246a0af08c3078cabad17720585ee7a2ab2dfabe13c6d307a002","src/adler32/generic.rs":"cfe8da0e145faac42ed31e9de1ccb718e389265517a007533b8c997cae68f1a7","src/adler32/neon.rs":"8c30926d74573ee5b74b013c19bb1fcebe980ebaf8384df66dae4f957d856036","src/allocate.rs":"81ad93751a1c3206a1b0a63b1970c75b6f59556b094055626472e64380fe81dd","src/c_api.rs":"b41685bc20b96760ea7fdc0e1d30d550901be5dc12292f9c905d7dea177dfeca","src/crc32.rs":"30be91db6a8a6d7004b9dcab43c9fe7e8623c7425e31bf4eff5c537b0204dcab","src/crc32/acle.rs":"e2990813a358629a4ace5b409897416685c84ebebb1becbcd4062d2a2c3dee0a","src/crc32/braid.rs":"1b83372b944f49d954c39e7348707f1668fc7d1dad2c8b881fb5f98d3c98f8cb","src/crc32/combine.rs":"a1aded8c5f1886f60daad9765886299c65feb5240f24f8e9f67ebced14e267f0","src/crc32/pclmulqdq.rs":"891a57eea0e8d5ca4b5d5ee0dd69c62d0c9ecaa741c26ba09abedefe53fd446b","src/deflate.rs":"5ced180868deb00914496f6e012b88c167a59f348a44cd0166a9f791b1b83312","src/deflate/algorithm/fast.rs":"686c0a35c1baff2d842287354f919e166fe5eca1748ad46ed14d6127611bffa0","src/deflate/algorithm/huff.rs":"2ed0a098571d4e056bb4e1d8655ec8d37e6d291ba3e2d5d7c581c2486e6abbce","src/deflate/algorithm/medium.rs":"6b3b3e99ad870a6c35921b0abb4b10569e49bf3d5f57a8af2179c886a94e54b6","src/deflate/algorithm/mod.rs":"15f980186da0355eb363eb97e1580c3ecfb90b0cc7d58ed3c25081f13983931b","src/deflate/algorithm/quick.rs":"3a77e897d13ee1cc7681a05a47e32030eedf64091dc186aa6dc00c397b897a44","src/deflate/algorithm/rle.rs":"549427a5a8a69610afd612f89a9cbde97fe78c38c85442083b5dde10e8be4d73","src/deflate/algorithm/slow.rs":"2fa351c77604fad7d5e113ed3b90ba2abc83be0ff589a0e367d012aee5ce967b","src/deflate/algorithm/stored.rs":"c3ea25d2b7e0ace89f7d3a02887f78072ef1c8f2306a143705d7f82917014af8","src/deflate/compare256.rs":"bba6aa1dc8d19ca36ba2ea343d15c086169b43eaed613c0894bb31c1905e0d5b","src/deflate/hash_calc.rs":"bf02da0eb13aef78ad8411c07e57b8a770b6b466bdf8a916eec7c54f127bbbb7","src/deflate/longest_match.rs":"3bc61d20d5f327d3530ac84c8198e101add84fe467a31c771449ed482c877355","src/deflate/pending.rs":"84f0860b650570e824607e3ceb53dcc9fbb91a667ba110728cc9d4c995f1bb05","src/deflate/slide_hash.rs":"4d16e26919152b56cfd5bba40e5fa46ba34f967fed85e064c57bd62fcea8527b","src/deflate/test-data/fireworks.jpg":"93b986ce7d7e361f0d3840f9d531b5f40fb6ca8c14d6d74364150e255f126512","src/deflate/test-data/inflate_buf_error.dat":"254f280f8f1e8914bd12d8bcd3813e5c08083b1b46d8d643c8e2ebe109e75cb8","src/deflate/test-data/lcet10.txt":"1eb5d7bddb1c3cb68064d5b5f7f27814949674b6702564ff7025ced60795a6d9","src/deflate/test-data/paper-100k.pdf":"60f73a051b7ca35bfec44734b2eed7736cb5c0b7f728beb7b97ade6c5e44849b","src/deflate/test-data/read_buf_window_uninitialized.txt":"88dcffb0155e55464871bf98c66dd008e61ba8c49d12c9efd103c5d081255c48","src/deflate/test-data/zlib-ng/CVE-2018-25032/default.txt":"d7f8278db331c47bd1208bf41e7903cbddee4f7b47c666c40afdd3c96237752e","src/deflate/test-data/zlib-ng/CVE-2018-25032/fixed.txt":"3b27a98edd2f3f580033f9add11d3469d7808c969a1128ee00c18ac7a12cef57","src/deflate/test-data/zlib-ng/GH-382/defneg3.dat":"b22bef6b7392401c9e7b079402c4a4074053d7a914d050400e37fd7af6fe26d5","src/deflate/trees_tbl.rs":"503c65c7648405619a95dc9f5a52ecd558e439e870c116f61ef94128c6a4c52e","src/deflate/window.rs":"6b9680a0250fd950118d56f50ced6cc174487f5f1c6f05652b39df65557ab059","src/inflate.rs":"cdd1ecc5a6eb3a277281723c9938cddb325b467b719eada8670344af1bdccbf9","src/inflate/bitreader.rs":"1161043209b7949ccf7700b7187bc90370003dd0872bbf3bd344f11db40e31bc","src/inflate/inffixed_tbl.rs":"eb1ed1927ca07b61fe30ae8461ce62e7da28c595416e687a26db57c8eac8f4a1","src/inflate/inftrees.rs":"44efb568c9cc2dbbc6c51e50f3cc38d6c8e896b93936f47b3879396fc814abfe","src/inflate/window.rs":"8b175bdba8c7f7cd346a4ab408f0218c84ae177f32f2ac581872064269677423","src/lib.rs":"61d5837f5695f81ca78dfc5e2f8afe3f40086a5a50b555f76ebe10fe387fdcf9","src/read_buf.rs":"33d03bb0a8250393879e1b9ff4835bfe405b5941a88c809a2f11d461b897ab38"},"package":null} \ No newline at end of file diff --git a/third_party/rust/zlib-rs/Cargo.toml b/third_party/rust/zlib-rs/Cargo.toml new file mode 100644 index 000000000000..464511e4a1d7 --- /dev/null +++ b/third_party/rust/zlib-rs/Cargo.toml @@ -0,0 +1,63 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g., crates.io) dependencies. +# +# If you are reading this file be aware that the original Cargo.toml +# will likely look very different (and much more reasonable). +# See Cargo.toml.orig for the original contents. + +[package] +edition = "2021" +rust-version = "1.75" +name = "zlib-rs" +version = "0.2.1" +publish = true +description = "A memory-safe zlib implementation written in rust" +homepage = "https://github.com/memorysafety/zlib-rs" +readme = "README.md" +license = "Zlib" +repository = "https://github.com/memorysafety/zlib-rs" + +[dependencies.arbitrary] +version = "1.0" +features = ["derive"] +optional = true + +[dependencies.libz-sys] +version = "1.1.12" +features = ["zlib-ng"] +optional = true +default-features = false + +[dependencies.quickcheck] +version = "1.0.3" +features = [] +optional = true +default-features = false + +[dev-dependencies] +crc32fast = "1.3.2" +libloading = "0.8.1" +libz-ng-sys = "1.1.12" + +[dev-dependencies.dynamic-libz-sys] +path = "../dynamic-libz-sys" + +[dev-dependencies.quickcheck] +version = "1.0.3" +features = [] +default-features = false + +[features] +__internal-fuzz = ["arbitrary"] +__internal-test = ["quickcheck"] +c-allocator = [] +default = [ + "std", + "c-allocator", +] +rust-allocator = [] +std = ["rust-allocator"] diff --git a/third_party/rust/zlib-rs/LICENSE b/third_party/rust/zlib-rs/LICENSE new file mode 100644 index 000000000000..8079b948a62e --- /dev/null +++ b/third_party/rust/zlib-rs/LICENSE @@ -0,0 +1,19 @@ +(C) 2024 Internet Security Research Group + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any damages +arising from the use of this software. + +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it +freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + +2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + +3. This notice may not be removed or altered from any source distribution. diff --git a/third_party/rust/zlib-rs/README.md b/third_party/rust/zlib-rs/README.md new file mode 100644 index 000000000000..7710c6d5c1d6 --- /dev/null +++ b/third_party/rust/zlib-rs/README.md @@ -0,0 +1,6 @@ +# âš ï¸ UNSTABLEâš ï¸ +_the public interface of this crate is unstable!_ + +A pure-rust implementation of [zlib](https://www.zlib.net/manual.html). + +For a [zlib](https://www.zlib.net/manual.html) -compatible rust api of this crate, see [`libz-rs-sys`](https://crates.io/crates/libz-rs-sys). For a more high-level interface, use [`flate2`](https://crates.io/crates/flate2). diff --git a/third_party/rust/zlib-rs/src/adler32.rs b/third_party/rust/zlib-rs/src/adler32.rs new file mode 100644 index 000000000000..71b34eaf8b67 --- /dev/null +++ b/third_party/rust/zlib-rs/src/adler32.rs @@ -0,0 +1,133 @@ +use core::mem::MaybeUninit; + +#[cfg(target_arch = "x86_64")] +mod avx2; +mod generic; +#[cfg(target_arch = "aarch64")] +mod neon; + +pub fn adler32(start_checksum: u32, data: &[u8]) -> u32 { + #[cfg(all(target_arch = "x86_64", feature = "std"))] + if std::is_x86_feature_detected!("avx2") { + return avx2::adler32_avx2(start_checksum, data); + } + + #[cfg(all(target_arch = "aarch64", feature = "std"))] + if std::arch::is_aarch64_feature_detected!("neon") { + return self::neon::adler32_neon(start_checksum, data); + } + + generic::adler32_rust(start_checksum, data) +} + +pub fn adler32_fold_copy(start_checksum: u32, dst: &mut [MaybeUninit], src: &[u8]) -> u32 { + debug_assert!(dst.len() >= src.len(), "{} < {}", dst.len(), src.len()); + + #[cfg(all(target_arch = "x86_64", feature = "std"))] + if std::is_x86_feature_detected!("avx2") { + return avx2::adler32_fold_copy_avx2(start_checksum, dst, src); + } + + let adler = adler32(start_checksum, src); + dst[..src.len()].copy_from_slice(slice_to_uninit(src)); + adler +} + +pub fn adler32_combine(adler1: u32, adler2: u32, len2: u64) -> u32 { + const BASE: u64 = self::BASE as u64; + + let rem = len2 % BASE; + + let adler1 = adler1 as u64; + let adler2 = adler2 as u64; + + /* the derivation of this formula is left as an exercise for the reader */ + let mut sum1 = adler1 & 0xffff; + let mut sum2 = rem * sum1; + sum2 %= BASE; + sum1 += (adler2 & 0xffff) + BASE - 1; + sum2 += ((adler1 >> 16) & 0xffff) + ((adler2 >> 16) & 0xffff) + BASE - rem; + + if sum1 >= BASE { + sum1 -= BASE; + } + if sum1 >= BASE { + sum1 -= BASE; + } + if sum2 >= (BASE << 1) { + sum2 -= BASE << 1; + } + if sum2 >= BASE { + sum2 -= BASE; + } + + (sum1 | (sum2 << 16)) as u32 +} + +// when stable, use MaybeUninit::write_slice +fn slice_to_uninit(slice: &[u8]) -> &[MaybeUninit] { + // safety: &[T] and &[MaybeUninit] have the same layout + unsafe { &*(slice as *const [u8] as *const [MaybeUninit]) } +} + +// inefficient but correct, useful for testing +#[cfg(test)] +fn naive_adler32(start_checksum: u32, data: &[u8]) -> u32 { + const MOD_ADLER: u32 = 65521; // Largest prime smaller than 2^16 + + let mut a = start_checksum & 0xFFFF; + let mut b = (start_checksum >> 16) & 0xFFFF; + + for &byte in data { + a = (a + byte as u32) % MOD_ADLER; + b = (b + a) % MOD_ADLER; + } + + (b << 16) | a +} + +const BASE: u32 = 65521; /* largest prime smaller than 65536 */ +const NMAX: u32 = 5552; + +#[cfg(test)] +mod test { + use super::*; + + #[test] + fn naive_is_fancy_small_inputs() { + for i in 0..128 { + let v = (0u8..i).collect::>(); + assert_eq!(naive_adler32(1, &v), generic::adler32_rust(1, &v)); + } + } + + #[test] + fn test_adler32_combine() { + ::quickcheck::quickcheck(test as fn(_) -> _); + + fn test(data: Vec) -> bool { + let Some(buf_len) = data.first().copied() else { + return true; + }; + + let buf_size = Ord::max(buf_len, 1) as usize; + + let mut adler1 = 1; + let mut adler2 = 1; + + for chunk in data.chunks(buf_size) { + adler1 = adler32(adler1, chunk); + } + + adler2 = adler32(adler2, &data); + + assert_eq!(adler1, adler2); + + let combine1 = adler32_combine(adler1, adler2, data.len() as _); + let combine2 = adler32_combine(adler1, adler1, data.len() as _); + assert_eq!(combine1, combine2); + + true + } + } +} diff --git a/third_party/rust/zlib-rs/src/adler32/avx2.rs b/third_party/rust/zlib-rs/src/adler32/avx2.rs new file mode 100644 index 000000000000..5d2f934e0a82 --- /dev/null +++ b/third_party/rust/zlib-rs/src/adler32/avx2.rs @@ -0,0 +1,258 @@ +use core::{ + arch::x86_64::{ + __m256i, _mm256_add_epi32, _mm256_castsi256_si128, _mm256_extracti128_si256, + _mm256_madd_epi16, _mm256_maddubs_epi16, _mm256_permutevar8x32_epi32, _mm256_sad_epu8, + _mm256_slli_epi32, _mm256_storeu_si256, _mm256_zextsi128_si256, _mm_add_epi32, + _mm_cvtsi128_si32, _mm_cvtsi32_si128, _mm_shuffle_epi32, _mm_unpackhi_epi64, + }, + mem::MaybeUninit, +}; + +use crate::adler32::{ + generic::{adler32_copy_len_16, adler32_len_16, adler32_len_64}, + BASE, NMAX, +}; + +const fn __m256i_literal(bytes: [u8; 32]) -> __m256i { + unsafe { core::mem::transmute(bytes) } +} + +const DOT2V: __m256i = __m256i_literal([ + 32, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, + 8, 7, 6, 5, 4, 3, 2, 1, +]); + +const DOT3V: __m256i = __m256i_literal([ + 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, +]); + +const ZERO: __m256i = __m256i_literal([0; 32]); + +// 32 bit horizontal sum, adapted from Agner Fog's vector library. +#[target_feature(enable = "avx2")] +unsafe fn hsum256(x: __m256i) -> u32 { + unsafe { + let sum1 = _mm_add_epi32(_mm256_extracti128_si256(x, 1), _mm256_castsi256_si128(x)); + let sum2 = _mm_add_epi32(sum1, _mm_unpackhi_epi64(sum1, sum1)); + let sum3 = _mm_add_epi32(sum2, _mm_shuffle_epi32(sum2, 1)); + _mm_cvtsi128_si32(sum3) as u32 + } +} + +#[target_feature(enable = "avx2")] +unsafe fn partial_hsum256(x: __m256i) -> u32 { + const PERM_VEC: __m256i = __m256i_literal([ + 0, 0, 0, 0, // + 2, 0, 0, 0, // + 4, 0, 0, 0, // + 6, 0, 0, 0, // + 1, 0, 0, 0, // + 1, 0, 0, 0, // + 1, 0, 0, 0, // + 1, 0, 0, 0, // + ]); + + unsafe { + let non_zero = _mm256_permutevar8x32_epi32(x, PERM_VEC); + let non_zero_sse = _mm256_castsi256_si128(non_zero); + let sum2 = _mm_add_epi32(non_zero_sse, _mm_unpackhi_epi64(non_zero_sse, non_zero_sse)); + let sum3 = _mm_add_epi32(sum2, _mm_shuffle_epi32(sum2, 1)); + _mm_cvtsi128_si32(sum3) as u32 + } +} + +pub fn adler32_avx2(adler: u32, src: &[u8]) -> u32 { + assert!(std::is_x86_feature_detected!("avx2")); + unsafe { adler32_avx2_help::(adler, &mut [], src) } +} + +pub fn adler32_fold_copy_avx2(adler: u32, dst: &mut [MaybeUninit], src: &[u8]) -> u32 { + assert!(std::is_x86_feature_detected!("avx2")); + unsafe { adler32_avx2_help::(adler, dst, src) } +} + +#[target_feature(enable = "avx2")] +unsafe fn adler32_avx2_help( + adler: u32, + mut dst: &mut [MaybeUninit], + src: &[u8], +) -> u32 { + if src.is_empty() { + return adler; + } + + let (before, middle, after) = unsafe { src.align_to::<__m256i>() }; + + let mut adler1 = (adler >> 16) & 0xffff; + let mut adler0 = adler & 0xffff; + + let adler = if before.len() < 16 { + if COPY { + let adler = adler32_copy_len_16(adler0, dst, before, adler1); + dst = &mut dst[before.len()..]; + adler + } else { + adler32_len_16(adler0, before, adler1) + } + } else if before.len() < 32 { + if COPY { + let adler = adler32_copy_len_16(adler0, dst, before, adler1); + dst = &mut dst[before.len()..]; + adler + } else { + adler32_len_64(adler0, before, adler1) + } + } else { + adler + }; + + adler1 = (adler >> 16) & 0xffff; + adler0 = adler & 0xffff; + + // use largest step possible (without causing overflow) + for chunk in middle.chunks(NMAX as usize / 32) { + (adler0, adler1) = unsafe { helper_32_bytes::(adler0, adler1, dst, chunk) }; + if COPY { + dst = &mut dst[32 * chunk.len()..]; + } + } + + if !after.is_empty() { + if after.len() < 16 { + if COPY { + return adler32_copy_len_16(adler0, dst, after, adler1); + } else { + return adler32_len_16(adler0, after, adler1); + } + } else if after.len() < 32 { + if COPY { + return adler32_copy_len_16(adler0, dst, after, adler1); + } else { + return adler32_len_64(adler0, after, adler1); + } + } else { + unreachable!() + } + } + + adler0 | (adler1 << 16) +} + +#[target_feature(enable = "avx2")] +unsafe fn helper_32_bytes( + mut adler0: u32, + mut adler1: u32, + dst: &mut [MaybeUninit], + src: &[__m256i], +) -> (u32, u32) { + let mut vs1 = _mm256_zextsi128_si256(_mm_cvtsi32_si128(adler0 as i32)); + let mut vs2 = _mm256_zextsi128_si256(_mm_cvtsi32_si128(adler1 as i32)); + + let mut vs1_0 = vs1; + let mut vs3 = ZERO; + + let mut out_chunks = dst.chunks_exact_mut(32); + + for vbuf in src.iter().copied() { + if COPY { + let out_chunk = out_chunks.next().unwrap(); + _mm256_storeu_si256(out_chunk.as_mut_ptr() as *mut __m256i, vbuf); + } + + let vs1_sad = _mm256_sad_epu8(vbuf, ZERO); // Sum of abs diff, resulting in 2 x int32's + + vs1 = _mm256_add_epi32(vs1, vs1_sad); + vs3 = _mm256_add_epi32(vs3, vs1_0); + let v_short_sum2 = _mm256_maddubs_epi16(vbuf, DOT2V); // sum 32 uint8s to 16 shorts + let vsum2 = _mm256_madd_epi16(v_short_sum2, DOT3V); // sum 16 shorts to 8 uint32s + vs2 = _mm256_add_epi32(vsum2, vs2); + vs1_0 = vs1; + } + + /* Defer the multiplication with 32 to outside of the loop */ + vs3 = _mm256_slli_epi32(vs3, 5); + vs2 = _mm256_add_epi32(vs2, vs3); + + adler0 = partial_hsum256(vs1) % BASE; + adler1 = hsum256(vs2) % BASE; + + (adler0, adler1) +} + +#[cfg(test)] +#[cfg(target_feature = "avx2")] +mod test { + use super::*; + + #[test] + fn empty_input() { + let avx2 = adler32_avx2(0, &[]); + let rust = crate::adler32::generic::adler32_rust(0, &[]); + + assert_eq!(rust, avx2); + } + + quickcheck::quickcheck! { + fn adler32_avx2_is_adler32_rust(v: Vec, start: u32) -> bool { + let avx2 = adler32_avx2(start, &v); + let rust = crate::adler32::generic::adler32_rust(start, &v); + + rust == avx2 + } + } + + const INPUT: [u8; 1024] = { + let mut array = [0; 1024]; + let mut i = 0; + while i < array.len() { + array[i] = i as u8; + i += 1; + } + + array + }; + + #[test] + fn start_alignment() { + // SIMD algorithm is sensitive to alignment; + for i in 0..16 { + for start in [crate::ADLER32_INITIAL_VALUE as u32, 42] { + let avx2 = adler32_avx2(start, &INPUT[i..]); + let rust = crate::adler32::generic::adler32_rust(start, &INPUT[i..]); + + assert_eq!(avx2, rust, "offset = {i}, start = {start}"); + } + } + } + + #[test] + #[cfg_attr(miri, ignore)] + fn large_input() { + const DEFAULT: &str = + include_str!("../deflate/test-data/zlib-ng/CVE-2018-25032/default.txt"); + + let avx2 = adler32_avx2(42, DEFAULT.as_bytes()); + let rust = crate::adler32::generic::adler32_rust(42, DEFAULT.as_bytes()); + + assert_eq!(avx2, rust); + } + + // TODO: This could use `MaybeUninit::slice_assume_init` when it is stable. + unsafe fn slice_assume_init(slice: &[MaybeUninit]) -> &[u8] { + &*(slice as *const [MaybeUninit] as *const [u8]) + } + + #[test] + fn fold_copy_copies() { + let src: Vec<_> = (0..128).map(|x| x as u8).collect(); + let mut dst = [MaybeUninit::new(0); 128]; + + for (i, _) in src.iter().enumerate() { + dst.fill(MaybeUninit::new(0)); + + adler32_fold_copy_avx2(1, &mut dst[..i], &src[..i]); + + assert_eq!(&src[..i], unsafe { slice_assume_init(&dst[..i]) }) + } + } +} diff --git a/third_party/rust/zlib-rs/src/adler32/generic.rs b/third_party/rust/zlib-rs/src/adler32/generic.rs new file mode 100644 index 000000000000..2500c38f61e6 --- /dev/null +++ b/third_party/rust/zlib-rs/src/adler32/generic.rs @@ -0,0 +1,136 @@ +use core::mem::MaybeUninit; + +use super::{BASE, NMAX}; + +const UNROLL_MORE: bool = true; + +// macros for loop unrolling +macro_rules! do1 { + ($sum1:expr, $sum2:expr, $chunk:expr, $i:expr) => { + $sum1 += unsafe { *$chunk.get_unchecked($i) } as u32; + $sum2 += $sum1; + }; +} + +macro_rules! do2 { + ($sum1:expr, $sum2:expr, $chunk:expr, $i:expr) => { + do1!($sum1, $sum2, $chunk, $i); + do1!($sum1, $sum2, $chunk, $i + 1); + }; +} + +macro_rules! do4 { + ($sum1:expr, $sum2:expr, $chunk:expr, $i:expr) => { + do2!($sum1, $sum2, $chunk, $i); + do2!($sum1, $sum2, $chunk, $i + 2); + }; +} + +macro_rules! do8 { + ($sum1:expr, $sum2:expr, $chunk:expr, $i:expr) => { + do4!($sum1, $sum2, $chunk, $i); + do4!($sum1, $sum2, $chunk, $i + 4); + }; +} + +macro_rules! do16 { + ($sum1:expr, $sum2:expr, $chunk:expr) => { + do8!($sum1, $sum2, $chunk, 0); + do8!($sum1, $sum2, $chunk, 8); + }; +} + +pub fn adler32_rust(mut adler: u32, buf: &[u8]) -> u32 { + /* split Adler-32 into component sums */ + let mut sum2 = (adler >> 16) & 0xffff; + adler &= 0xffff; + + /* in case user likes doing a byte at a time, keep it fast */ + if buf.len() == 1 { + return adler32_len_1(adler, buf, sum2); + } + + /* initial Adler-32 value (deferred check for len == 1 speed) */ + if buf.is_empty() { + return adler | (sum2 << 16); + } + + /* in case short lengths are provided, keep it somewhat fast */ + if buf.len() < 16 { + return adler32_len_16(adler, buf, sum2); + } + + let mut it = buf.chunks_exact(NMAX as usize); + for big_chunk in it.by_ref() { + const N: usize = if UNROLL_MORE { 16 } else { 8 } as usize; + let it = big_chunk.chunks_exact(N); + for chunk in it { + if N == 16 { + do16!(adler, sum2, chunk); + } else { + do8!(adler, sum2, chunk, 0); + } + } + + adler %= BASE; + sum2 %= BASE; + } + + /* do remaining bytes (less than NMAX, still just one modulo) */ + return adler32_len_64(adler, it.remainder(), sum2); +} + +pub(crate) fn adler32_len_1(mut adler: u32, buf: &[u8], mut sum2: u32) -> u32 { + adler += buf[0] as u32; + adler %= BASE; + sum2 += adler; + sum2 %= BASE; + adler | (sum2 << 16) +} + +pub(crate) fn adler32_len_16(mut adler: u32, buf: &[u8], mut sum2: u32) -> u32 { + for b in buf { + adler += (*b) as u32; + sum2 += adler; + } + + adler %= BASE; + sum2 %= BASE; /* only added so many BASE's */ + /* return recombined sums */ + adler | (sum2 << 16) +} + +#[cfg_attr(not(target_arch = "x86_64"), allow(unused))] +pub(crate) fn adler32_copy_len_16( + mut adler: u32, + dst: &mut [MaybeUninit], + src: &[u8], + mut sum2: u32, +) -> u32 { + for (source, destination) in src.iter().zip(dst.iter_mut()) { + let v = *source; + *destination = MaybeUninit::new(v); + adler += v as u32; + sum2 += adler; + } + + adler %= BASE; + sum2 %= BASE; /* only added so many BASE's */ + /* return recombined sums */ + adler | (sum2 << 16) +} + +pub(crate) fn adler32_len_64(mut adler: u32, buf: &[u8], mut sum2: u32) -> u32 { + const N: usize = if UNROLL_MORE { 16 } else { 8 }; + let mut it = buf.chunks_exact(N); + for chunk in it.by_ref() { + if N == 16 { + do16!(adler, sum2, chunk); + } else { + do8!(adler, sum2, chunk, 0); + } + } + + /* Process tail (len < 16). */ + adler32_len_16(adler, it.remainder(), sum2) +} diff --git a/third_party/rust/zlib-rs/src/adler32/neon.rs b/third_party/rust/zlib-rs/src/adler32/neon.rs new file mode 100644 index 000000000000..8113ad01067b --- /dev/null +++ b/third_party/rust/zlib-rs/src/adler32/neon.rs @@ -0,0 +1,243 @@ +use core::arch::aarch64::{ + uint16x8_t, uint16x8x2_t, uint16x8x4_t, uint8x16_t, vaddq_u32, vaddw_high_u8, vaddw_u8, + vdupq_n_u16, vdupq_n_u32, vget_high_u32, vget_lane_u32, vget_low_u16, vget_low_u32, + vget_low_u8, vld1q_u8_x4, vmlal_high_u16, vmlal_u16, vpadalq_u16, vpadalq_u8, vpadd_u32, + vpaddlq_u8, vsetq_lane_u32, vshlq_n_u32, +}; + +use crate::adler32::{ + generic::{adler32_len_1, adler32_len_16}, + BASE, NMAX, +}; + +const TAPS: [uint16x8x4_t; 2] = unsafe { + core::mem::transmute::<[u16; 64], [uint16x8x4_t; 2]>([ + 64, 63, 62, 61, 60, 59, 58, 57, 56, 55, 54, 53, 52, 51, 50, 49, 48, 47, 46, 45, 44, 43, 42, + 41, 40, 39, 38, 37, 36, 35, 34, 33, 32, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, + 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, + ]) +}; + +pub fn adler32_neon(adler: u32, buf: &[u8]) -> u32 { + assert!(std::arch::is_aarch64_feature_detected!("neon")); + unsafe { adler32_neon_internal(adler, buf) } +} + +#[target_feature(enable = "neon")] +unsafe fn adler32_neon_internal(mut adler: u32, buf: &[u8]) -> u32 { + /* split Adler-32 into component sums */ + let sum2 = (adler >> 16) & 0xffff; + adler &= 0xffff; + + /* in case user likes doing a byte at a time, keep it fast */ + if buf.len() == 1 { + return adler32_len_1(adler, buf, sum2); + } + + /* initial Adler-32 value (deferred check for len == 1 speed) */ + if buf.is_empty() { + return adler | (sum2 << 16); + } + + /* in case short lengths are provided, keep it somewhat fast */ + if buf.len() < 16 { + return adler32_len_16(adler, buf, sum2); + } + + // Split Adler-32 into component sums, it can be supplied by the caller sites (e.g. in a PNG file). + let mut pair = (adler, sum2); + + // If memory is not SIMD aligned, do scalar sums to an aligned + // offset, provided that doing so doesn't completely eliminate + // SIMD operation. Aligned loads are still faster on ARM, even + // though there's no explicit aligned load instruction + const _: () = assert!(core::mem::align_of::() == 16); + let (before, middle, after) = unsafe { buf.align_to::() }; + + pair = handle_tail(pair, before); + + for chunk in middle.chunks(NMAX as usize / core::mem::size_of::()) { + pair = unsafe { accum32(pair, chunk) }; + pair.0 %= BASE; + pair.1 %= BASE; + } + + if !after.is_empty() { + pair = handle_tail(pair, after); + pair.0 %= BASE; + pair.1 %= BASE; + } + + // D = B * 65536 + A, see: https://en.wikipedia.org/wiki/Adler-32. + (pair.1 << 16) | pair.0 +} + +fn handle_tail(mut pair: (u32, u32), buf: &[u8]) -> (u32, u32) { + for x in buf { + pair.0 += *x as u32; + pair.1 += pair.0; + } + + pair +} + +#[target_feature(enable = "neon")] +unsafe fn accum32(s: (u32, u32), buf: &[uint8x16_t]) -> (u32, u32) { + let mut adacc = vdupq_n_u32(0); + let mut s2acc = vdupq_n_u32(0); + + adacc = vsetq_lane_u32(s.0, adacc, 0); + s2acc = vsetq_lane_u32(s.1, s2acc, 0); + + let mut s3acc = vdupq_n_u32(0); + let mut adacc_prev = adacc; + + let mut s2_0 = vdupq_n_u16(0); + let mut s2_1 = vdupq_n_u16(0); + let mut s2_2 = vdupq_n_u16(0); + let mut s2_3 = vdupq_n_u16(0); + + let mut s2_4 = vdupq_n_u16(0); + let mut s2_5 = vdupq_n_u16(0); + let mut s2_6 = vdupq_n_u16(0); + let mut s2_7 = vdupq_n_u16(0); + + let mut it = buf.chunks_exact(4); + + for chunk in &mut it { + let d0_d3 = vld1q_u8_x4(chunk.as_ptr() as *const u8); + + // Unfortunately it doesn't look like there's a direct sum 8 bit to 32 + // bit instruction, we'll have to make due summing to 16 bits first + let hsum = uint16x8x2_t(vpaddlq_u8(d0_d3.0), vpaddlq_u8(d0_d3.1)); + + let hsum_fold = uint16x8x2_t(vpadalq_u8(hsum.0, d0_d3.2), vpadalq_u8(hsum.1, d0_d3.3)); + + adacc = vpadalq_u16(adacc, hsum_fold.0); + s3acc = vaddq_u32(s3acc, adacc_prev); + adacc = vpadalq_u16(adacc, hsum_fold.1); + + // If we do straight widening additions to the 16 bit values, we don't incur + // the usual penalties of a pairwise add. We can defer the multiplications + // until the very end. These will not overflow because we are incurring at + // most 408 loop iterations (NMAX / 64), and a given lane is only going to be + // summed into once. This means for the maximum input size, the largest value + // we will see is 255 * 102 = 26010, safely under uint16 max + s2_0 = vaddw_u8(s2_0, vget_low_u8(d0_d3.0)); + s2_1 = vaddw_high_u8(s2_1, d0_d3.0); + s2_2 = vaddw_u8(s2_2, vget_low_u8(d0_d3.1)); + s2_3 = vaddw_high_u8(s2_3, d0_d3.1); + s2_4 = vaddw_u8(s2_4, vget_low_u8(d0_d3.2)); + s2_5 = vaddw_high_u8(s2_5, d0_d3.2); + s2_6 = vaddw_u8(s2_6, vget_low_u8(d0_d3.3)); + s2_7 = vaddw_high_u8(s2_7, d0_d3.3); + + adacc_prev = adacc; + } + + s3acc = vshlq_n_u32(s3acc, 6); + + let remainder = it.remainder(); + + if !remainder.is_empty() { + let mut s3acc_0 = vdupq_n_u32(0); + for d0 in remainder.iter().copied() { + let adler: uint16x8_t = vpaddlq_u8(d0); + s2_6 = vaddw_u8(s2_6, vget_low_u8(d0)); + s2_7 = vaddw_high_u8(s2_7, d0); + adacc = vpadalq_u16(adacc, adler); + s3acc_0 = vaddq_u32(s3acc_0, adacc_prev); + adacc_prev = adacc; + } + + s3acc_0 = vshlq_n_u32(s3acc_0, 4); + s3acc = vaddq_u32(s3acc_0, s3acc); + } + + let t0_t3 = TAPS[0]; + let t4_t7 = TAPS[1]; + + let mut s2acc_0 = vdupq_n_u32(0); + let mut s2acc_1 = vdupq_n_u32(0); + let mut s2acc_2 = vdupq_n_u32(0); + + s2acc = vmlal_high_u16(s2acc, t0_t3.0, s2_0); + s2acc_0 = vmlal_u16(s2acc_0, vget_low_u16(t0_t3.0), vget_low_u16(s2_0)); + s2acc_1 = vmlal_high_u16(s2acc_1, t0_t3.1, s2_1); + s2acc_2 = vmlal_u16(s2acc_2, vget_low_u16(t0_t3.1), vget_low_u16(s2_1)); + + s2acc = vmlal_high_u16(s2acc, t0_t3.2, s2_2); + s2acc_0 = vmlal_u16(s2acc_0, vget_low_u16(t0_t3.2), vget_low_u16(s2_2)); + s2acc_1 = vmlal_high_u16(s2acc_1, t0_t3.3, s2_3); + s2acc_2 = vmlal_u16(s2acc_2, vget_low_u16(t0_t3.3), vget_low_u16(s2_3)); + + s2acc = vmlal_high_u16(s2acc, t4_t7.0, s2_4); + s2acc_0 = vmlal_u16(s2acc_0, vget_low_u16(t4_t7.0), vget_low_u16(s2_4)); + s2acc_1 = vmlal_high_u16(s2acc_1, t4_t7.1, s2_5); + s2acc_2 = vmlal_u16(s2acc_2, vget_low_u16(t4_t7.1), vget_low_u16(s2_5)); + + s2acc = vmlal_high_u16(s2acc, t4_t7.2, s2_6); + s2acc_0 = vmlal_u16(s2acc_0, vget_low_u16(t4_t7.2), vget_low_u16(s2_6)); + s2acc_1 = vmlal_high_u16(s2acc_1, t4_t7.3, s2_7); + s2acc_2 = vmlal_u16(s2acc_2, vget_low_u16(t4_t7.3), vget_low_u16(s2_7)); + + s2acc = vaddq_u32(s2acc_0, s2acc); + s2acc_2 = vaddq_u32(s2acc_1, s2acc_2); + s2acc = vaddq_u32(s2acc, s2acc_2); + + let s2acc = vaddq_u32(s2acc, s3acc); + let adacc2 = vpadd_u32(vget_low_u32(adacc), vget_high_u32(adacc)); + let s2acc2 = vpadd_u32(vget_low_u32(s2acc), vget_high_u32(s2acc)); + let as_ = vpadd_u32(adacc2, s2acc2); + + (vget_lane_u32(as_, 0), vget_lane_u32(as_, 1)) +} + +#[cfg(test)] +mod tests { + use super::*; + + quickcheck::quickcheck! { + fn adler32_neon_is_adler32_rust(v: Vec, start: u32) -> bool { + let neon = adler32_neon(start, &v); + let rust = crate::adler32::generic::adler32_rust(start, &v); + + rust == neon + } + } + + const INPUT: [u8; 1024] = { + let mut array = [0; 1024]; + let mut i = 0; + while i < array.len() { + array[i] = i as u8; + i += 1; + } + + array + }; + + #[test] + fn start_alignment() { + // SIMD algorithm is sensitive to alignment; + for i in 0..16 { + for start in [crate::ADLER32_INITIAL_VALUE as u32, 42] { + let neon = adler32_neon(start, &INPUT[i..]); + let rust = crate::adler32::generic::adler32_rust(start, &INPUT[i..]); + + assert_eq!(neon, rust, "offset = {i}, start = {start}"); + } + } + } + + #[test] + fn large_input() { + const DEFAULT: &str = + include_str!("../deflate/test-data/zlib-ng/CVE-2018-25032/default.txt"); + + let neon = adler32_neon(42, &DEFAULT.as_bytes()); + let rust = crate::adler32::generic::adler32_rust(42, &DEFAULT.as_bytes()); + + assert_eq!(neon, rust); + } +} diff --git a/third_party/rust/zlib-rs/src/allocate.rs b/third_party/rust/zlib-rs/src/allocate.rs new file mode 100644 index 000000000000..97defa6bd110 --- /dev/null +++ b/third_party/rust/zlib-rs/src/allocate.rs @@ -0,0 +1,357 @@ +use core::ffi::c_int; +use core::{ + alloc::Layout, + ffi::{c_uint, c_void}, + marker::PhantomData, + mem::MaybeUninit, +}; + +#[cfg(feature = "rust-allocator")] +use alloc::alloc::GlobalAlloc; + +#[allow(non_camel_case_types)] +type size_t = usize; + +/// # Safety +/// +/// This function is safe, but must have this type signature to be used elsewhere in the library +#[cfg(unix)] +pub unsafe extern "C" fn zalloc_c(opaque: *mut c_void, items: c_uint, size: c_uint) -> *mut c_void { + let _ = opaque; + + extern "C" { + fn posix_memalign(memptr: *mut *mut c_void, align: size_t, size: size_t) -> c_int; + } + + let mut ptr = core::ptr::null_mut(); + match posix_memalign(&mut ptr, 64, items as size_t * size as size_t) { + 0 => ptr, + _ => core::ptr::null_mut(), + } +} + +/// # Safety +/// +/// This function is safe, but must have this type signature to be used elsewhere in the library +#[cfg(not(unix))] +pub unsafe extern "C" fn zalloc_c(opaque: *mut c_void, items: c_uint, size: c_uint) -> *mut c_void { + let _ = opaque; + + extern "C" { + fn malloc(size: size_t) -> *mut c_void; + } + + malloc(items as size_t * size as size_t) +} + +/// # Safety +/// +/// The `ptr` must be allocated with the allocator that is used internally by `zcfree` +pub unsafe extern "C" fn zfree_c(opaque: *mut c_void, ptr: *mut c_void) { + let _ = opaque; + + extern "C" { + fn free(p: *mut c_void); + } + + unsafe { free(ptr) } +} + +/// # Safety +/// +/// This function is safe to call. +#[cfg(feature = "rust-allocator")] +pub unsafe extern "C" fn zalloc_rust( + _opaque: *mut c_void, + count: c_uint, + size: c_uint, +) -> *mut c_void { + let align = 64; + let size = count as usize * size as usize; + + // internally, we want to align allocations to 64 bytes (in part for SIMD reasons) + let layout = Layout::from_size_align(size, align).unwrap(); + + let ptr = std::alloc::System.alloc(layout); + + ptr as *mut c_void +} + +/// # Safety +/// +/// - `ptr` must be allocated with the rust `alloc::System` allocator +/// - `opaque` is a `&usize` that represents the size of the allocation +#[cfg(feature = "rust-allocator")] +pub unsafe extern "C" fn zfree_rust(opaque: *mut c_void, ptr: *mut c_void) { + if ptr.is_null() { + return; + } + + // we can't really do much else. Deallocating with an invalid layout is UB. + debug_assert!(!opaque.is_null()); + if opaque.is_null() { + return; + } + + let size = *(opaque as *mut usize); + let align = 64; + + let layout = Layout::from_size_align(size, align); + let layout = layout.unwrap(); + + std::alloc::System.dealloc(ptr.cast(), layout); +} + +#[derive(Clone, Copy)] +#[repr(C)] +pub(crate) struct Allocator<'a> { + pub(crate) zalloc: crate::c_api::alloc_func, + pub(crate) zfree: crate::c_api::free_func, + pub(crate) opaque: crate::c_api::voidpf, + pub(crate) _marker: PhantomData<&'a ()>, +} + +impl Allocator<'static> { + #[cfg(feature = "rust-allocator")] + pub const RUST: Self = Self { + zalloc: zalloc_rust, + zfree: zfree_rust, + opaque: core::ptr::null_mut(), + _marker: PhantomData, + }; + + #[cfg(feature = "c-allocator")] + pub const C: Self = Self { + zalloc: zalloc_c, + zfree: zfree_c, + opaque: core::ptr::null_mut(), + _marker: PhantomData, + }; +} + +impl<'a> Allocator<'a> { + pub fn allocate_layout(&self, layout: Layout) -> *mut c_void { + // Special case for the Rust `alloc` backed allocator + #[cfg(feature = "rust-allocator")] + if self.zalloc == Allocator::RUST.zalloc { + let ptr = unsafe { (Allocator::RUST.zalloc)(self.opaque, layout.size() as _, 1) }; + + debug_assert_eq!(ptr as usize % layout.align(), 0); + + return ptr; + } + + // General case for c-style allocation + + // We cannot rely on the allocator giving properly aligned allocations and have to fix that ourselves. + // + // The general approach is to allocate a bit more than the layout needs, so that we can + // give the application a properly aligned address and also store the real allocation + // pointer in the allocation so that `free` can free the real allocation pointer. + // + // + // Example: The layout represents `(u32, u32)`, with an alignment of 4 bytes and a + // total size of 8 bytes. + // + // Assume that the allocator will give us address `0x07`. We need that to be a multiple + // of the alignment, so that shifts the starting position to `0x08`. Then we also need + // to store the pointer to the start of the allocation so that `free` can free that + // pointer, bumping to `0x10`. The `0x10` pointer is then the pointer that the application + // deals with. When free'ing, the original allocation pointer can be read from `0x10 - size_of::<*const c_void>()`. + // + // Of course there does need to be enough space in the allocation such that when we + // shift the start forwards, the end is still within the allocation. Hence we allocate + // `extra_space` bytes: enough for a full alignment plus a pointer. + + // we need at least + // + // - `align` extra space so that no matter what pointer we get from zalloc, we can shift the start of the + // allocation by at most `align - 1` so that `ptr as usize % align == 0 + // - `size_of::<*mut _>` extra space so that after aligning to `align`, + // there is `size_of::<*mut _>` space to store the pointer to the allocation. + // This pointer is then retrieved in `free` + let extra_space = core::mem::size_of::<*mut c_void>() + layout.align(); + + // Safety: we assume allocating works correctly in the safety assumptions on + // `DeflateStream` and `InflateStream`. + let ptr = unsafe { (self.zalloc)(self.opaque, (layout.size() + extra_space) as _, 1) }; + + if ptr.is_null() { + return ptr; + } + + // Calculate return pointer address with space enough to store original pointer + let align_diff = (ptr as usize).next_multiple_of(layout.align()) - (ptr as usize); + + // Safety: offset is smaller than 64, and we allocated 64 extra bytes in the allocation + let mut return_ptr = unsafe { ptr.cast::().add(align_diff) }; + + // if there is not enough space to store a pointer we need to make more + if align_diff < core::mem::size_of::<*mut c_void>() { + // # Safety + // + // - `return_ptr` is well-aligned, therefore `return_ptr + align` is also well-aligned + // - we reserve `size_of::<*mut _> + align` extra space in the allocation, so + // `ptr + align_diff + align` is still valid for (at least) `layout.size` bytes + let offset = Ord::max(core::mem::size_of::<*mut c_void>(), layout.align()); + return_ptr = unsafe { return_ptr.add(offset) }; + } + + // Store the original pointer for free() + // + // Safety: `align >= size_of::<*mut _>`, so there is now space for a pointer before `return_ptr` + // in the allocation + unsafe { + let original_ptr = return_ptr.sub(core::mem::size_of::<*mut c_void>()); + core::ptr::write_unaligned(original_ptr.cast::<*mut c_void>(), ptr); + }; + + // Return properly aligned pointer in allocation + let ptr = return_ptr.cast::(); + + debug_assert_eq!(ptr as usize % layout.align(), 0); + + ptr + } + + pub fn allocate(&self) -> Option<&'a mut MaybeUninit> { + let ptr = self.allocate_layout(Layout::new::()); + + if ptr.is_null() { + None + } else { + Some(unsafe { &mut *(ptr as *mut MaybeUninit) }) + } + } + + pub fn allocate_slice(&self, len: usize) -> Option<&'a mut [MaybeUninit]> { + let ptr = self.allocate_layout(Layout::array::(len).ok()?); + + if ptr.is_null() { + None + } else { + Some(unsafe { core::slice::from_raw_parts_mut(ptr.cast(), len) }) + } + } + + /// # Panics + /// + /// - when `len` is 0 + /// + /// # Safety + /// + /// - `ptr` must be allocated with this allocator + /// - `len` must be the number of `T`s that are in this allocation + #[allow(unused)] // Rust needs `len` for deallocation + pub unsafe fn deallocate(&self, ptr: *mut T, len: usize) { + if !ptr.is_null() { + // Special case for the Rust `alloc` backed allocator + #[cfg(feature = "rust-allocator")] + if self.zfree == Allocator::RUST.zfree { + assert_ne!(len, 0, "invalid size for {:?}", ptr); + let mut size = core::mem::size_of::() * len; + return (Allocator::RUST.zfree)(&mut size as *mut usize as *mut c_void, ptr.cast()); + } + + // General case for c-style allocation + let original_ptr = (ptr as *mut u8).sub(core::mem::size_of::<*const c_void>()); + let free_ptr = core::ptr::read_unaligned(original_ptr as *mut *mut c_void); + + (self.zfree)(self.opaque, free_ptr) + } + } +} + +#[cfg(test)] +mod tests { + use core::sync::atomic::{AtomicPtr, Ordering}; + use std::sync::Mutex; + + use super::*; + + static PTR: AtomicPtr = AtomicPtr::new(core::ptr::null_mut()); + static MUTEX: Mutex<()> = Mutex::new(()); + + unsafe extern "C" fn unaligned_alloc( + _opaque: *mut c_void, + _items: c_uint, + _size: c_uint, + ) -> *mut c_void { + PTR.load(Ordering::Relaxed) + } + + unsafe extern "C" fn unaligned_free(_opaque: *mut c_void, ptr: *mut c_void) { + let expected = PTR.load(Ordering::Relaxed); + assert_eq!(expected, ptr) + } + + fn unaligned_allocator_help() { + let mut buf = [0u8; 1024]; + + // we don't want anyone else messing with the PTR static + let _guard = MUTEX.lock().unwrap(); + + for i in 0..64 { + let ptr = unsafe { buf.as_mut_ptr().add(i).cast() }; + PTR.store(ptr, Ordering::Relaxed); + + let allocator = Allocator { + zalloc: unaligned_alloc, + zfree: unaligned_free, + opaque: core::ptr::null_mut(), + _marker: PhantomData, + }; + + let ptr = allocator.allocate::().unwrap(); + assert_eq!(ptr.as_ptr() as usize % core::mem::align_of::(), 0); + unsafe { allocator.deallocate(ptr, 1) } + + let ptr = allocator.allocate_slice::(10).unwrap(); + assert_eq!(ptr.as_ptr() as usize % core::mem::align_of::(), 0); + unsafe { allocator.deallocate(ptr.as_mut_ptr(), 10) } + } + } + + #[test] + fn unaligned_allocator_0() { + unaligned_allocator_help::<()>() + } + + #[test] + fn unaligned_allocator_1() { + unaligned_allocator_help::() + } + + #[test] + fn unaligned_allocator_2() { + unaligned_allocator_help::() + } + #[test] + fn unaligned_allocator_4() { + unaligned_allocator_help::() + } + #[test] + fn unaligned_allocator_8() { + unaligned_allocator_help::() + } + #[test] + fn unaligned_allocator_16() { + unaligned_allocator_help::() + } + + #[test] + fn unaligned_allocator_32() { + #[repr(C, align(32))] + struct Align32(u8); + + unaligned_allocator_help::() + } + + #[test] + fn unaligned_allocator_64() { + #[repr(C, align(64))] + struct Align64(u8); + + unaligned_allocator_help::() + } +} diff --git a/third_party/rust/zlib-rs/src/c_api.rs b/third_party/rust/zlib-rs/src/c_api.rs new file mode 100644 index 000000000000..d30ee3803e29 --- /dev/null +++ b/third_party/rust/zlib-rs/src/c_api.rs @@ -0,0 +1,228 @@ +#![allow(non_camel_case_types)] +#![allow(non_snake_case)] + +use core::ffi::{c_char, c_int, c_uchar, c_uint, c_ulong, c_void}; + +use crate::allocate::Allocator; + +pub type alloc_func = unsafe extern "C" fn(voidpf, uInt, uInt) -> voidpf; +pub type free_func = unsafe extern "C" fn(voidpf, voidpf); + +pub type Bytef = u8; +pub type in_func = unsafe extern "C" fn(*mut c_void, *mut *const c_uchar) -> c_uint; +pub type out_func = unsafe extern "C" fn(*mut c_void, *mut c_uchar, c_uint) -> c_int; +pub type uInt = c_uint; +pub type uLong = c_ulong; +pub type uLongf = c_ulong; +pub type voidp = *mut c_void; +pub type voidpc = *const c_void; +pub type voidpf = *mut c_void; + +#[repr(C)] +#[derive(Copy, Clone)] +pub struct z_stream { + pub next_in: *const Bytef, + pub avail_in: uInt, + pub total_in: z_size, + pub next_out: *mut Bytef, + pub avail_out: uInt, + pub total_out: z_size, + pub msg: *mut c_char, + pub state: *mut internal_state, + pub zalloc: Option, + pub zfree: Option, + pub opaque: voidpf, + pub data_type: c_int, + pub adler: z_checksum, + pub reserved: uLong, +} +pub type z_streamp = *mut z_stream; + +impl Default for z_stream { + fn default() -> Self { + let mut stream = Self { + next_in: core::ptr::null_mut(), + avail_in: 0, + total_in: 0, + next_out: core::ptr::null_mut(), + avail_out: 0, + total_out: 0, + msg: core::ptr::null_mut(), + state: core::ptr::null_mut(), + zalloc: None, + zfree: None, + opaque: core::ptr::null_mut(), + data_type: 0, + adler: 0, + reserved: 0, + }; + + #[cfg(feature = "rust-allocator")] + if stream.zalloc.is_none() || stream.zfree.is_none() { + stream.configure_default_rust_allocator() + } + + #[cfg(feature = "c-allocator")] + if stream.zalloc.is_none() || stream.zfree.is_none() { + stream.configure_default_c_allocator() + } + + stream + } +} + +impl z_stream { + fn configure_allocator(&mut self, alloc: Allocator) { + self.zalloc = Some(alloc.zalloc); + self.zfree = Some(alloc.zfree); + self.opaque = alloc.opaque; + } + + #[cfg(feature = "rust-allocator")] + pub fn configure_default_rust_allocator(&mut self) { + self.configure_allocator(Allocator::RUST) + } + + #[cfg(feature = "c-allocator")] + pub fn configure_default_c_allocator(&mut self) { + self.configure_allocator(Allocator::C) + } +} + +// // zlib stores Adler-32 and CRC-32 checksums in unsigned long; zlib-ng uses uint32_t. +pub(crate) type z_size = c_ulong; +pub(crate) type z_checksum = c_ulong; + +// opaque to the user +pub enum internal_state {} + +pub const Z_NO_FLUSH: c_int = 0; +pub const Z_PARTIAL_FLUSH: c_int = 1; +pub const Z_SYNC_FLUSH: c_int = 2; +pub const Z_FULL_FLUSH: c_int = 3; +pub const Z_FINISH: c_int = 4; +pub const Z_BLOCK: c_int = 5; +pub const Z_TREES: c_int = 6; + +pub const Z_OK: c_int = 0; +pub const Z_STREAM_END: c_int = 1; +pub const Z_NEED_DICT: c_int = 2; +pub const Z_ERRNO: c_int = -1; +pub const Z_STREAM_ERROR: c_int = -2; +pub const Z_DATA_ERROR: c_int = -3; +pub const Z_MEM_ERROR: c_int = -4; +pub const Z_BUF_ERROR: c_int = -5; +pub const Z_VERSION_ERROR: c_int = -6; + +pub const Z_NO_COMPRESSION: c_int = 0; +pub const Z_BEST_SPEED: c_int = 1; +pub const Z_BEST_COMPRESSION: c_int = 9; +pub const Z_DEFAULT_COMPRESSION: c_int = -1; + +pub const Z_DEFLATED: c_int = 8; + +pub const Z_BINARY: c_int = 0; +pub const Z_TEXT: c_int = 1; +pub const Z_ASCII: c_int = Z_TEXT; /* for compatibility with 1.2.2 and earlier */ +pub const Z_UNKNOWN: c_int = 2; + +pub const Z_FILTERED: c_int = 1; +pub const Z_HUFFMAN_ONLY: c_int = 2; +pub const Z_RLE: c_int = 3; +pub const Z_FIXED: c_int = 4; +pub const Z_DEFAULT_STRATEGY: c_int = 0; + +pub type gz_headerp = *mut gz_header; + +/// gzip header information passed to and from zlib routines. +/// See RFC 1952 for more details on the meanings of these fields. +#[derive(Debug)] +#[repr(C)] +pub struct gz_header { + /// true if compressed data believed to be text + pub text: i32, + /// modification time + pub time: c_ulong, + /// extra flags (not used when writing a gzip file) + pub xflags: i32, + /// operating system + pub os: i32, + /// pointer to extra field or NULL if none + pub extra: *mut u8, + /// extra field length (valid if extra != NULL) + pub extra_len: u32, + /// space at extra (only when reading header) + pub extra_max: u32, + /// pointer to zero-terminated file name or NULL + pub name: *mut u8, + /// space at name (only when reading header) + pub name_max: u32, + /// pointer to zero-terminated comment or NULL + pub comment: *mut u8, + /// space at comment (only when reading header) + pub comm_max: u32, + /// true if there was or will be a header crc + pub hcrc: i32, + /// true when done reading gzip header (not used when writing a gzip file) + pub done: i32, +} + +impl Default for gz_header { + fn default() -> Self { + Self { + text: 0, + time: 0, + xflags: 0, + os: 0, + extra: core::ptr::null_mut(), + extra_len: 0, + extra_max: 0, + name: core::ptr::null_mut(), + name_max: 0, + comment: core::ptr::null_mut(), + comm_max: 0, + hcrc: 0, + done: 0, + } + } +} + +impl gz_header { + // based on the spec https://www.ietf.org/rfc/rfc1952.txt + // + // 0 - FAT filesystem (MS-DOS, OS/2, NT/Win32) + // 1 - Amiga + // 2 - VMS (or OpenVMS) + // 3 - Unix + // 4 - VM/CMS + // 5 - Atari TOS + // 6 - HPFS filesystem (OS/2, NT) + // 7 - Macintosh + // 8 - Z-System + // 9 - CP/M + // 10 - TOPS-20 + // 11 - NTFS filesystem (NT) + // 12 - QDOS + // 13 - Acorn RISCOS + // 255 - unknown + #[allow(clippy::if_same_then_else)] + pub(crate) const OS_CODE: u8 = { + if cfg!(windows) { + 10 + } else if cfg!(target_os = "macos") { + 19 + } else if cfg!(unix) { + 3 + } else { + 3 // assume unix + } + }; + + pub(crate) fn flags(&self) -> u8 { + (if self.text > 0 { 1 } else { 0 }) + + (if self.hcrc > 0 { 2 } else { 0 }) + + (if self.extra.is_null() { 0 } else { 4 }) + + (if self.name.is_null() { 0 } else { 8 }) + + (if self.comment.is_null() { 0 } else { 16 }) + } +} diff --git a/third_party/rust/zlib-rs/src/crc32.rs b/third_party/rust/zlib-rs/src/crc32.rs new file mode 100644 index 000000000000..972e0e2f6107 --- /dev/null +++ b/third_party/rust/zlib-rs/src/crc32.rs @@ -0,0 +1,259 @@ +use core::mem::MaybeUninit; + +use crate::{read_buf::ReadBuf, CRC32_INITIAL_VALUE}; + +#[cfg(target_arch = "aarch64")] +pub(crate) mod acle; +mod braid; +mod combine; +#[cfg(target_arch = "x86_64")] +mod pclmulqdq; + +pub use combine::crc32_combine; + +pub fn crc32(start: u32, buf: &[u8]) -> u32 { + /* For lens < 64, crc32_braid method is faster. The CRC32 instruction for + * these short lengths might also prove to be effective */ + if buf.len() < 64 { + return crc32_braid(start, buf); + } + + let mut crc_state = Crc32Fold::new_with_initial(start); + crc_state.fold(buf, start); + crc_state.finish() +} + +pub fn crc32_braid(start: u32, buf: &[u8]) -> u32 { + braid::crc32_braid::<5>(start, buf) +} + +#[allow(unused)] +pub fn crc32_copy(dst: &mut ReadBuf, buf: &[u8]) -> u32 { + /* For lens < 64, crc32_braid method is faster. The CRC32 instruction for + * these short lengths might also prove to be effective */ + if buf.len() < 64 { + dst.extend(buf); + return braid::crc32_braid::<5>(CRC32_INITIAL_VALUE, buf); + } + + let mut crc_state = Crc32Fold::new(); + + crc_state.fold_copy(unsafe { dst.inner_mut() }, buf); + unsafe { dst.assume_init(buf.len()) }; + dst.set_filled(buf.len()); + + crc_state.finish() +} + +#[derive(Debug, Clone, Copy)] +pub struct Crc32Fold { + #[cfg(target_arch = "x86_64")] + fold: pclmulqdq::Accumulator, + value: u32, +} + +impl Default for Crc32Fold { + fn default() -> Self { + Self::new() + } +} + +impl Crc32Fold { + pub const fn new() -> Self { + Self::new_with_initial(CRC32_INITIAL_VALUE) + } + + pub const fn new_with_initial(initial: u32) -> Self { + Self { + #[cfg(target_arch = "x86_64")] + fold: pclmulqdq::Accumulator::new(), + value: initial, + } + } + + #[cfg(all(target_arch = "x86_64", feature = "std"))] + fn is_pclmulqdq() -> bool { + std::is_x86_feature_detected!("pclmulqdq") + && std::is_x86_feature_detected!("sse2") + && std::is_x86_feature_detected!("sse4.1") + } + + pub fn fold(&mut self, src: &[u8], _start: u32) { + #[cfg(all(target_arch = "x86_64", feature = "std"))] + if Self::is_pclmulqdq() { + return self.fold.fold(src, _start); + } + + #[cfg(all(target_arch = "aarch64", feature = "std"))] + if std::arch::is_aarch64_feature_detected!("crc") { + self.value = self::acle::crc32_acle_aarch64(self.value, src); + return; + } + + // in this case the start value is ignored + self.value = braid::crc32_braid::<5>(self.value, src); + } + + pub fn fold_copy(&mut self, dst: &mut [MaybeUninit], src: &[u8]) { + #[cfg(all(target_arch = "x86_64", feature = "std"))] + if Self::is_pclmulqdq() { + return self.fold.fold_copy(dst, src); + } + + self.fold(src, 0); + dst[..src.len()].copy_from_slice(slice_to_uninit(src)); + } + + pub fn finish(self) -> u32 { + #[cfg(all(target_arch = "x86_64", feature = "std"))] + if Self::is_pclmulqdq() { + return unsafe { self.fold.finish() }; + } + + self.value + } +} + +// when stable, use MaybeUninit::write_slice +fn slice_to_uninit(slice: &[u8]) -> &[MaybeUninit] { + // safety: &[T] and &[MaybeUninit] have the same layout + unsafe { &*(slice as *const [u8] as *const [MaybeUninit]) } +} + +#[cfg(test)] +mod test { + use test::braid::crc32_braid; + + use super::*; + + const INPUT: [u8; 1024] = { + let mut array = [0; 1024]; + let mut i = 0; + while i < array.len() { + array[i] = i as u8; + i += 1; + } + + array + }; + + #[test] + fn test_crc32_fold() { + // input large enough to trigger the SIMD + let mut h = crc32fast::Hasher::new_with_initial(CRC32_INITIAL_VALUE); + h.update(&INPUT); + assert_eq!(crc32(CRC32_INITIAL_VALUE, &INPUT), h.finalize()); + } + + #[test] + fn test_crc32_fold_align() { + // SIMD algorithm is sensitive to alignment; + for i in 0..16 { + for start in [CRC32_INITIAL_VALUE, 42] { + let mut h = crc32fast::Hasher::new_with_initial(start); + h.update(&INPUT[i..]); + assert_eq!( + crc32(start, &INPUT[i..]), + h.finalize(), + "offset = {i}, start = {start}" + ); + } + } + } + + #[test] + fn test_crc32_fold_copy() { + // input large enough to trigger the SIMD + let mut h = crc32fast::Hasher::new_with_initial(CRC32_INITIAL_VALUE); + h.update(&INPUT); + let mut dst = [0; INPUT.len()]; + let mut dst = ReadBuf::new(&mut dst); + + assert_eq!(crc32_copy(&mut dst, &INPUT), h.finalize()); + + assert_eq!(INPUT, dst.filled()); + } + + quickcheck::quickcheck! { + fn crc_fold_is_crc32fast(v: Vec, start: u32) -> bool { + let mut h = crc32fast::Hasher::new_with_initial(start); + h.update(&v); + + let a = crc32(start, &v) ; + let b = h.finalize(); + + a == b + } + + fn crc_fold_copy_is_crc32fast(v: Vec) -> bool { + let mut h = crc32fast::Hasher::new_with_initial(CRC32_INITIAL_VALUE); + h.update(&v); + + let mut dst = vec![0; v.len()]; + let mut dst = ReadBuf::new(&mut dst); + + let a = crc32_copy(&mut dst, &v) ; + let b = h.finalize(); + + assert_eq!(a,b); + + v == dst.filled() + } + } + + #[test] + fn chunked() { + const INPUT: &[&[u8]] = &[ + &[116], + &[111, 107, 105, 111, 44, 32, 97, 115], + &[121, 110, 99, 45, 115, 116, 100, 44], + &[32, 97, 110, 100, 32, 115, 109, 111], + &[108, 46, 32, 89, 111, 117, 226, 128], + &[153, 118, 101, 32, 112, 114, 111, 98], + &[97, 98, 108, 121, 32, 117, 115, 101], + &[100, 32, 116, 104, 101, 109, 32, 97], + &[116, 32, 115, 111, 109, 101, 32, 112], + &[111, 105, 110, 116, 44, 32, 101, 105], + &[116, 104, 101, 114, 32, 100, 105, 114], + &[101, 99, 116, 108, 121, 32, 111, 114], + &[0], + ]; + + const START: u32 = 2380683574; + + let mut in_chunks = START; + for chunk in INPUT { + in_chunks = crc32(in_chunks, chunk); + } + + let flattened: Vec<_> = INPUT.iter().copied().flatten().copied().collect(); + let flat = crc32(START, &flattened); + + assert_eq!(in_chunks, flat); + } + + #[test] + fn nasty_alignment() { + const START: u32 = 2380683574; + + const FLAT: &[u8] = &[ + 116, 111, 107, 105, 111, 44, 32, 97, 115, 121, 110, 99, 45, 115, 116, 100, 44, 32, 97, + 110, 100, 32, 115, 109, 111, 108, 46, 32, 89, 111, 117, 226, 128, 153, 118, 101, 32, + 112, 114, 111, 98, 97, 98, 108, 121, 32, 117, 115, 101, 100, 32, 116, 104, 101, 109, + 32, 97, 116, 32, 115, 111, 109, 101, 32, 112, 111, 105, 110, 116, 44, 32, 101, 105, + 116, 104, 101, 114, 32, 100, 105, 114, 101, 99, 116, 108, 121, 32, 111, 114, 0, + ]; + + let mut i = 0; + let mut flat = FLAT.to_vec(); + while flat[i..].as_ptr() as usize % 16 != 15 { + flat.insert(0, 0); + i += 1; + } + + let flat = &flat[i..]; + + assert_eq!(crc32_braid::<5>(START, flat), crc32(START, flat)); + assert_eq!(crc32(2380683574, flat), 1175758345); + } +} diff --git a/third_party/rust/zlib-rs/src/crc32/acle.rs b/third_party/rust/zlib-rs/src/crc32/acle.rs new file mode 100644 index 000000000000..ee2502832a98 --- /dev/null +++ b/third_party/rust/zlib-rs/src/crc32/acle.rs @@ -0,0 +1,181 @@ +#[cfg_attr(not(target_arch = "aarch64"), allow(unused))] +pub fn crc32_acle_aarch64(crc: u32, buf: &[u8]) -> u32 { + let mut c = !crc; + + let (before, middle, after) = unsafe { buf.align_to::() }; + + c = remainder(c, before); + + if middle.is_empty() && after.is_empty() { + return !c; + } + + for d in middle { + c = unsafe { __crc32d(c, *d) }; + } + + c = remainder(c, after); + + !c +} + +#[cfg_attr(not(target_arch = "arm"), allow(unused))] +pub fn crc32_acle_arm(crc: u32, buf: &[u8]) -> u32 { + let mut c = !crc; + + let (before, middle, after) = unsafe { buf.align_to::() }; + + c = remainder(c, before); + + if middle.is_empty() && after.is_empty() { + return !c; + } + + for w in middle { + c = unsafe { __crc32w(c, *w) }; + } + + c = remainder(c, after); + + !c +} + +fn remainder(mut c: u32, mut buf: &[u8]) -> u32 { + if let [b0, b1, b2, b3, rest @ ..] = buf { + c = unsafe { __crc32w(c, u32::from_ne_bytes([*b0, *b1, *b2, *b3])) }; + buf = rest; + } + + if let [b0, b1, rest @ ..] = buf { + c = unsafe { __crc32h(c, u16::from_ne_bytes([*b0, *b1])) }; + buf = rest; + } + + if let [b0, rest @ ..] = buf { + c = unsafe { __crc32b(c, *b0) }; + buf = rest; + } + + debug_assert!(buf.is_empty()); + + c +} + +/// CRC32 single round checksum for bytes (8 bits). +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/__crc32b) +#[target_feature(enable = "crc")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v8"))] +unsafe fn __crc32b(mut crc: u32, data: u8) -> u32 { + core::arch::asm!("crc32b {crc:w}, {crc:w}, {data:w}", crc = inout(reg) crc, data = in(reg) data); + crc +} + +/// CRC32 single round checksum for half words (16 bits). +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/__crc32h) +#[target_feature(enable = "crc")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v8"))] +unsafe fn __crc32h(mut crc: u32, data: u16) -> u32 { + core::arch::asm!("crc32h {crc:w}, {crc:w}, {data:w}", crc = inout(reg) crc, data = in(reg) data); + crc +} + +/// CRC32 single round checksum for words (32 bits). +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/__crc32w) +#[target_feature(enable = "crc")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v8"))] +unsafe fn __crc32w(mut crc: u32, data: u32) -> u32 { + core::arch::asm!("crc32w {crc:w}, {crc:w}, {data:w}", crc = inout(reg) crc, data = in(reg) data); + crc +} + +/// CRC32 single round checksum for double words (64 bits). +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/__crc32d) +#[cfg(target_arch = "aarch64")] +#[target_feature(enable = "crc")] +unsafe fn __crc32d(mut crc: u32, data: u64) -> u32 { + core::arch::asm!("crc32x {crc:w}, {crc:w}, {data:x}", crc = inout(reg) crc, data = in(reg) data); + crc +} + +/// CRC32-C single round checksum for words (32 bits). +/// +/// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/__crc32cw) +#[target_feature(enable = "crc")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v8"))] +pub unsafe fn __crc32cw(mut crc: u32, data: u32) -> u32 { + core::arch::asm!("crc32cw {crc:w}, {crc:w}, {data:w}", crc = inout(reg) crc, data = in(reg) data); + crc +} + +#[cfg(test)] +mod tests { + use super::*; + + quickcheck::quickcheck! { + #[cfg(target_arch = "aarch64")] + fn crc32_acle_aarch64_is_crc32fast(v: Vec, start: u32) -> bool { + let mut h = crc32fast::Hasher::new_with_initial(start); + h.update(&v); + + let a = crc32_acle_aarch64(start, &v) ; + let b = h.finalize(); + + a == b + } + + fn crc32_acle_arm_is_crc32fast(v: Vec, start: u32) -> bool { + let mut h = crc32fast::Hasher::new_with_initial(start); + h.update(&v); + + let a = crc32_acle_arm(start, &v) ; + let b = h.finalize(); + + a == b + } + } + + #[test] + fn test_crc32b() { + unsafe { + assert_eq!(__crc32b(0, 0), 0); + assert_eq!(__crc32b(0, 255), 755167117); + } + } + + #[test] + fn test_crc32h() { + unsafe { + assert_eq!(__crc32h(0, 0), 0); + assert_eq!(__crc32h(0, 16384), 1994146192); + } + } + + #[test] + fn test_crc32w() { + unsafe { + assert_eq!(__crc32w(0, 0), 0); + assert_eq!(__crc32w(0, 4294967295), 3736805603); + } + } + + #[test] + #[cfg(target_arch = "aarch64")] + fn test_crc32d() { + unsafe { + assert_eq!(__crc32d(0, 0), 0); + assert_eq!(__crc32d(0, 18446744073709551615), 1147535477); + } + } + + #[test] + fn test_crc32cw() { + unsafe { + assert_eq!(__crc32cw(0, 0), 0); + assert_eq!(__crc32cw(0, 4294967295), 3080238136); + } + } +} diff --git a/third_party/rust/zlib-rs/src/crc32/braid.rs b/third_party/rust/zlib-rs/src/crc32/braid.rs new file mode 100644 index 000000000000..b216b5aab884 --- /dev/null +++ b/third_party/rust/zlib-rs/src/crc32/braid.rs @@ -0,0 +1,178 @@ +// Several implementations of CRC-32: +// * A naive byte-granularity approach +// * A word-sized approach that processes a usize word at a time +// * A "braid" implementation that processes a block of N words +// at a time, based on the algorithm in section 4.11 from +// https://github.com/zlib-ng/zlib-ng/blob/develop/doc/crc-doc.1.0.pdf. + +// The binary encoding of the CRC-32 polynomial. +// We are assuming little-endianness so we process the input +// LSB-first. We need to use the "reversed" value from e.g +// https://en.wikipedia.org/wiki/Cyclic_redundancy_check#Polynomial_representations. +pub(crate) const CRC32_LSB_POLY: usize = 0xedb8_8320usize; + +const W: usize = core::mem::size_of::(); + +// The logic assumes that W >= sizeof(u32). +// In Rust, this is generally true. +const _: () = assert!(W >= core::mem::size_of::()); + +// Pre-computed tables for the CRC32 algorithm. +// CRC32_BYTE_TABLE corresponds to MulByXPowD from the paper. +static CRC32_BYTE_TABLE: [[u32; 256]; 1] = build_crc32_table::<256, 1, 1>(); +// CRC32_WORD_TABLE is MulWordByXpowD. +static CRC32_WORD_TABLE: [[u32; 256]; W] = build_crc32_table::<256, W, 1>(); + +// Work-around for not being able to define generic consts or statics +// Crc32BraidTable::::TABLE is the generic table for any braid size N. +struct Crc32BraidTable; + +impl Crc32BraidTable { + const TABLE: [[u32; 256]; W] = build_crc32_table::<256, W, N>(); +} + +// Build the CRC32 tables using a more efficient and simpler approach +// than the combination of Multiply and XpowN (which implement polynomial +// multiplication and exponentiation, respectively) from the paper, +// but with identical results. This function is const, so it should be +// fully evaluated at compile time. +const fn build_crc32_table() -> [[u32; A]; W] { + let mut arr = [[0u32; A]; W]; + let mut i = 0; + while i < W { + let mut j = 0; + while j < A { + let mut c = j; + let mut k = 0; + while k < 8 * (W * N - i) { + if c & 1 != 0 { + c = CRC32_LSB_POLY ^ (c >> 1); + } else { + c >>= 1; + } + k += 1; + } + arr[i][j] = c as u32; + j += 1; + } + i += 1; + } + arr +} + +fn crc32_naive_inner(data: &[u8], start: u32) -> u32 { + data.iter().fold(start, |crc, val| { + let crc32_lsb = crc.to_le_bytes()[0]; + CRC32_BYTE_TABLE[0][usize::from(crc32_lsb ^ *val)] ^ (crc >> 8) + }) +} + +fn crc32_words_inner(words: &[usize], start: u32, per_word_crcs: &[u32]) -> u32 { + words.iter().enumerate().fold(start, |crc, (i, word)| { + let value = *word ^ (crc ^ per_word_crcs.get(i).unwrap_or(&0)) as usize; + value + .to_le_bytes() + .into_iter() + .zip(CRC32_WORD_TABLE) + .fold(0u32, |crc, (b, tab)| crc ^ tab[usize::from(b)]) + }) +} + +#[allow(unused)] +pub fn crc32_braid(start: u32, data: &[u8]) -> u32 { + // Get a word-aligned sub-slice of the input data + let (prefix, words, suffix) = unsafe { data.align_to::() }; + let crc = !start; + let crc = crc32_naive_inner(prefix, crc); + + let mut crcs = [0u32; N]; + crcs[0] = crc; + + // TODO: this would normally use words.chunks_exact(N), but + // we need to pass the last full block to crc32_words_inner + // because we accumulate partial crcs in the array and we + // need to roll those into the final value. The last call to + // crc32_words_inner does that for us with its per_word_crcs + // argument. + let blocks = words.len() / N; + let blocks = blocks.saturating_sub(1); + for i in 0..blocks { + // Load the next N words. + let mut buffer: [usize; N] = + core::array::from_fn(|j| usize::to_le(words[i * N + j] ^ (crcs[j] as usize))); + + crcs.fill(0); + for j in 0..W { + for k in 0..N { + crcs[k] ^= Crc32BraidTable::::TABLE[j][buffer[k] & 0xff]; + buffer[k] >>= 8; + } + } + } + + let crc = core::mem::take(&mut crcs[0]); + let crc = crc32_words_inner(&words[blocks * N..], crc, &crcs); + let crc = crc32_naive_inner(suffix, crc); + !crc +} + +#[cfg(test)] +mod test { + use super::*; + + fn crc32_naive(data: &[u8], start: u32) -> u32 { + let crc = !start; + let crc = crc32_naive_inner(data, crc); + !crc + } + + fn crc32_words(data: &[u8], start: u32) -> u32 { + // Get a word-aligned sub-slice of the input data + let (prefix, words, suffix) = unsafe { data.align_to::() }; + let crc = !start; + let crc = crc32_naive_inner(prefix, crc); + let crc = crc32_words_inner(words, crc, &[]); + let crc = crc32_naive_inner(suffix, crc); + !crc + } + + #[test] + fn empty_is_identity() { + assert_eq!(crc32_naive(&[], 32), 32); + } + + quickcheck::quickcheck! { + fn naive_is_crc32fast(v: Vec, start: u32) -> bool { + let mut h = crc32fast::Hasher::new_with_initial(start); + h.update(&v[..]); + crc32_naive(&v[..], start) == h.finalize() + } + + fn words_is_crc32fast(v: Vec, start: u32) -> bool { + let mut h = crc32fast::Hasher::new_with_initial(start); + h.update(&v[..]); + crc32_words(&v[..], start) == h.finalize() + } + + #[cfg_attr(miri, ignore)] + fn braid_4_is_crc32fast(v: Vec, start: u32) -> bool { + let mut h = crc32fast::Hasher::new_with_initial(start); + h.update(&v[..]); + crc32_braid::<4>(start, &v[..]) == h.finalize() + } + + #[cfg_attr(miri, ignore)] + fn braid_5_is_crc32fast(v: Vec, start: u32) -> bool { + let mut h = crc32fast::Hasher::new_with_initial(start); + h.update(&v[..]); + crc32_braid::<5>(start, &v[..]) == h.finalize() + } + + #[cfg_attr(miri, ignore)] + fn braid_6_is_crc32fast(v: Vec, start: u32) -> bool { + let mut h = crc32fast::Hasher::new_with_initial(start); + h.update(&v[..]); + crc32_braid::<6>(start, &v[..]) == h.finalize() + } + } +} diff --git a/third_party/rust/zlib-rs/src/crc32/combine.rs b/third_party/rust/zlib-rs/src/crc32/combine.rs new file mode 100644 index 000000000000..40e3745dd2ab --- /dev/null +++ b/third_party/rust/zlib-rs/src/crc32/combine.rs @@ -0,0 +1,115 @@ +use super::braid::CRC32_LSB_POLY; + +pub const fn crc32_combine(crc1: u32, crc2: u32, len2: u64) -> u32 { + crc32_combine_op(crc1, crc2, crc32_combine_gen(len2)) +} + +#[inline(always)] +const fn crc32_combine_gen(len2: u64) -> u32 { + x2nmodp(len2, 3) +} + +#[inline(always)] +const fn crc32_combine_op(crc1: u32, crc2: u32, op: u32) -> u32 { + multmodp(op, crc1) ^ crc2 +} + +const X2N_TABLE: [u32; 32] = [ + 0x40000000, 0x20000000, 0x08000000, 0x00800000, 0x00008000, 0xedb88320, 0xb1e6b092, 0xa06a2517, + 0xed627dae, 0x88d14467, 0xd7bbfe6a, 0xec447f11, 0x8e7ea170, 0x6427800e, 0x4d47bae0, 0x09fe548f, + 0x83852d0f, 0x30362f1a, 0x7b5a9cc3, 0x31fec169, 0x9fec022a, 0x6c8dedc4, 0x15d6874d, 0x5fde7a4e, + 0xbad90e37, 0x2e4e5eef, 0x4eaba214, 0xa8a472c0, 0x429a969e, 0x148d302a, 0xc40ba6d0, 0xc4e22c3c, +]; + +// Return a(x) multiplied by b(x) modulo p(x), where p(x) is the CRC polynomial, +// reflected. For speed, this requires that a not be zero. +const fn multmodp(a: u32, mut b: u32) -> u32 { + let mut m = 1 << 31; + let mut p = 0; + + loop { + if (a & m) != 0 { + p ^= b; + if (a & (m - 1)) == 0 { + break; + } + } + m >>= 1; + b = if (b & 1) != 0 { + (b >> 1) ^ CRC32_LSB_POLY as u32 + } else { + b >> 1 + }; + } + + p +} + +// Return x^(n * 2^k) modulo p(x). +const fn x2nmodp(mut n: u64, mut k: u32) -> u32 { + let mut p: u32 = 1 << 31; /* x^0 == 1 */ + + while n > 0 { + if (n & 1) != 0 { + p = multmodp(X2N_TABLE[k as usize & 31], p); + } + n >>= 1; + k += 1; + } + + p +} + +#[cfg(test)] +mod test { + use super::*; + + use crate::crc32; + + #[test] + fn test_crc32_combine() { + ::quickcheck::quickcheck(test as fn(_) -> _); + + fn test(data: Vec) -> bool { + let Some(buf_len) = data.first().copied() else { + return true; + }; + + let buf_size = Ord::max(buf_len, 1) as usize; + + let crc0 = 0; + let mut crc1 = crc0; + let mut crc2 = crc0; + + /* CRC32 */ + for chunk in data.chunks(buf_size) { + let crc3 = crc32(crc0, chunk); + let op = crc32_combine_gen(chunk.len() as _); + let crc4 = crc32_combine_op(crc1, crc3, op); + crc1 = crc32(crc1, chunk); + + assert_eq!(crc1, crc4); + } + + crc2 = crc32(crc2, &data); + + assert_eq!(crc1, crc2); + + let combine1 = crc32_combine(crc1, crc2, data.len() as _); + let combine2 = crc32_combine(crc1, crc1, data.len() as _); + assert_eq!(combine1, combine2); + + // Fast CRC32 combine. + let op = crc32_combine_gen(data.len() as _); + let combine1 = crc32_combine_op(crc1, crc2, op); + let combine2 = crc32_combine_op(crc2, crc1, op); + assert_eq!(combine1, combine2); + + let combine1 = crc32_combine(crc1, crc2, data.len() as _); + let combine2 = crc32_combine_op(crc2, crc1, op); + assert_eq!(combine1, combine2); + + true + } + } +} diff --git a/third_party/rust/zlib-rs/src/crc32/pclmulqdq.rs b/third_party/rust/zlib-rs/src/crc32/pclmulqdq.rs new file mode 100644 index 000000000000..9eb276183007 --- /dev/null +++ b/third_party/rust/zlib-rs/src/crc32/pclmulqdq.rs @@ -0,0 +1,342 @@ +use core::arch::x86_64::__m128i; +use core::{ + arch::x86_64::{ + _mm_and_si128, _mm_clmulepi64_si128, _mm_extract_epi32, _mm_load_si128, _mm_loadu_si128, + _mm_or_si128, _mm_shuffle_epi8, _mm_slli_si128, _mm_srli_si128, _mm_storeu_si128, + _mm_xor_si128, + }, + mem::MaybeUninit, +}; + +use crate::{crc32::slice_to_uninit, CRC32_INITIAL_VALUE}; + +#[derive(Debug)] +#[repr(C, align(16))] +struct Align16(T); + +#[cfg(target_arch = "x86_64")] +const fn reg(input: [u32; 4]) -> __m128i { + // safety: any valid [u32; 4] represents a valid __m128i + unsafe { core::mem::transmute(input) } +} + +#[derive(Debug, Clone, Copy)] +#[cfg(target_arch = "x86_64")] +pub(crate) struct Accumulator { + fold: [__m128i; 4], +} + +#[cfg(target_arch = "x86_64")] +impl Accumulator { + const XMM_FOLD4: __m128i = reg([0xc6e41596u32, 0x00000001u32, 0x54442bd4u32, 0x00000001u32]); + + pub const fn new() -> Self { + let xmm_crc0 = reg([0x9db42487, 0, 0, 0]); + let xmm_zero = reg([0, 0, 0, 0]); + + Self { + fold: [xmm_crc0, xmm_zero, xmm_zero, xmm_zero], + } + } + + pub fn fold(&mut self, src: &[u8], start: u32) { + unsafe { self.fold_help::(&mut [], src, start) } + } + + pub fn fold_copy(&mut self, dst: &mut [MaybeUninit], src: &[u8]) { + unsafe { self.fold_help::(dst, src, 0) } + } + + #[target_feature(enable = "pclmulqdq", enable = "sse2", enable = "sse4.1")] + pub unsafe fn finish(self) -> u32 { + const CRC_MASK1: __m128i = + reg([0xFFFFFFFFu32, 0xFFFFFFFFu32, 0x00000000u32, 0x00000000u32]); + + const CRC_MASK2: __m128i = + reg([0x00000000u32, 0xFFFFFFFFu32, 0xFFFFFFFFu32, 0xFFFFFFFFu32]); + + const RK1_RK2: __m128i = reg([ + 0xccaa009e, 0x00000000, /* rk1 */ + 0x751997d0, 0x00000001, /* rk2 */ + ]); + + const RK5_RK6: __m128i = reg([ + 0xccaa009e, 0x00000000, /* rk5 */ + 0x63cd6124, 0x00000001, /* rk6 */ + ]); + + const RK7_RK8: __m128i = reg([ + 0xf7011640, 0x00000001, /* rk7 */ + 0xdb710640, 0x00000001, /* rk8 */ + ]); + + let [mut xmm_crc0, mut xmm_crc1, mut xmm_crc2, mut xmm_crc3] = self.fold; + + /* + * k1 + */ + let mut crc_fold = RK1_RK2; + + let x_tmp0 = _mm_clmulepi64_si128(xmm_crc0, crc_fold, 0x10); + xmm_crc0 = _mm_clmulepi64_si128(xmm_crc0, crc_fold, 0x01); + xmm_crc1 = _mm_xor_si128(xmm_crc1, x_tmp0); + xmm_crc1 = _mm_xor_si128(xmm_crc1, xmm_crc0); + + let x_tmp1 = _mm_clmulepi64_si128(xmm_crc1, crc_fold, 0x10); + xmm_crc1 = _mm_clmulepi64_si128(xmm_crc1, crc_fold, 0x01); + xmm_crc2 = _mm_xor_si128(xmm_crc2, x_tmp1); + xmm_crc2 = _mm_xor_si128(xmm_crc2, xmm_crc1); + + let x_tmp2 = _mm_clmulepi64_si128(xmm_crc2, crc_fold, 0x10); + xmm_crc2 = _mm_clmulepi64_si128(xmm_crc2, crc_fold, 0x01); + xmm_crc3 = _mm_xor_si128(xmm_crc3, x_tmp2); + xmm_crc3 = _mm_xor_si128(xmm_crc3, xmm_crc2); + + /* + * k5 + */ + crc_fold = RK5_RK6; + + xmm_crc0 = xmm_crc3; + xmm_crc3 = _mm_clmulepi64_si128(xmm_crc3, crc_fold, 0); + xmm_crc0 = _mm_srli_si128(xmm_crc0, 8); + xmm_crc3 = _mm_xor_si128(xmm_crc3, xmm_crc0); + + xmm_crc0 = xmm_crc3; + xmm_crc3 = _mm_slli_si128(xmm_crc3, 4); + xmm_crc3 = _mm_clmulepi64_si128(xmm_crc3, crc_fold, 0x10); + xmm_crc3 = _mm_xor_si128(xmm_crc3, xmm_crc0); + xmm_crc3 = _mm_and_si128(xmm_crc3, CRC_MASK2); + + /* + * k7 + */ + xmm_crc1 = xmm_crc3; + xmm_crc2 = xmm_crc3; + crc_fold = RK7_RK8; + + xmm_crc3 = _mm_clmulepi64_si128(xmm_crc3, crc_fold, 0); + xmm_crc3 = _mm_xor_si128(xmm_crc3, xmm_crc2); + xmm_crc3 = _mm_and_si128(xmm_crc3, CRC_MASK1); + + xmm_crc2 = xmm_crc3; + xmm_crc3 = _mm_clmulepi64_si128(xmm_crc3, crc_fold, 0x10); + xmm_crc3 = _mm_xor_si128(xmm_crc3, xmm_crc2); + xmm_crc3 = _mm_xor_si128(xmm_crc3, xmm_crc1); + + !(_mm_extract_epi32(xmm_crc3, 2) as u32) + } + + fn fold_step(&mut self) { + self.fold = core::array::from_fn(|i| match self.fold.get(i + N) { + Some(v) => *v, + None => unsafe { Self::step(self.fold[(i + N) - 4]) }, + }); + } + + #[inline(always)] + unsafe fn step(input: __m128i) -> __m128i { + _mm_xor_si128( + _mm_clmulepi64_si128(input, Self::XMM_FOLD4, 0x01), + _mm_clmulepi64_si128(input, Self::XMM_FOLD4, 0x10), + ) + } + + unsafe fn partial_fold(&mut self, xmm_crc_part: __m128i, len: usize) { + const PSHUFB_SHF_TABLE: [__m128i; 15] = [ + reg([0x84838281, 0x88878685, 0x8c8b8a89, 0x008f8e8d]), /* shl 15 (16 - 1)/shr1 */ + reg([0x85848382, 0x89888786, 0x8d8c8b8a, 0x01008f8e]), /* shl 14 (16 - 3)/shr2 */ + reg([0x86858483, 0x8a898887, 0x8e8d8c8b, 0x0201008f]), /* shl 13 (16 - 4)/shr3 */ + reg([0x87868584, 0x8b8a8988, 0x8f8e8d8c, 0x03020100]), /* shl 12 (16 - 4)/shr4 */ + reg([0x88878685, 0x8c8b8a89, 0x008f8e8d, 0x04030201]), /* shl 11 (16 - 5)/shr5 */ + reg([0x89888786, 0x8d8c8b8a, 0x01008f8e, 0x05040302]), /* shl 10 (16 - 6)/shr6 */ + reg([0x8a898887, 0x8e8d8c8b, 0x0201008f, 0x06050403]), /* shl 9 (16 - 7)/shr7 */ + reg([0x8b8a8988, 0x8f8e8d8c, 0x03020100, 0x07060504]), /* shl 8 (16 - 8)/shr8 */ + reg([0x8c8b8a89, 0x008f8e8d, 0x04030201, 0x08070605]), /* shl 7 (16 - 9)/shr9 */ + reg([0x8d8c8b8a, 0x01008f8e, 0x05040302, 0x09080706]), /* shl 6 (16 -10)/shr10*/ + reg([0x8e8d8c8b, 0x0201008f, 0x06050403, 0x0a090807]), /* shl 5 (16 -11)/shr11*/ + reg([0x8f8e8d8c, 0x03020100, 0x07060504, 0x0b0a0908]), /* shl 4 (16 -12)/shr12*/ + reg([0x008f8e8d, 0x04030201, 0x08070605, 0x0c0b0a09]), /* shl 3 (16 -13)/shr13*/ + reg([0x01008f8e, 0x05040302, 0x09080706, 0x0d0c0b0a]), /* shl 2 (16 -14)/shr14*/ + reg([0x0201008f, 0x06050403, 0x0a090807, 0x0e0d0c0b]), /* shl 1 (16 -15)/shr15*/ + ]; + + let xmm_shl = PSHUFB_SHF_TABLE[len - 1]; + let xmm_shr = _mm_xor_si128(xmm_shl, reg([0x80808080u32; 4])); + + let xmm_a0 = Self::step(_mm_shuffle_epi8(self.fold[0], xmm_shl)); + + self.fold[0] = _mm_shuffle_epi8(self.fold[0], xmm_shr); + let xmm_tmp1 = _mm_shuffle_epi8(self.fold[1], xmm_shl); + self.fold[0] = _mm_or_si128(self.fold[0], xmm_tmp1); + + self.fold[1] = _mm_shuffle_epi8(self.fold[1], xmm_shr); + let xmm_tmp2 = _mm_shuffle_epi8(self.fold[2], xmm_shl); + self.fold[1] = _mm_or_si128(self.fold[1], xmm_tmp2); + + self.fold[2] = _mm_shuffle_epi8(self.fold[2], xmm_shr); + let xmm_tmp3 = _mm_shuffle_epi8(self.fold[3], xmm_shl); + self.fold[2] = _mm_or_si128(self.fold[2], xmm_tmp3); + + self.fold[3] = _mm_shuffle_epi8(self.fold[3], xmm_shr); + let xmm_crc_part = _mm_shuffle_epi8(xmm_crc_part, xmm_shl); + self.fold[3] = _mm_or_si128(self.fold[3], xmm_crc_part); + + // zlib-ng uses casts and a floating-point xor instruction here. There is a theory that + // this breaks dependency chains on some CPUs and gives better throughput. Other sources + // claim that casting between integer and float has a cost and should be avoided. We can't + // measure the difference, and choose the shorter code. + self.fold[3] = _mm_xor_si128(self.fold[3], xmm_a0) + } + + #[allow(clippy::needless_range_loop)] + fn progress( + &mut self, + dst: &mut [MaybeUninit], + src: &mut &[u8], + init_crc: &mut u32, + ) -> usize { + let mut it = src.chunks_exact(16); + let mut input: [_; N] = core::array::from_fn(|_| unsafe { + _mm_load_si128(it.next().unwrap().as_ptr() as *const __m128i) + }); + + *src = &src[N * 16..]; + + if COPY { + for (s, d) in input[..N].iter().zip(dst.chunks_exact_mut(16)) { + unsafe { _mm_storeu_si128(d.as_mut_ptr() as *mut __m128i, *s) }; + } + } else if *init_crc != CRC32_INITIAL_VALUE { + let xmm_initial = reg([*init_crc, 0, 0, 0]); + input[0] = unsafe { _mm_xor_si128(input[0], xmm_initial) }; + *init_crc = CRC32_INITIAL_VALUE; + } + + self.fold_step::(); + + for i in 0..N { + self.fold[i + (4 - N)] = unsafe { _mm_xor_si128(self.fold[i + (4 - N)], input[i]) }; + } + + if COPY { + N * 16 + } else { + 0 + } + } + + #[target_feature(enable = "pclmulqdq", enable = "sse2", enable = "sse4.1")] + unsafe fn fold_help( + &mut self, + mut dst: &mut [MaybeUninit], + mut src: &[u8], + mut init_crc: u32, + ) { + let mut xmm_crc_part = reg([0; 4]); + + let mut partial_buf = Align16([0u8; 16]); + + // Technically the CRC functions don't even call this for input < 64, but a bare minimum of 31 + // bytes of input is needed for the aligning load that occurs. If there's an initial CRC, to + // carry it forward through the folded CRC there must be 16 - src % 16 + 16 bytes available, which + // by definition can be up to 15 bytes + one full vector load. */ + assert!(src.len() >= 31 || init_crc == CRC32_INITIAL_VALUE); + + if COPY { + assert_eq!(dst.len(), src.len(), "dst and src must be the same length") + } + + if src.len() < 16 { + if COPY { + if src.is_empty() { + return; + } + + partial_buf.0[..src.len()].copy_from_slice(src); + xmm_crc_part = _mm_load_si128(partial_buf.0.as_mut_ptr() as *mut __m128i); + dst[..src.len()].copy_from_slice(slice_to_uninit(&partial_buf.0[..src.len()])); + } + } else { + let (before, _, _) = unsafe { src.align_to::<__m128i>() }; + + if !before.is_empty() { + xmm_crc_part = _mm_loadu_si128(src.as_ptr() as *const __m128i); + if COPY { + _mm_storeu_si128(dst.as_mut_ptr() as *mut __m128i, xmm_crc_part); + dst = &mut dst[before.len()..]; + } else { + let is_initial = init_crc == CRC32_INITIAL_VALUE; + + if !is_initial { + let xmm_initial = reg([init_crc, 0, 0, 0]); + xmm_crc_part = _mm_xor_si128(xmm_crc_part, xmm_initial); + init_crc = CRC32_INITIAL_VALUE; + } + + if before.len() < 4 && !is_initial { + let xmm_t0 = xmm_crc_part; + xmm_crc_part = _mm_loadu_si128((src.as_ptr() as *const __m128i).add(1)); + + self.fold_step::<1>(); + + self.fold[3] = _mm_xor_si128(self.fold[3], xmm_t0); + src = &src[16..]; + } + } + + self.partial_fold(xmm_crc_part, before.len()); + + src = &src[before.len()..]; + } + + // if is_x86_feature_detected!("vpclmulqdq") { + // if src.len() >= 256 { + // if COPY { + // // size_t n = fold_16_vpclmulqdq_copy(&xmm_crc0, &xmm_crc1, &xmm_crc2, &xmm_crc3, dst, src, len); + // // dst += n; + // } else { + // // size_t n = fold_16_vpclmulqdq(&xmm_crc0, &xmm_crc1, &xmm_crc2, &xmm_crc3, src, len, xmm_initial, first); + // // first = false; + // } + // // len -= n; + // // src += n; + // } + // } + + while src.len() >= 64 { + let n = self.progress::<4, COPY>(dst, &mut src, &mut init_crc); + dst = &mut dst[n..]; + } + + if src.len() >= 48 { + let n = self.progress::<3, COPY>(dst, &mut src, &mut init_crc); + dst = &mut dst[n..]; + } else if src.len() >= 32 { + let n = self.progress::<2, COPY>(dst, &mut src, &mut init_crc); + dst = &mut dst[n..]; + } else if src.len() >= 16 { + let n = self.progress::<1, COPY>(dst, &mut src, &mut init_crc); + dst = &mut dst[n..]; + } + } + + if !src.is_empty() { + core::ptr::copy_nonoverlapping( + src.as_ptr(), + &mut xmm_crc_part as *mut _ as *mut u8, + src.len(), + ); + if COPY { + _mm_storeu_si128(partial_buf.0.as_mut_ptr() as *mut __m128i, xmm_crc_part); + core::ptr::copy_nonoverlapping( + partial_buf.0.as_ptr() as *const MaybeUninit, + dst.as_mut_ptr(), + src.len(), + ); + } + + self.partial_fold(xmm_crc_part, src.len()); + } + } +} diff --git a/third_party/rust/zlib-rs/src/deflate.rs b/third_party/rust/zlib-rs/src/deflate.rs new file mode 100644 index 000000000000..e58dbb88a5eb --- /dev/null +++ b/third_party/rust/zlib-rs/src/deflate.rs @@ -0,0 +1,4431 @@ +use core::{ffi::CStr, marker::PhantomData, mem::MaybeUninit, ops::ControlFlow}; + +use crate::{ + adler32::adler32, + allocate::Allocator, + c_api::{gz_header, internal_state, z_checksum, z_stream}, + crc32::{crc32, Crc32Fold}, + read_buf::ReadBuf, + trace, DeflateFlush, ReturnCode, ADLER32_INITIAL_VALUE, CRC32_INITIAL_VALUE, MAX_WBITS, + MIN_WBITS, +}; + +use self::{ + algorithm::CONFIGURATION_TABLE, + hash_calc::{Crc32HashCalc, HashCalc, HashCalcVariant, RollHashCalc, StandardHashCalc}, + pending::Pending, + trees_tbl::STATIC_LTREE, + window::Window, +}; + +mod algorithm; +mod compare256; +mod hash_calc; +mod longest_match; +mod pending; +mod slide_hash; +mod trees_tbl; +mod window; + +#[repr(C)] +pub struct DeflateStream<'a> { + pub(crate) next_in: *mut crate::c_api::Bytef, + pub(crate) avail_in: crate::c_api::uInt, + pub(crate) total_in: crate::c_api::z_size, + pub(crate) next_out: *mut crate::c_api::Bytef, + pub(crate) avail_out: crate::c_api::uInt, + pub(crate) total_out: crate::c_api::z_size, + pub(crate) msg: *const core::ffi::c_char, + pub(crate) state: &'a mut State<'a>, + pub(crate) alloc: Allocator<'a>, + pub(crate) data_type: core::ffi::c_int, + pub(crate) adler: crate::c_api::z_checksum, + pub(crate) reserved: crate::c_api::uLong, +} + +impl<'a> DeflateStream<'a> { + const _S: () = assert!(core::mem::size_of::() == core::mem::size_of::()); + const _A: () = assert!(core::mem::align_of::() == core::mem::align_of::()); + + /// # Safety + /// + /// The `strm` pointer must be either `NULL` or a correctly initalized `z_stream`. Here + /// correctly initalized does not just mean that the pointer is valid and well-aligned, but + /// also that it has been initialized by that `deflateInit_` or `deflateInit2_`. + #[inline(always)] + pub unsafe fn from_stream_mut(strm: *mut z_stream) -> Option<&'a mut Self> { + if strm.is_null() { + return None; + } + + // safety: ptr points to a valid value of type z_stream (if non-null) + let stream = unsafe { &mut *strm }; + + if stream.zalloc.is_none() || stream.zfree.is_none() { + return None; + } + + if stream.state.is_null() { + return None; + } + + // safety: DeflateStream has the same layout as z_stream + let stream = unsafe { &mut *(strm as *mut DeflateStream) }; + + Some(stream) + } + + fn as_z_stream_mut(&mut self) -> &mut z_stream { + // safety: a valid &mut DeflateStream is also a valid &mut z_stream + unsafe { &mut *(self as *mut DeflateStream as *mut z_stream) } + } + + pub fn pending(&self) -> (usize, u8) { + ( + self.state.bit_writer.pending.pending, + self.state.bit_writer.bits_used, + ) + } +} + +/// number of elements in hash table +pub(crate) const HASH_SIZE: usize = 65536; +/// log2(HASH_SIZE) +const HASH_BITS: usize = 16; + +/// Maximum value for memLevel in deflateInit2 +const MAX_MEM_LEVEL: i32 = 9; +const DEF_MEM_LEVEL: i32 = if MAX_MEM_LEVEL > 8 { 8 } else { MAX_MEM_LEVEL }; + +#[repr(i32)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)] +#[cfg_attr(feature = "__internal-fuzz", derive(arbitrary::Arbitrary))] +pub enum Method { + #[default] + Deflated = 8, +} + +impl TryFrom for Method { + type Error = (); + + fn try_from(value: i32) -> Result { + match value { + 8 => Ok(Self::Deflated), + _ => Err(()), + } + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +#[cfg_attr(feature = "__internal-fuzz", derive(arbitrary::Arbitrary))] +pub struct DeflateConfig { + pub level: i32, + pub method: Method, + pub window_bits: i32, + pub mem_level: i32, + pub strategy: Strategy, +} + +#[cfg(any(test, feature = "__internal-test"))] +impl quickcheck::Arbitrary for DeflateConfig { + fn arbitrary(g: &mut quickcheck::Gen) -> Self { + let mem_levels: Vec<_> = (1..=9).collect(); + let levels: Vec<_> = (0..=9).collect(); + + let mut window_bits = Vec::new(); + window_bits.extend(9..=15); // zlib + window_bits.extend(9 + 16..=15 + 16); // gzip + window_bits.extend(-15..=-9); // raw + + Self { + level: *g.choose(&levels).unwrap(), + method: Method::Deflated, + window_bits: *g.choose(&window_bits).unwrap(), + mem_level: *g.choose(&mem_levels).unwrap(), + strategy: *g + .choose(&[ + Strategy::Default, + Strategy::Filtered, + Strategy::HuffmanOnly, + Strategy::Rle, + Strategy::Fixed, + ]) + .unwrap(), + } + } +} + +impl DeflateConfig { + pub fn new(level: i32) -> Self { + Self { + level, + ..Self::default() + } + } +} + +impl Default for DeflateConfig { + fn default() -> Self { + Self { + level: crate::c_api::Z_DEFAULT_COMPRESSION, + method: Method::Deflated, + window_bits: MAX_WBITS, + mem_level: DEF_MEM_LEVEL, + strategy: Strategy::Default, + } + } +} + +// TODO: This could use `MaybeUninit::slice_assume_init` when it is stable. +unsafe fn slice_assume_init_mut(slice: &mut [MaybeUninit]) -> &mut [T] { + &mut *(slice as *mut [MaybeUninit] as *mut [T]) +} + +// when stable, use MaybeUninit::write_slice +fn slice_to_uninit(slice: &[T]) -> &[MaybeUninit] { + // safety: &[T] and &[MaybeUninit] have the same layout + unsafe { &*(slice as *const [T] as *const [MaybeUninit]) } +} + +pub fn init(stream: &mut z_stream, config: DeflateConfig) -> ReturnCode { + let DeflateConfig { + mut level, + method: _, + mut window_bits, + mem_level, + strategy, + } = config; + + /* Todo: ignore strm->next_in if we use it as window */ + stream.msg = core::ptr::null_mut(); + + // for safety we must really make sure that alloc and free are consistent + // this is a (slight) deviation from stock zlib. In this crate we pick the rust + // allocator as the default, but `libz-rs-sys` always explicitly sets an allocator, + // and can configure the C allocator + #[cfg(feature = "rust-allocator")] + if stream.zalloc.is_none() || stream.zfree.is_none() { + stream.configure_default_rust_allocator() + } + + #[cfg(feature = "c-allocator")] + if stream.zalloc.is_none() || stream.zfree.is_none() { + stream.configure_default_c_allocator() + } + + if stream.zalloc.is_none() || stream.zfree.is_none() { + return ReturnCode::StreamError; + } + + if level == crate::c_api::Z_DEFAULT_COMPRESSION { + level = 6; + } + + let wrap = if window_bits < 0 { + if window_bits < -MAX_WBITS { + return ReturnCode::StreamError; + } + window_bits = -window_bits; + + 0 + } else if window_bits > MAX_WBITS { + window_bits -= 16; + 2 + } else { + 1 + }; + + if (!(1..=MAX_MEM_LEVEL).contains(&mem_level)) + || !(MIN_WBITS..=MAX_WBITS).contains(&window_bits) + || !(0..=9).contains(&level) + || (window_bits == 8 && wrap != 1) + { + return ReturnCode::StreamError; + } + + let window_bits = if window_bits == 8 { + 9 /* until 256-byte window bug fixed */ + } else { + window_bits as usize + }; + + let alloc = Allocator { + zalloc: stream.zalloc.unwrap(), + zfree: stream.zfree.unwrap(), + opaque: stream.opaque, + _marker: PhantomData, + }; + + // allocated here to have the same order as zlib + let Some(state_allocation) = alloc.allocate::() else { + return ReturnCode::MemError; + }; + + let w_size = 1 << window_bits; + let window = Window::new_in(&alloc, window_bits); + + let prev = alloc.allocate_slice::(w_size); + let head = alloc.allocate::<[u16; HASH_SIZE]>(); + + let lit_bufsize = 1 << (mem_level + 6); // 16K elements by default + let pending = Pending::new_in(&alloc, 4 * lit_bufsize); + + // zlib-ng overlays the pending_buf and sym_buf. We cannot really do that safely + let sym_buf = ReadBuf::new_in(&alloc, 3 * lit_bufsize); + + // if any allocation failed, clean up allocations that did succeed + let (window, prev, head, pending, sym_buf) = match (window, prev, head, pending, sym_buf) { + (Some(window), Some(prev), Some(head), Some(pending), Some(sym_buf)) => { + (window, prev, head, pending, sym_buf) + } + (window, prev, head, pending, sym_buf) => { + unsafe { + if let Some(mut sym_buf) = sym_buf { + alloc.deallocate(sym_buf.as_mut_ptr(), sym_buf.capacity()) + } + if let Some(pending) = pending { + pending.drop_in(&alloc); + } + if let Some(head) = head { + alloc.deallocate(head.as_mut_ptr(), 1) + } + if let Some(prev) = prev { + alloc.deallocate(prev.as_mut_ptr(), prev.len()) + } + if let Some(mut window) = window { + window.drop_in(&alloc); + } + + alloc.deallocate(state_allocation.as_mut_ptr(), 1); + } + + return ReturnCode::MemError; + } + }; + + prev.fill(MaybeUninit::zeroed()); + let prev = unsafe { slice_assume_init_mut(prev) }; + + *head = MaybeUninit::zeroed(); + let head = unsafe { head.assume_init_mut() }; + + let state = State { + status: Status::Init, + + // window + w_bits: window_bits, + w_size, + w_mask: w_size - 1, + + // allocated values + window, + prev, + head, + bit_writer: BitWriter::from_pending(pending), + + // + lit_bufsize, + + // + sym_buf, + + // + level: level as i8, // set to zero again for testing? + strategy, + + // these fields are not set explicitly at this point + last_flush: 0, + wrap, + strstart: 0, + block_start: 0, + block_open: 0, + window_size: 0, + insert: 0, + matches: 0, + opt_len: 0, + static_len: 0, + lookahead: 0, + ins_h: 0, + max_chain_length: 0, + max_lazy_match: 0, + good_match: 0, + nice_match: 0, + + // + l_desc: TreeDesc::EMPTY, + d_desc: TreeDesc::EMPTY, + bl_desc: TreeDesc::EMPTY, + + bl_count: [0u16; MAX_BITS + 1], + + // + heap: Heap::new(), + + // + crc_fold: Crc32Fold::new(), + gzhead: None, + gzindex: 0, + + // + match_start: 0, + match_length: 0, + prev_match: 0, + match_available: false, + prev_length: 0, + + // just provide a valid default; gets set properly later + hash_calc_variant: HashCalcVariant::Standard, + }; + + let state = state_allocation.write(state); + stream.state = state as *mut _ as *mut internal_state; + + let Some(stream) = (unsafe { DeflateStream::from_stream_mut(stream) }) else { + if cfg!(debug_assertions) { + unreachable!("we should have initialized the stream properly"); + } + return ReturnCode::StreamError; + }; + + reset(stream) +} + +pub fn params(stream: &mut DeflateStream, level: i32, strategy: Strategy) -> ReturnCode { + let level = if level == crate::c_api::Z_DEFAULT_COMPRESSION { + 6 + } else { + level + }; + + if !(0..=9).contains(&level) { + return ReturnCode::StreamError; + } + + let level = level as i8; + + let func = CONFIGURATION_TABLE[stream.state.level as usize].func; + + let state = &mut stream.state; + + if (strategy != state.strategy || func != CONFIGURATION_TABLE[level as usize].func) + && state.last_flush != -2 + { + // Flush the last buffer. + let err = deflate(stream, DeflateFlush::Block); + if err == ReturnCode::StreamError { + return err; + } + + let state = &mut stream.state; + + if stream.avail_in != 0 + || ((state.strstart as isize - state.block_start) + state.lookahead as isize) != 0 + { + return ReturnCode::BufError; + } + } + + let state = &mut stream.state; + + if state.level != level { + if state.level == 0 && state.matches != 0 { + if state.matches == 1 { + self::slide_hash::slide_hash(state); + } else { + state.head.fill(0); + } + state.matches = 0; + } + + lm_set_level(state, level); + } + + state.strategy = strategy; + + ReturnCode::Ok +} + +pub fn set_dictionary(stream: &mut DeflateStream, mut dictionary: &[u8]) -> ReturnCode { + let state = &mut stream.state; + + let wrap = state.wrap; + + if wrap == 2 || (wrap == 1 && state.status != Status::Init) || state.lookahead != 0 { + return ReturnCode::StreamError; + } + + // when using zlib wrappers, compute Adler-32 for provided dictionary + if wrap == 1 { + stream.adler = adler32(stream.adler as u32, dictionary) as z_checksum; + } + + // avoid computing Adler-32 in read_buf + state.wrap = 0; + + // if dictionary would fill window, just replace the history + if dictionary.len() >= state.window.capacity() { + if wrap == 0 { + // clear the hash table + state.head.fill(0); + + state.strstart = 0; + state.block_start = 0; + state.insert = 0; + } else { + /* already empty otherwise */ + } + + // use the tail + dictionary = &dictionary[dictionary.len() - state.w_size..]; + } + + // insert dictionary into window and hash + let avail = stream.avail_in; + let next = stream.next_in; + stream.avail_in = dictionary.len() as _; + stream.next_in = dictionary.as_ptr() as *mut u8; + fill_window(stream); + + while stream.state.lookahead >= STD_MIN_MATCH { + let str = stream.state.strstart; + let n = stream.state.lookahead - (STD_MIN_MATCH - 1); + stream.state.insert_string(str, n); + stream.state.strstart = str + n; + stream.state.lookahead = STD_MIN_MATCH - 1; + fill_window(stream); + } + + let state = &mut stream.state; + + state.strstart += state.lookahead; + state.block_start = state.strstart as _; + state.insert = state.lookahead; + state.lookahead = 0; + state.prev_length = 0; + state.match_available = false; + + // restore the state + stream.next_in = next; + stream.avail_in = avail; + state.wrap = wrap; + + ReturnCode::Ok +} + +pub fn prime(stream: &mut DeflateStream, mut bits: i32, value: i32) -> ReturnCode { + // our logic actually supports up to 32 bits. + debug_assert!(bits <= 16, "zlib only supports up to 16 bits here"); + + let mut value64 = value as u64; + + let state = &mut stream.state; + + if bits < 0 + || bits > BitWriter::BIT_BUF_SIZE as i32 + || bits > (core::mem::size_of_val(&value) << 3) as i32 + { + return ReturnCode::BufError; + } + + let mut put; + + loop { + put = BitWriter::BIT_BUF_SIZE - state.bit_writer.bits_used; + let put = Ord::min(put as i32, bits); + + if state.bit_writer.bits_used == 0 { + state.bit_writer.bit_buffer = value64; + } else { + state.bit_writer.bit_buffer |= + (value64 & ((1 << put) - 1)) << state.bit_writer.bits_used; + } + + state.bit_writer.bits_used += put as u8; + state.bit_writer.flush_bits(); + value64 >>= put; + bits -= put; + + if bits == 0 { + break; + } + } + + ReturnCode::Ok +} + +pub fn copy<'a>( + dest: &mut MaybeUninit>, + source: &mut DeflateStream<'a>, +) -> ReturnCode { + // Safety: source and dest are both mutable references, so guaranteed not to overlap. + // dest being a reference to maybe uninitialized memory makes a copy of 1 DeflateStream valid. + unsafe { + core::ptr::copy_nonoverlapping(source, dest.as_mut_ptr(), 1); + } + + let alloc = &source.alloc; + + // allocated here to have the same order as zlib + let Some(state_allocation) = alloc.allocate::() else { + return ReturnCode::MemError; + }; + + let source_state = &source.state; + + let window = source_state.window.clone_in(alloc); + + let prev = alloc.allocate_slice::(source_state.w_size); + let head = alloc.allocate::<[u16; HASH_SIZE]>(); + + let pending = source_state.bit_writer.pending.clone_in(alloc); + let sym_buf = source_state.sym_buf.clone_in(alloc); + + // if any allocation failed, clean up allocations that did succeed + let (window, prev, head, pending, sym_buf) = match (window, prev, head, pending, sym_buf) { + (Some(window), Some(prev), Some(head), Some(pending), Some(sym_buf)) => { + (window, prev, head, pending, sym_buf) + } + (window, prev, head, pending, sym_buf) => { + // Safety: this access is in-bounds + let field_ptr = unsafe { core::ptr::addr_of_mut!((*dest.as_mut_ptr()).state) }; + unsafe { core::ptr::write(field_ptr as *mut *mut State, core::ptr::null_mut()) }; + + // Safety: it is an assumpion on DeflateStream that (de)allocation does not cause UB. + unsafe { + if let Some(mut sym_buf) = sym_buf { + alloc.deallocate(sym_buf.as_mut_ptr(), sym_buf.capacity()) + } + if let Some(pending) = pending { + pending.drop_in(alloc); + } + if let Some(head) = head { + alloc.deallocate(head.as_mut_ptr(), HASH_SIZE) + } + if let Some(prev) = prev { + alloc.deallocate(prev.as_mut_ptr(), prev.len()) + } + if let Some(mut window) = window { + window.drop_in(alloc); + } + + alloc.deallocate(state_allocation.as_mut_ptr(), 1); + } + + return ReturnCode::MemError; + } + }; + + prev.copy_from_slice(slice_to_uninit(source_state.prev)); + let prev = unsafe { core::slice::from_raw_parts_mut(prev.as_mut_ptr().cast(), prev.len()) }; + let head = head.write(*source_state.head); + + let mut bit_writer = BitWriter::from_pending(pending); + bit_writer.bits_used = source_state.bit_writer.bits_used; + bit_writer.bit_buffer = source_state.bit_writer.bit_buffer; + + let dest_state = State { + status: source_state.status, + bit_writer, + last_flush: source_state.last_flush, + wrap: source_state.wrap, + strategy: source_state.strategy, + level: source_state.level, + good_match: source_state.good_match, + nice_match: source_state.nice_match, + l_desc: source_state.l_desc.clone(), + d_desc: source_state.d_desc.clone(), + bl_desc: source_state.bl_desc.clone(), + bl_count: source_state.bl_count, + match_length: source_state.match_length, + prev_match: source_state.prev_match, + match_available: source_state.match_available, + strstart: source_state.strstart, + match_start: source_state.match_start, + prev_length: source_state.prev_length, + max_chain_length: source_state.max_chain_length, + max_lazy_match: source_state.max_lazy_match, + block_start: source_state.block_start, + block_open: source_state.block_open, + window, + sym_buf, + lit_bufsize: source_state.lit_bufsize, + window_size: source_state.window_size, + matches: source_state.matches, + opt_len: source_state.opt_len, + static_len: source_state.static_len, + insert: source_state.insert, + w_size: source_state.w_size, + w_bits: source_state.w_bits, + w_mask: source_state.w_mask, + lookahead: source_state.lookahead, + prev, + head, + ins_h: source_state.ins_h, + heap: source_state.heap.clone(), + hash_calc_variant: source_state.hash_calc_variant, + crc_fold: source_state.crc_fold, + gzhead: None, + gzindex: source_state.gzindex, + }; + + // write the cloned state into state_ptr + let state_ptr = state_allocation.write(dest_state); + + // insert the state_ptr into `dest` + let field_ptr = unsafe { core::ptr::addr_of_mut!((*dest.as_mut_ptr()).state) }; + unsafe { core::ptr::write(field_ptr as *mut *mut State, state_ptr) }; + + // update the gzhead field (it contains a mutable reference so we need to be careful + let field_ptr = unsafe { core::ptr::addr_of_mut!((*dest.as_mut_ptr()).state.gzhead) }; + unsafe { core::ptr::copy(&source_state.gzhead, field_ptr, 1) }; + + ReturnCode::Ok +} + +/// # Returns +/// +/// - Err when deflate is not done. A common cause is insufficient output space +/// - Ok otherwise +pub fn end<'a>(stream: &'a mut DeflateStream) -> Result<&'a mut z_stream, &'a mut z_stream> { + let status = stream.state.status; + + let alloc = stream.alloc; + + // deallocate in reverse order of allocations + unsafe { + // safety: we make sure that these fields are not used (by invalidating the state pointer) + stream.state.sym_buf.drop_in(&alloc); + stream.state.bit_writer.pending.drop_in(&alloc); + alloc.deallocate(stream.state.head, 1); + if !stream.state.prev.is_empty() { + alloc.deallocate(stream.state.prev.as_mut_ptr(), stream.state.prev.len()); + } + stream.state.window.drop_in(&alloc); + } + + let state = stream.state as *mut State; + let stream = stream.as_z_stream_mut(); + stream.state = core::ptr::null_mut(); + + // safety: `state` is not used later + unsafe { + alloc.deallocate(state, 1); + } + + match status { + Status::Busy => Err(stream), + _ => Ok(stream), + } +} + +pub fn reset(stream: &mut DeflateStream) -> ReturnCode { + let ret = reset_keep(stream); + + if ret == ReturnCode::Ok { + lm_init(stream.state); + } + + ret +} + +fn reset_keep(stream: &mut DeflateStream) -> ReturnCode { + stream.total_in = 0; + stream.total_out = 0; + stream.msg = core::ptr::null_mut(); + stream.data_type = crate::c_api::Z_UNKNOWN; + + let state = &mut stream.state; + + state.bit_writer.pending.reset_keep(); + + // can be made negative by deflate(..., Z_FINISH); + state.wrap = state.wrap.abs(); + + state.status = match state.wrap { + 2 => Status::GZip, + _ => Status::Init, + }; + + stream.adler = match state.wrap { + 2 => { + state.crc_fold = Crc32Fold::new(); + CRC32_INITIAL_VALUE as _ + } + _ => ADLER32_INITIAL_VALUE as _, + }; + + state.last_flush = -2; + + state.zng_tr_init(); + + ReturnCode::Ok +} + +fn lm_init(state: &mut State) { + state.window_size = 2 * state.w_size; + + // zlib uses CLEAR_HASH here + state.head.fill(0); + + // Set the default configuration parameters: + lm_set_level(state, state.level); + + state.strstart = 0; + state.block_start = 0; + state.lookahead = 0; + state.insert = 0; + state.prev_length = 0; + state.match_available = false; + state.match_start = 0; + state.ins_h = 0; +} + +fn lm_set_level(state: &mut State, level: i8) { + state.max_lazy_match = CONFIGURATION_TABLE[level as usize].max_lazy as usize; + state.good_match = CONFIGURATION_TABLE[level as usize].good_length as usize; + state.nice_match = CONFIGURATION_TABLE[level as usize].nice_length as usize; + state.max_chain_length = CONFIGURATION_TABLE[level as usize].max_chain as usize; + + // Use rolling hash for deflate_slow algorithm with level 9. It allows us to + // properly lookup different hash chains to speed up longest_match search. Since hashing + // method changes depending on the level we cannot put this into functable. */ + state.hash_calc_variant = if state.max_chain_length > 1024 { + HashCalcVariant::Roll + } else if Crc32HashCalc::is_supported() { + HashCalcVariant::Crc32 + } else { + HashCalcVariant::Standard + }; + + state.level = level; +} + +pub fn tune( + stream: &mut DeflateStream, + good_length: usize, + max_lazy: usize, + nice_length: usize, + max_chain: usize, +) -> ReturnCode { + stream.state.good_match = good_length; + stream.state.max_lazy_match = max_lazy; + stream.state.nice_match = nice_length; + stream.state.max_chain_length = max_chain; + + ReturnCode::Ok +} + +#[repr(C)] +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub(crate) struct Value { + a: u16, + b: u16, +} + +impl Value { + pub(crate) const fn new(a: u16, b: u16) -> Self { + Self { a, b } + } + + pub(crate) fn freq_mut(&mut self) -> &mut u16 { + &mut self.a + } + + pub(crate) fn code_mut(&mut self) -> &mut u16 { + &mut self.a + } + + pub(crate) fn dad_mut(&mut self) -> &mut u16 { + &mut self.b + } + + pub(crate) fn len_mut(&mut self) -> &mut u16 { + &mut self.b + } + + #[inline(always)] + pub(crate) const fn freq(self) -> u16 { + self.a + } + + pub(crate) fn code(self) -> u16 { + self.a + } + + pub(crate) fn dad(self) -> u16 { + self.b + } + + pub(crate) fn len(self) -> u16 { + self.b + } +} + +/// number of length codes, not counting the special END_BLOCK code +pub(crate) const LENGTH_CODES: usize = 29; + +/// number of literal bytes 0..255 +const LITERALS: usize = 256; + +/// number of Literal or Length codes, including the END_BLOCK code +pub(crate) const L_CODES: usize = LITERALS + 1 + LENGTH_CODES; + +/// number of distance codes +pub(crate) const D_CODES: usize = 30; + +/// number of codes used to transfer the bit lengths +const BL_CODES: usize = 19; + +/// maximum heap size +const HEAP_SIZE: usize = 2 * L_CODES + 1; + +/// all codes must not exceed MAX_BITS bits +const MAX_BITS: usize = 15; + +/// Bit length codes must not exceed MAX_BL_BITS bits +const MAX_BL_BITS: usize = 7; + +pub(crate) const DIST_CODE_LEN: usize = 512; + +struct BitWriter<'a> { + pub(crate) pending: Pending<'a>, // output still pending + pub(crate) bit_buffer: u64, + pub(crate) bits_used: u8, +} + +impl<'a> BitWriter<'a> { + pub(crate) const BIT_BUF_SIZE: u8 = 64; + + fn from_pending(pending: Pending<'a>) -> Self { + Self { + pending, + bit_buffer: 0, + bits_used: 0, + } + } + + fn flush_bits(&mut self) { + debug_assert!(self.bits_used <= 64); + let removed = self.bits_used.saturating_sub(7).next_multiple_of(8); + let keep_bytes = self.bits_used / 8; // can never divide by zero + + let src = &self.bit_buffer.to_le_bytes(); + self.pending.extend(&src[..keep_bytes as usize]); + + self.bits_used -= removed; + self.bit_buffer = self.bit_buffer.checked_shr(removed as u32).unwrap_or(0); + } + + fn flush_and_align_bits(&mut self) { + debug_assert!(self.bits_used <= 64); + let keep_bytes = self.bits_used.div_ceil(8); + let src = &self.bit_buffer.to_le_bytes(); + self.pending.extend(&src[..keep_bytes as usize]); + + self.bits_used = 0; + self.bit_buffer = 0; + } + + fn send_bits(&mut self, val: u64, len: u8) { + debug_assert!(len <= 64); + debug_assert!(self.bits_used <= 64); + + let total_bits = len + self.bits_used; + + // send_bits_trace(s, val, len);\ + // sent_bits_add(s, len);\ + + if total_bits < Self::BIT_BUF_SIZE { + self.bit_buffer |= val << self.bits_used; + self.bits_used = total_bits; + } else if self.bits_used == Self::BIT_BUF_SIZE { + // with how send_bits is called, this is unreachable in practice + self.pending.extend(&self.bit_buffer.to_ne_bytes()); + self.bit_buffer = val; + self.bits_used = len; + } else { + self.bit_buffer |= val << self.bits_used; + self.pending.extend(&self.bit_buffer.to_ne_bytes()); + self.bit_buffer = val >> (Self::BIT_BUF_SIZE - self.bits_used); + self.bits_used = total_bits - Self::BIT_BUF_SIZE; + } + } + + fn send_code(&mut self, code: usize, tree: &[Value]) { + let node = tree[code]; + self.send_bits(node.code() as u64, node.len() as u8) + } + + /// Send one empty static block to give enough lookahead for inflate. + /// This takes 10 bits, of which 7 may remain in the bit buffer. + pub fn align(&mut self) { + self.emit_tree(BlockType::StaticTrees, false); + self.emit_end_block(&STATIC_LTREE, false); + self.flush_bits(); + } + + pub(crate) fn emit_tree(&mut self, block_type: BlockType, is_last_block: bool) { + let header_bits = (block_type as u64) << 1 | (is_last_block as u64); + self.send_bits(header_bits, 3); + } + + pub(crate) fn emit_end_block_and_align(&mut self, ltree: &[Value], is_last_block: bool) { + self.emit_end_block(ltree, is_last_block); + + if is_last_block { + self.flush_and_align_bits(); + } + } + + fn emit_end_block(&mut self, ltree: &[Value], _is_last_block: bool) { + const END_BLOCK: usize = 256; + self.send_code(END_BLOCK, ltree); + } + + pub(crate) fn emit_lit(&mut self, ltree: &[Value], c: u8) -> u16 { + self.send_code(c as usize, ltree); + + trace!( + "'{}' ", + match char::from_u32(c as u32) { + None => ' ', + Some(c) => match c.is_ascii() && !c.is_whitespace() { + true => c, + false => ' ', + }, + } + ); + + ltree[c as usize].len() + } + + pub(crate) fn emit_dist( + &mut self, + ltree: &[Value], + dtree: &[Value], + lc: u8, + mut dist: usize, + ) -> usize { + let mut lc = lc as usize; + + /* Send the length code, len is the match length - STD_MIN_MATCH */ + let mut code = self::trees_tbl::LENGTH_CODE[lc] as usize; + let c = code + LITERALS + 1; + assert!(c < L_CODES, "bad l_code"); + // send_code_trace(s, c); + + let lnode = ltree[c]; + let mut match_bits = lnode.code() as usize; + let mut match_bits_len = lnode.len() as usize; + let mut extra = StaticTreeDesc::EXTRA_LBITS[code] as usize; + if extra != 0 { + lc -= self::trees_tbl::BASE_LENGTH[code] as usize; + match_bits |= lc << match_bits_len; + match_bits_len += extra; + } + + dist -= 1; /* dist is now the match distance - 1 */ + code = State::d_code(dist) as usize; + assert!(code < D_CODES, "bad d_code"); + // send_code_trace(s, code); + + /* Send the distance code */ + let dnode = dtree[code]; + match_bits |= (dnode.code() as usize) << match_bits_len; + match_bits_len += dnode.len() as usize; + extra = StaticTreeDesc::EXTRA_DBITS[code] as usize; + if extra != 0 { + dist -= self::trees_tbl::BASE_DIST[code] as usize; + match_bits |= dist << match_bits_len; + match_bits_len += extra; + } + + self.send_bits(match_bits as u64, match_bits_len as u8); + + match_bits_len + } + + fn compress_block_help(&mut self, sym_buf: &[u8], ltree: &[Value], dtree: &[Value]) { + for chunk in sym_buf.chunks_exact(3) { + let [dist_low, dist_high, lc] = *chunk else { + unreachable!("out of bound access on the symbol buffer"); + }; + + match u16::from_be_bytes([dist_high, dist_low]) as usize { + 0 => self.emit_lit(ltree, lc) as usize, + dist => self.emit_dist(ltree, dtree, lc, dist), + }; + } + + self.emit_end_block(ltree, false) + } + + fn send_tree(&mut self, tree: &[Value], bl_tree: &[Value], max_code: usize) { + /* tree: the tree to be scanned */ + /* max_code and its largest code of non zero frequency */ + let mut prevlen: isize = -1; /* last emitted length */ + let mut curlen; /* length of current code */ + let mut nextlen = tree[0].len(); /* length of next code */ + let mut count = 0; /* repeat count of the current code */ + let mut max_count = 7; /* max repeat count */ + let mut min_count = 4; /* min repeat count */ + + /* tree[max_code+1].Len = -1; */ + /* guard already set */ + if nextlen == 0 { + max_count = 138; + min_count = 3; + } + + for n in 0..=max_code { + curlen = nextlen; + nextlen = tree[n + 1].len(); + count += 1; + if count < max_count && curlen == nextlen { + continue; + } else if count < min_count { + loop { + self.send_code(curlen as usize, bl_tree); + + count -= 1; + if count == 0 { + break; + } + } + } else if curlen != 0 { + if curlen as isize != prevlen { + self.send_code(curlen as usize, bl_tree); + count -= 1; + } + assert!((3..=6).contains(&count), " 3_6?"); + self.send_code(REP_3_6, bl_tree); + self.send_bits(count - 3, 2); + } else if count <= 10 { + self.send_code(REPZ_3_10, bl_tree); + self.send_bits(count - 3, 3); + } else { + self.send_code(REPZ_11_138, bl_tree); + self.send_bits(count - 11, 7); + } + + count = 0; + prevlen = curlen as isize; + + if nextlen == 0 { + max_count = 138; + min_count = 3; + } else if curlen == nextlen { + max_count = 6; + min_count = 3; + } else { + max_count = 7; + min_count = 4; + } + } + } +} + +#[allow(unused)] +#[repr(C)] +pub(crate) struct State<'a> { + status: Status, + + last_flush: i32, /* value of flush param for previous deflate call */ + + bit_writer: BitWriter<'a>, + + pub(crate) wrap: i8, /* bit 0 true for zlib, bit 1 true for gzip */ + + pub(crate) strategy: Strategy, + pub(crate) level: i8, + + /// Use a faster search when the previous match is longer than this + pub(crate) good_match: usize, + + /// Stop searching when current match exceeds this + pub(crate) nice_match: usize, + + // part of the fields below + // dyn_ltree: [Value; ], + // dyn_dtree: [Value; ], + // bl_tree: [Value; ], + l_desc: TreeDesc, /* literal and length tree */ + d_desc: TreeDesc<{ 2 * D_CODES + 1 }>, /* distance tree */ + bl_desc: TreeDesc<{ 2 * BL_CODES + 1 }>, /* Huffman tree for bit lengths */ + + pub(crate) bl_count: [u16; MAX_BITS + 1], + + pub(crate) match_length: usize, /* length of best match */ + pub(crate) prev_match: u16, /* previous match */ + pub(crate) match_available: bool, /* set if previous match exists */ + pub(crate) strstart: usize, /* start of string to insert */ + pub(crate) match_start: usize, /* start of matching string */ + + /// Length of the best match at previous step. Matches not greater than this + /// are discarded. This is used in the lazy match evaluation. + pub(crate) prev_length: usize, + + /// To speed up deflation, hash chains are never searched beyond this length. + /// A higher limit improves compression ratio but degrades the speed. + pub(crate) max_chain_length: usize, + + // TODO untangle this mess! zlib uses the same field differently based on compression level + // we should just have 2 fields for clarity! + // + // Insert new strings in the hash table only if the match length is not + // greater than this length. This saves time but degrades compression. + // max_insert_length is used only for compression levels <= 3. + // define max_insert_length max_lazy_match + /// Attempt to find a better match only when the current match is strictly smaller + /// than this value. This mechanism is used only for compression levels >= 4. + pub(crate) max_lazy_match: usize, + + /// Window position at the beginning of the current output block. Gets + /// negative when the window is moved backwards. + pub(crate) block_start: isize, + + /// Whether or not a block is currently open for the QUICK deflation scheme. + /// true if there is an active block, or false if the block was just closed + pub(crate) block_open: u8, + + pub(crate) window: Window<'a>, + + pub(crate) sym_buf: ReadBuf<'a>, + + /// Size of match buffer for literals/lengths. There are 4 reasons for + /// limiting lit_bufsize to 64K: + /// - frequencies can be kept in 16 bit counters + /// - if compression is not successful for the first block, all input + /// data is still in the window so we can still emit a stored block even + /// when input comes from standard input. (This can also be done for + /// all blocks if lit_bufsize is not greater than 32K.) + /// - if compression is not successful for a file smaller than 64K, we can + /// even emit a stored file instead of a stored block (saving 5 bytes). + /// This is applicable only for zip (not gzip or zlib). + /// - creating new Huffman trees less frequently may not provide fast + /// adaptation to changes in the input data statistics. (Take for + /// example a binary file with poorly compressible code followed by + /// a highly compressible string table.) Smaller buffer sizes give + /// fast adaptation but have of course the overhead of transmitting + /// trees more frequently. + /// - I can't count above 4 + lit_bufsize: usize, + + /// Actual size of window: 2*wSize, except when the user input buffer is directly used as sliding window. + pub(crate) window_size: usize, + + /// number of string matches in current block + pub(crate) matches: usize, + + /// bit length of current block with optimal trees + opt_len: usize, + /// bit length of current block with static trees + static_len: usize, + + /// bytes at end of window left to insert + pub(crate) insert: usize, + + pub(crate) w_size: usize, /* LZ77 window size (32K by default) */ + pub(crate) w_bits: usize, /* log2(w_size) (8..16) */ + pub(crate) w_mask: usize, /* w_size - 1 */ + pub(crate) lookahead: usize, /* number of valid bytes ahead in window */ + + pub(crate) prev: &'a mut [u16], + pub(crate) head: &'a mut [u16; HASH_SIZE], + + /// hash index of string to be inserted + pub(crate) ins_h: usize, + + heap: Heap, + + pub(crate) hash_calc_variant: HashCalcVariant, + + crc_fold: crate::crc32::Crc32Fold, + gzhead: Option<&'a mut gz_header>, + gzindex: usize, +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, Default)] +#[cfg_attr(feature = "__internal-fuzz", derive(arbitrary::Arbitrary))] +pub enum Strategy { + #[default] + Default = 0, + Filtered = 1, + HuffmanOnly = 2, + Rle = 3, + Fixed = 4, +} + +impl TryFrom for Strategy { + type Error = (); + + fn try_from(value: i32) -> Result { + match value { + 0 => Ok(Strategy::Default), + 1 => Ok(Strategy::Filtered), + 2 => Ok(Strategy::HuffmanOnly), + 3 => Ok(Strategy::Rle), + 4 => Ok(Strategy::Fixed), + _ => Err(()), + } + } +} + +#[derive(Debug, PartialEq, Eq)] +enum DataType { + Binary = 0, + Text = 1, + Unknown = 2, +} + +impl<'a> State<'a> { + pub const BIT_BUF_SIZE: u8 = BitWriter::BIT_BUF_SIZE; + + pub(crate) fn max_dist(&self) -> usize { + self.w_size - MIN_LOOKAHEAD + } + + // TODO untangle this mess! zlib uses the same field differently based on compression level + // we should just have 2 fields for clarity! + pub(crate) fn max_insert_length(&self) -> usize { + self.max_lazy_match + } + + /// Total size of the pending buf. But because `pending` shares memory with `sym_buf`, this is + /// not the number of bytes that are actually in `pending`! + pub(crate) fn pending_buf_size(&self) -> usize { + self.lit_bufsize * 4 + } + + pub(crate) fn update_hash(&self, h: u32, val: u32) -> u32 { + match self.hash_calc_variant { + HashCalcVariant::Standard => StandardHashCalc::update_hash(h, val), + HashCalcVariant::Crc32 => Crc32HashCalc::update_hash(h, val), + HashCalcVariant::Roll => RollHashCalc::update_hash(h, val), + } + } + + pub(crate) fn quick_insert_string(&mut self, string: usize) -> u16 { + match self.hash_calc_variant { + HashCalcVariant::Standard => StandardHashCalc::quick_insert_string(self, string), + HashCalcVariant::Crc32 => Crc32HashCalc::quick_insert_string(self, string), + HashCalcVariant::Roll => RollHashCalc::quick_insert_string(self, string), + } + } + + pub(crate) fn insert_string(&mut self, string: usize, count: usize) { + match self.hash_calc_variant { + HashCalcVariant::Standard => StandardHashCalc::insert_string(self, string, count), + HashCalcVariant::Crc32 => Crc32HashCalc::insert_string(self, string, count), + HashCalcVariant::Roll => RollHashCalc::insert_string(self, string, count), + } + } + + pub(crate) fn tally_lit(&mut self, unmatched: u8) -> bool { + self.sym_buf.push(0); + self.sym_buf.push(0); + self.sym_buf.push(unmatched); + + *self.l_desc.dyn_tree[unmatched as usize].freq_mut() += 1; + + assert!( + unmatched as usize <= STD_MAX_MATCH - STD_MIN_MATCH, + "zng_tr_tally: bad literal" + ); + + // signal that the current block should be flushed + self.sym_buf.len() == self.sym_buf.capacity() - 3 + } + + const fn d_code(dist: usize) -> u8 { + let index = if dist < 256 { dist } else { 256 + (dist >> 7) }; + self::trees_tbl::DIST_CODE[index] + } + + pub(crate) fn tally_dist(&mut self, mut dist: usize, len: usize) -> bool { + let symbols = [dist as u8, (dist >> 8) as u8, len as u8]; + self.sym_buf.extend(&symbols); + + self.matches += 1; + dist -= 1; + + assert!( + dist < self.max_dist() && Self::d_code(dist) < D_CODES as u8, + "tally_dist: bad match" + ); + + let index = self::trees_tbl::LENGTH_CODE[len] as usize + LITERALS + 1; + *self.l_desc.dyn_tree[index].freq_mut() += 1; + + *self.d_desc.dyn_tree[Self::d_code(dist) as usize].freq_mut() += 1; + + // signal that the current block should be flushed + self.sym_buf.len() == self.sym_buf.capacity() - 3 + } + + fn detect_data_type(dyn_tree: &[Value]) -> DataType { + // set bits 0..6, 14..25, and 28..31 + // 0xf3ffc07f = binary 11110011111111111100000001111111 + const NON_TEXT: u64 = 0xf3ffc07f; + let mut mask = NON_TEXT; + + /* Check for non-textual bytes. */ + for value in &dyn_tree[0..32] { + if (mask & 1) != 0 && value.freq() != 0 { + return DataType::Binary; + } + + mask >>= 1; + } + + /* Check for textual bytes. */ + if dyn_tree[9].freq() != 0 || dyn_tree[10].freq() != 0 || dyn_tree[13].freq() != 0 { + return DataType::Text; + } + + if dyn_tree[32..LITERALS].iter().any(|v| v.freq() != 0) { + return DataType::Text; + } + + // there are no explicit text or non-text bytes. The stream is either empty or has only + // tolerated bytes + DataType::Binary + } + + fn compress_block_static_trees(&mut self) { + self.bit_writer.compress_block_help( + self.sym_buf.filled(), + self::trees_tbl::STATIC_LTREE.as_slice(), + self::trees_tbl::STATIC_DTREE.as_slice(), + ) + } + + fn compress_block_dynamic_trees(&mut self) { + self.bit_writer.compress_block_help( + self.sym_buf.filled(), + &self.l_desc.dyn_tree, + &self.d_desc.dyn_tree, + ); + } + + fn header(&self) -> u16 { + // preset dictionary flag in zlib header + const PRESET_DICT: u16 = 0x20; + + // The deflate compression method (the only one supported in this version) + const Z_DEFLATED: u16 = 8; + + let dict = match self.strstart { + 0 => 0, + _ => PRESET_DICT, + }; + + let h = + (Z_DEFLATED + ((self.w_bits as u16 - 8) << 4)) << 8 | (self.level_flags() << 6) | dict; + + h + 31 - (h % 31) + } + + fn level_flags(&self) -> u16 { + if self.strategy >= Strategy::HuffmanOnly || self.level < 2 { + 0 + } else if self.level < 6 { + 1 + } else if self.level == 6 { + 2 + } else { + 3 + } + } + + fn zng_tr_init(&mut self) { + self.l_desc.stat_desc = &StaticTreeDesc::L; + + self.d_desc.stat_desc = &StaticTreeDesc::D; + + self.bl_desc.stat_desc = &StaticTreeDesc::BL; + + self.bit_writer.bit_buffer = 0; + self.bit_writer.bits_used = 0; + + // Initialize the first block of the first file: + self.init_block(); + } + + /// initializes a new block + fn init_block(&mut self) { + // Initialize the trees. + // TODO would a memset also work here? + + for value in &mut self.l_desc.dyn_tree[..L_CODES] { + *value.freq_mut() = 0; + } + + for value in &mut self.d_desc.dyn_tree[..D_CODES] { + *value.freq_mut() = 0; + } + + for value in &mut self.bl_desc.dyn_tree[..BL_CODES] { + *value.freq_mut() = 0; + } + + // end of block literal code + const END_BLOCK: usize = 256; + + *self.l_desc.dyn_tree[END_BLOCK].freq_mut() = 1; + self.opt_len = 0; + self.static_len = 0; + self.sym_buf.clear(); + self.matches = 0; + } +} + +#[repr(u8)] +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +enum Status { + Init = 1, + + GZip = 4, + Extra = 5, + Name = 6, + Comment = 7, + Hcrc = 8, + + Busy = 2, + Finish = 3, +} + +const fn error_message(return_code: ReturnCode) -> *const core::ffi::c_char { + const TABLE: [&str; 10] = [ + "need dictionary\0", /* Z_NEED_DICT 2 */ + "stream end\0", /* Z_STREAM_END 1 */ + "\0", /* Z_OK 0 */ + "file error\0", /* Z_ERRNO (-1) */ + "stream error\0", /* Z_STREAM_ERROR (-2) */ + "data error\0", /* Z_DATA_ERROR (-3) */ + "insufficient memory\0", /* Z_MEM_ERROR (-4) */ + "buffer error\0", /* Z_BUF_ERROR (-5) */ + "incompatible version\0", /* Z_VERSION_ERROR (-6) */ + "\0", + ]; + + let index = (ReturnCode::NeedDict as i32 - return_code as i32) as usize; + + TABLE[index].as_ptr().cast() +} + +const fn rank_flush(f: i32) -> i32 { + // rank Z_BLOCK between Z_NO_FLUSH and Z_PARTIAL_FLUSH + ((f) * 2) - (if (f) > 4 { 9 } else { 0 }) +} + +#[derive(Debug)] +pub(crate) enum BlockState { + /// block not completed, need more input or more output + NeedMore = 0, + /// block flush performed + BlockDone = 1, + /// finish started, need only more output at next deflate + FinishStarted = 2, + /// finish done, accept no more input or output + FinishDone = 3, +} + +// Maximum stored block length in deflate format (not including header). +pub(crate) const MAX_STORED: usize = 65535; // so u16::max + +pub(crate) fn read_buf_window(stream: &mut DeflateStream, offset: usize, size: usize) -> usize { + let len = Ord::min(stream.avail_in as usize, size); + + if len == 0 { + return 0; + } + + stream.avail_in -= len as u32; + + if stream.state.wrap == 2 { + // we likely cannot fuse the crc32 and the copy here because the input can be changed by + // a concurrent thread. Therefore it cannot be converted into a slice! + let window = &mut stream.state.window; + window.initialize_at_least(offset + len); + unsafe { window.copy_and_initialize(offset..offset + len, stream.next_in) }; + + let data = &stream.state.window.filled()[offset..][..len]; + stream.state.crc_fold.fold(data, CRC32_INITIAL_VALUE); + } else if stream.state.wrap == 1 { + // we likely cannot fuse the adler32 and the copy here because the input can be changed by + // a concurrent thread. Therefore it cannot be converted into a slice! + let window = &mut stream.state.window; + window.initialize_at_least(offset + len); + unsafe { window.copy_and_initialize(offset..offset + len, stream.next_in) }; + + let data = &stream.state.window.filled()[offset..][..len]; + stream.adler = adler32(stream.adler as u32, data) as _; + } else { + let window = &mut stream.state.window; + window.initialize_at_least(offset + len); + unsafe { window.copy_and_initialize(offset..offset + len, stream.next_in) }; + } + + stream.next_in = stream.next_in.wrapping_add(len); + stream.total_in += len as crate::c_api::z_size; + + len +} + +pub(crate) enum BlockType { + StoredBlock = 0, + StaticTrees = 1, + DynamicTrees = 2, +} + +pub(crate) fn zng_tr_stored_block( + state: &mut State, + window_range: core::ops::Range, + is_last: bool, +) { + // send block type + state.bit_writer.emit_tree(BlockType::StoredBlock, is_last); + + // align on byte boundary + state.bit_writer.flush_and_align_bits(); + + // cmpr_bits_align(s); + + let input_block: &[u8] = &state.window.filled()[window_range]; + let stored_len = input_block.len() as u16; + + state.bit_writer.pending.extend(&stored_len.to_le_bytes()); + state + .bit_writer + .pending + .extend(&(!stored_len).to_le_bytes()); + + // cmpr_bits_add(s, 32); + // sent_bits_add(s, 32); + if stored_len > 0 { + state.bit_writer.pending.extend(input_block); + // cmpr_bits_add(s, stored_len << 3); + // sent_bits_add(s, stored_len << 3); + } +} + +/// The minimum match length mandated by the deflate standard +pub(crate) const STD_MIN_MATCH: usize = 3; +/// The maximum match length mandated by the deflate standard +pub(crate) const STD_MAX_MATCH: usize = 258; + +/// The minimum wanted match length, affects deflate_quick, deflate_fast, deflate_medium and deflate_slow +pub(crate) const WANT_MIN_MATCH: usize = 4; + +pub(crate) const MIN_LOOKAHEAD: usize = STD_MAX_MATCH + STD_MIN_MATCH + 1; + +pub(crate) fn fill_window(stream: &mut DeflateStream) { + debug_assert!(stream.state.lookahead < MIN_LOOKAHEAD); + + let wsize = stream.state.w_size; + + loop { + let state = &mut stream.state; + let mut more = state.window_size - state.lookahead - state.strstart; + + // If the window is almost full and there is insufficient lookahead, + // move the upper half to the lower one to make room in the upper half. + if state.strstart >= wsize + state.max_dist() { + // in some cases zlib-ng copies uninitialized bytes here. We cannot have that, so + // explicitly initialize them with zeros. + // + // see also the "fill_window_out_of_bounds" test. + state.window.initialize_at_least(2 * wsize); + state.window.filled_mut().copy_within(wsize..2 * wsize, 0); + + if state.match_start >= wsize { + state.match_start -= wsize; + } else { + state.match_start = 0; + state.prev_length = 0; + } + state.strstart -= wsize; /* we now have strstart >= MAX_DIST */ + state.block_start -= wsize as isize; + if state.insert > state.strstart { + state.insert = state.strstart; + } + + self::slide_hash::slide_hash(state); + + more += wsize; + } + + if stream.avail_in == 0 { + break; + } + + // If there was no sliding: + // strstart <= WSIZE+MAX_DIST-1 && lookahead <= MIN_LOOKAHEAD - 1 && + // more == window_size - lookahead - strstart + // => more >= window_size - (MIN_LOOKAHEAD-1 + WSIZE + MAX_DIST-1) + // => more >= window_size - 2*WSIZE + 2 + // In the BIG_MEM or MMAP case (not yet supported), + // window_size == input_size + MIN_LOOKAHEAD && + // strstart + s->lookahead <= input_size => more >= MIN_LOOKAHEAD. + // Otherwise, window_size == 2*WSIZE so more >= 2. + // If there was sliding, more >= WSIZE. So in all cases, more >= 2. + assert!(more >= 2, "more < 2"); + + let n = read_buf_window(stream, stream.state.strstart + stream.state.lookahead, more); + + let state = &mut stream.state; + state.lookahead += n; + + // Initialize the hash value now that we have some input: + if state.lookahead + state.insert >= STD_MIN_MATCH { + let string = state.strstart - state.insert; + if state.max_chain_length > 1024 { + let v0 = state.window.filled()[string] as u32; + let v1 = state.window.filled()[string + 1] as u32; + state.ins_h = state.update_hash(v0, v1) as usize; + } else if string >= 1 { + state.quick_insert_string(string + 2 - STD_MIN_MATCH); + } + let mut count = state.insert; + if state.lookahead == 1 { + count -= 1; + } + if count > 0 { + state.insert_string(string, count); + state.insert -= count; + } + } + + // If the whole input has less than STD_MIN_MATCH bytes, ins_h is garbage, + // but this is not important since only literal bytes will be emitted. + + if !(stream.state.lookahead < MIN_LOOKAHEAD && stream.avail_in != 0) { + break; + } + } + + // initialize some memory at the end of the (filled) window, so SIMD operations can go "out of + // bounds" without violating any requirements. The window allocation is already slightly bigger + // to allow for this. + stream.state.window.initialize_out_of_bounds(); + + assert!( + stream.state.strstart <= stream.state.window_size - MIN_LOOKAHEAD, + "not enough room for search" + ); +} + +pub(crate) struct StaticTreeDesc { + /// static tree or NULL + pub(crate) static_tree: &'static [Value], + /// extra bits for each code or NULL + extra_bits: &'static [u8], + /// base index for extra_bits + extra_base: usize, + /// max number of elements in the tree + elems: usize, + /// max bit length for the codes + max_length: u16, +} + +impl StaticTreeDesc { + const EMPTY: Self = Self { + static_tree: &[], + extra_bits: &[], + extra_base: 0, + elems: 0, + max_length: 0, + }; + + /// extra bits for each length code + const EXTRA_LBITS: [u8; LENGTH_CODES] = [ + 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0, + ]; + + /// extra bits for each distance code + const EXTRA_DBITS: [u8; D_CODES] = [ + 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, + ]; + + /// extra bits for each bit length code + const EXTRA_BLBITS: [u8; BL_CODES] = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 3, 7]; + + /// The lengths of the bit length codes are sent in order of decreasing + /// probability, to avoid transmitting the lengths for unused bit length codes. + const BL_ORDER: [u8; BL_CODES] = [ + 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15, + ]; + + pub(crate) const L: Self = Self { + static_tree: &self::trees_tbl::STATIC_LTREE, + extra_bits: &Self::EXTRA_LBITS, + extra_base: LITERALS + 1, + elems: L_CODES, + max_length: MAX_BITS as u16, + }; + + pub(crate) const D: Self = Self { + static_tree: &self::trees_tbl::STATIC_DTREE, + extra_bits: &Self::EXTRA_DBITS, + extra_base: 0, + elems: D_CODES, + max_length: MAX_BITS as u16, + }; + + pub(crate) const BL: Self = Self { + static_tree: &[], + extra_bits: &Self::EXTRA_BLBITS, + extra_base: 0, + elems: BL_CODES, + max_length: MAX_BL_BITS as u16, + }; +} + +#[derive(Clone)] +struct TreeDesc { + dyn_tree: [Value; N], + max_code: usize, + stat_desc: &'static StaticTreeDesc, +} + +impl TreeDesc { + const EMPTY: Self = Self { + dyn_tree: [Value::new(0, 0); N], + max_code: 0, + stat_desc: &StaticTreeDesc::EMPTY, + }; +} + +fn build_tree(state: &mut State, desc: &mut TreeDesc) { + let tree = &mut desc.dyn_tree; + let stree = desc.stat_desc.static_tree; + let elements = desc.stat_desc.elems; + + let mut max_code = state.heap.initialize(&mut tree[..elements]); + + // The pkzip format requires that at least one distance code exists, + // and that at least one bit should be sent even if there is only one + // possible code. So to avoid special checks later on we force at least + // two codes of non zero frequency. + while state.heap.heap_len < 2 { + state.heap.heap_len += 1; + let node = if max_code < 2 { + max_code += 1; + max_code + } else { + 0 + }; + + debug_assert!(node >= 0); + let node = node as usize; + + state.heap.heap[state.heap.heap_len] = node as u32; + *tree[node].freq_mut() = 1; + state.heap.depth[node] = 0; + state.opt_len -= 1; + if !stree.is_empty() { + state.static_len -= stree[node].len() as usize; + } + /* node is 0 or 1 so it does not have extra bits */ + } + + debug_assert!(max_code >= 0); + let max_code = max_code as usize; + desc.max_code = max_code; + + // The elements heap[heap_len/2+1 .. heap_len] are leaves of the tree, + // establish sub-heaps of increasing lengths: + let mut n = state.heap.heap_len / 2; + while n >= 1 { + state.heap.pqdownheap(tree, n); + n -= 1; + } + + state.heap.construct_huffman_tree(tree, elements); + + // At this point, the fields freq and dad are set. We can now + // generate the bit lengths. + gen_bitlen(state, desc); + + // The field len is now set, we can generate the bit codes + gen_codes(&mut desc.dyn_tree, max_code, &state.bl_count); +} + +fn gen_bitlen(state: &mut State, desc: &mut TreeDesc) { + let heap = &mut state.heap; + + let tree = &mut desc.dyn_tree; + let max_code = desc.max_code; + let stree = desc.stat_desc.static_tree; + let extra = desc.stat_desc.extra_bits; + let base = desc.stat_desc.extra_base; + let max_length = desc.stat_desc.max_length; + + state.bl_count.fill(0); + + // In a first pass, compute the optimal bit lengths (which may + // overflow in the case of the bit length tree). + *tree[heap.heap[heap.heap_max] as usize].len_mut() = 0; /* root of the heap */ + + // number of elements with bit length too large + let mut overflow: i32 = 0; + + for h in heap.heap_max + 1..HEAP_SIZE { + let n = heap.heap[h] as usize; + let mut bits = tree[tree[n].dad() as usize].len() + 1; + + if bits > max_length { + bits = max_length; + overflow += 1; + } + + // We overwrite tree[n].Dad which is no longer needed + *tree[n].len_mut() = bits; + + // not a leaf node + if n > max_code { + continue; + } + + state.bl_count[bits as usize] += 1; + let mut xbits = 0; + if n >= base { + xbits = extra[n - base] as usize; + } + + let f = tree[n].freq() as usize; + state.opt_len += f * (bits as usize + xbits); + + if !stree.is_empty() { + state.static_len += f * (stree[n].len() as usize + xbits); + } + } + + if overflow == 0 { + return; + } + + /* Find the first bit length which could increase: */ + loop { + let mut bits = max_length as usize - 1; + while state.bl_count[bits] == 0 { + bits -= 1; + } + state.bl_count[bits] -= 1; /* move one leaf down the tree */ + state.bl_count[bits + 1] += 2; /* move one overflow item as its brother */ + state.bl_count[max_length as usize] -= 1; + /* The brother of the overflow item also moves one step up, + * but this does not affect bl_count[max_length] + */ + overflow -= 2; + + if overflow <= 0 { + break; + } + } + + // Now recompute all bit lengths, scanning in increasing frequency. + // h is still equal to HEAP_SIZE. (It is simpler to reconstruct all + // lengths instead of fixing only the wrong ones. This idea is taken + // from 'ar' written by Haruhiko Okumura.) + let mut h = HEAP_SIZE; + for bits in (1..=max_length).rev() { + let mut n = state.bl_count[bits as usize]; + while n != 0 { + h -= 1; + let m = heap.heap[h] as usize; + if m > max_code { + continue; + } + + if tree[m].len() != bits { + // Tracev((stderr, "code %d bits %d->%u\n", m, tree[m].Len, bits)); + state.opt_len += (bits * tree[m].freq()) as usize; + state.opt_len -= (tree[m].len() * tree[m].freq()) as usize; + *tree[m].len_mut() = bits; + } + + n -= 1; + } + } +} + +/// Checks that symbol is a printing character (excluding space) +#[allow(unused)] +fn isgraph(c: u8) -> bool { + (c > 0x20) && (c <= 0x7E) +} + +fn gen_codes(tree: &mut [Value], max_code: usize, bl_count: &[u16]) { + /* tree: the tree to decorate */ + /* max_code: largest code with non zero frequency */ + /* bl_count: number of codes at each bit length */ + let mut next_code = [0; MAX_BITS + 1]; /* next code value for each bit length */ + let mut code = 0; /* running code value */ + + /* The distribution counts are first used to generate the code values + * without bit reversal. + */ + for bits in 1..=MAX_BITS { + code = (code + bl_count[bits - 1]) << 1; + next_code[bits] = code; + } + + /* Check that the bit counts in bl_count are consistent. The last code + * must be all ones. + */ + assert!( + code + bl_count[MAX_BITS] - 1 == (1 << MAX_BITS) - 1, + "inconsistent bit counts" + ); + + trace!("\ngen_codes: max_code {max_code} "); + + for n in 0..=max_code { + let len = tree[n].len(); + if len == 0 { + continue; + } + + /* Now reverse the bits */ + assert!((1..=15).contains(&len), "code length must be 1-15"); + *tree[n].code_mut() = next_code[len as usize].reverse_bits() >> (16 - len); + next_code[len as usize] += 1; + + if tree != self::trees_tbl::STATIC_LTREE.as_slice() { + trace!( + "\nn {:>3} {} l {:>2} c {:>4x} ({:x}) ", + n, + if isgraph(n as u8) { + char::from_u32(n as u32).unwrap() + } else { + ' ' + }, + len, + tree[n].code(), + next_code[len as usize] - 1 + ); + } + } +} + +/// repeat previous bit length 3-6 times (2 bits of repeat count) +const REP_3_6: usize = 16; + +/// repeat a zero length 3-10 times (3 bits of repeat count) +const REPZ_3_10: usize = 17; + +/// repeat a zero length 11-138 times (7 bits of repeat count) +const REPZ_11_138: usize = 18; + +fn scan_tree(bl_desc: &mut TreeDesc<{ 2 * BL_CODES + 1 }>, tree: &mut [Value], max_code: usize) { + /* tree: the tree to be scanned */ + /* max_code: and its largest code of non zero frequency */ + let mut prevlen = -1isize; /* last emitted length */ + let mut curlen: isize; /* length of current code */ + let mut nextlen = tree[0].len(); /* length of next code */ + let mut count = 0; /* repeat count of the current code */ + let mut max_count = 7; /* max repeat count */ + let mut min_count = 4; /* min repeat count */ + + if nextlen == 0 { + max_count = 138; + min_count = 3; + } + + *tree[max_code + 1].len_mut() = 0xffff; /* guard */ + + let bl_tree = &mut bl_desc.dyn_tree; + + for n in 0..=max_code { + curlen = nextlen as isize; + nextlen = tree[n + 1].len(); + count += 1; + if count < max_count && curlen == nextlen as isize { + continue; + } else if count < min_count { + *bl_tree[curlen as usize].freq_mut() += count; + } else if curlen != 0 { + if curlen != prevlen { + *bl_tree[curlen as usize].freq_mut() += 1; + } + *bl_tree[REP_3_6].freq_mut() += 1; + } else if count <= 10 { + *bl_tree[REPZ_3_10].freq_mut() += 1; + } else { + *bl_tree[REPZ_11_138].freq_mut() += 1; + } + + count = 0; + prevlen = curlen; + + if nextlen == 0 { + max_count = 138; + min_count = 3; + } else if curlen == nextlen as isize { + max_count = 6; + min_count = 3; + } else { + max_count = 7; + min_count = 4; + } + } +} + +fn send_all_trees(state: &mut State, lcodes: usize, dcodes: usize, blcodes: usize) { + assert!( + lcodes >= 257 && dcodes >= 1 && blcodes >= 4, + "not enough codes" + ); + assert!( + lcodes <= L_CODES && dcodes <= D_CODES && blcodes <= BL_CODES, + "too many codes" + ); + + trace!("\nbl counts: "); + state.bit_writer.send_bits(lcodes as u64 - 257, 5); /* not +255 as stated in appnote.txt */ + state.bit_writer.send_bits(dcodes as u64 - 1, 5); + state.bit_writer.send_bits(blcodes as u64 - 4, 4); /* not -3 as stated in appnote.txt */ + + for rank in 0..blcodes { + trace!("\nbl code {:>2} ", StaticTreeDesc::BL_ORDER[rank]); + state.bit_writer.send_bits( + state.bl_desc.dyn_tree[StaticTreeDesc::BL_ORDER[rank] as usize].len() as u64, + 3, + ); + } + // trace!("\nbl tree: sent {}", state.bits_sent); + + // literal tree + state + .bit_writer + .send_tree(&state.l_desc.dyn_tree, &state.bl_desc.dyn_tree, lcodes - 1); + // trace!("\nlit tree: sent {}", state.bits_sent); + + // distance tree + state + .bit_writer + .send_tree(&state.d_desc.dyn_tree, &state.bl_desc.dyn_tree, dcodes - 1); + // trace!("\ndist tree: sent {}", state.bits_sent); +} + +/// Construct the Huffman tree for the bit lengths and return the index in +/// bl_order of the last bit length code to send. +fn build_bl_tree(state: &mut State) -> usize { + /* Determine the bit length frequencies for literal and distance trees */ + + scan_tree( + &mut state.bl_desc, + &mut state.l_desc.dyn_tree, + state.l_desc.max_code, + ); + + scan_tree( + &mut state.bl_desc, + &mut state.d_desc.dyn_tree, + state.d_desc.max_code, + ); + + /* Build the bit length tree: */ + { + let mut tmp = TreeDesc::EMPTY; + core::mem::swap(&mut tmp, &mut state.bl_desc); + build_tree(state, &mut tmp); + core::mem::swap(&mut tmp, &mut state.bl_desc); + } + + /* opt_len now includes the length of the tree representations, except + * the lengths of the bit lengths codes and the 5+5+4 bits for the counts. + */ + + /* Determine the number of bit length codes to send. The pkzip format + * requires that at least 4 bit length codes be sent. (appnote.txt says + * 3 but the actual value used is 4.) + */ + let mut max_blindex = BL_CODES - 1; + while max_blindex >= 3 { + let index = StaticTreeDesc::BL_ORDER[max_blindex] as usize; + if state.bl_desc.dyn_tree[index].len() != 0 { + break; + } + + max_blindex -= 1; + } + + /* Update opt_len to include the bit length tree and counts */ + state.opt_len += 3 * (max_blindex + 1) + 5 + 5 + 4; + // Tracev((stderr, "\ndyn trees: dyn %lu, stat %lu", s->opt_len, s->static_len)); + + max_blindex +} + +fn zng_tr_flush_block( + stream: &mut DeflateStream, + window_offset: Option, + stored_len: u32, + last: bool, +) { + /* window_offset: offset of the input block into the window */ + /* stored_len: length of input block */ + /* last: one if this is the last block for a file */ + + let mut opt_lenb; + let static_lenb; + let mut max_blindex = 0; + + let state = &mut stream.state; + + if state.sym_buf.is_empty() { + opt_lenb = 0; + static_lenb = 0; + state.static_len = 7; + } else if state.level > 0 { + if stream.data_type == DataType::Unknown as i32 { + stream.data_type = State::detect_data_type(&state.l_desc.dyn_tree) as i32; + } + + { + let mut tmp = TreeDesc::EMPTY; + core::mem::swap(&mut tmp, &mut state.l_desc); + + build_tree(state, &mut tmp); + core::mem::swap(&mut tmp, &mut state.l_desc); + + trace!( + "\nlit data: dyn {}, stat {}", + state.opt_len, + state.static_len + ); + } + + { + let mut tmp = TreeDesc::EMPTY; + core::mem::swap(&mut tmp, &mut state.d_desc); + build_tree(state, &mut tmp); + core::mem::swap(&mut tmp, &mut state.d_desc); + + trace!( + "\nlit data: dyn {}, stat {}", + state.opt_len, + state.static_len + ); + } + + // Build the bit length tree for the above two trees, and get the index + // in bl_order of the last bit length code to send. + max_blindex = build_bl_tree(state); + + // Determine the best encoding. Compute the block lengths in bytes. + opt_lenb = (state.opt_len + 3 + 7) >> 3; + static_lenb = (state.static_len + 3 + 7) >> 3; + + // Tracev((stderr, "\nopt %lu(%lu) stat %lu(%lu) stored %u lit %u ", + // opt_lenb, state.opt_len, static_lenb, state.static_len, stored_len, + // state.sym_next / 3)); + + if static_lenb <= opt_lenb || state.strategy == Strategy::Fixed { + opt_lenb = static_lenb; + } + } else { + assert!(window_offset.is_some(), "lost buf"); + /* force a stored block */ + opt_lenb = stored_len as usize + 5; + static_lenb = stored_len as usize + 5; + } + + if stored_len as usize + 4 <= opt_lenb && window_offset.is_some() { + /* 4: two words for the lengths + * The test buf != NULL is only necessary if LIT_BUFSIZE > WSIZE. + * Otherwise we can't have processed more than WSIZE input bytes since + * the last block flush, because compression would have been + * successful. If LIT_BUFSIZE <= WSIZE, it is never too late to + * transform a block into a stored block. + */ + let window_offset = window_offset.unwrap(); + let range = window_offset..window_offset + stored_len as usize; + zng_tr_stored_block(state, range, last); + } else if static_lenb == opt_lenb { + state.bit_writer.emit_tree(BlockType::StaticTrees, last); + state.compress_block_static_trees(); + // cmpr_bits_add(s, s.static_len); + } else { + state.bit_writer.emit_tree(BlockType::DynamicTrees, last); + send_all_trees( + state, + state.l_desc.max_code + 1, + state.d_desc.max_code + 1, + max_blindex + 1, + ); + + state.compress_block_dynamic_trees(); + } + + // TODO + // This check is made mod 2^32, for files larger than 512 MB and unsigned long implemented on 32 bits. + // assert_eq!(state.compressed_len, state.bits_sent, "bad compressed size"); + + state.init_block(); + if last { + state.bit_writer.flush_and_align_bits(); + } + + // Tracev((stderr, "\ncomprlen %lu(%lu) ", s->compressed_len>>3, s->compressed_len-7*last)); +} + +pub(crate) fn flush_block_only(stream: &mut DeflateStream, is_last: bool) { + zng_tr_flush_block( + stream, + (stream.state.block_start >= 0).then_some(stream.state.block_start as usize), + (stream.state.strstart as isize - stream.state.block_start) as u32, + is_last, + ); + + stream.state.block_start = stream.state.strstart as isize; + flush_pending(stream) +} + +#[must_use] +fn flush_bytes(stream: &mut DeflateStream, mut bytes: &[u8]) -> ControlFlow { + let mut state = &mut stream.state; + + // we'll be using the pending buffer as temporary storage + let mut beg = state.bit_writer.pending.pending().len(); /* start of bytes to update crc */ + + while state.bit_writer.pending.remaining() < bytes.len() { + let copy = state.bit_writer.pending.remaining(); + + state.bit_writer.pending.extend(&bytes[..copy]); + + stream.adler = crc32( + stream.adler as u32, + &state.bit_writer.pending.pending()[beg..], + ) as z_checksum; + + state.gzindex += copy; + flush_pending(stream); + state = &mut stream.state; + + // could not flush all the pending output + if !state.bit_writer.pending.pending().is_empty() { + state.last_flush = -1; + return ControlFlow::Break(ReturnCode::Ok); + } + + beg = 0; + bytes = &bytes[copy..]; + } + + state.bit_writer.pending.extend(bytes); + + stream.adler = crc32( + stream.adler as u32, + &state.bit_writer.pending.pending()[beg..], + ) as z_checksum; + state.gzindex = 0; + + ControlFlow::Continue(()) +} + +pub fn deflate(stream: &mut DeflateStream, flush: DeflateFlush) -> ReturnCode { + if stream.next_out.is_null() + || (stream.avail_in != 0 && stream.next_in.is_null()) + || (stream.state.status == Status::Finish && flush != DeflateFlush::Finish) + { + let err = ReturnCode::StreamError; + stream.msg = error_message(err); + return err; + } + + if stream.avail_out == 0 { + let err = ReturnCode::BufError; + stream.msg = error_message(err); + return err; + } + + let old_flush = stream.state.last_flush; + stream.state.last_flush = flush as i32; + + /* Flush as much pending output as possible */ + if !stream.state.bit_writer.pending.pending().is_empty() { + flush_pending(stream); + if stream.avail_out == 0 { + /* Since avail_out is 0, deflate will be called again with + * more output space, but possibly with both pending and + * avail_in equal to zero. There won't be anything to do, + * but this is not an error situation so make sure we + * return OK instead of BUF_ERROR at next call of deflate: + */ + stream.state.last_flush = -1; + return ReturnCode::Ok; + } + + /* Make sure there is something to do and avoid duplicate consecutive + * flushes. For repeated and useless calls with Z_FINISH, we keep + * returning Z_STREAM_END instead of Z_BUF_ERROR. + */ + } else if stream.avail_in == 0 + && rank_flush(flush as i32) <= rank_flush(old_flush) + && flush != DeflateFlush::Finish + { + let err = ReturnCode::BufError; + stream.msg = error_message(err); + return err; + } + + /* User must not provide more input after the first FINISH: */ + if stream.state.status == Status::Finish && stream.avail_in != 0 { + let err = ReturnCode::BufError; + stream.msg = error_message(err); + return err; + } + + /* Write the header */ + if stream.state.status == Status::Init && stream.state.wrap == 0 { + stream.state.status = Status::Busy; + } + + if stream.state.status == Status::Init { + let header = stream.state.header(); + stream + .state + .bit_writer + .pending + .extend(&header.to_be_bytes()); + + /* Save the adler32 of the preset dictionary: */ + if stream.state.strstart != 0 { + let adler = stream.adler as u32; + stream.state.bit_writer.pending.extend(&adler.to_be_bytes()); + } + + stream.adler = ADLER32_INITIAL_VALUE as _; + stream.state.status = Status::Busy; + + // compression must start with an empty pending buffer + flush_pending(stream); + + if !stream.state.bit_writer.pending.pending().is_empty() { + stream.state.last_flush = -1; + + return ReturnCode::Ok; + } + } + + if stream.state.status == Status::GZip { + /* gzip header */ + stream.state.crc_fold = Crc32Fold::new(); + + stream.state.bit_writer.pending.extend(&[31, 139, 8]); + + let extra_flags = if stream.state.level == 9 { + 2 + } else if stream.state.strategy >= Strategy::HuffmanOnly || stream.state.level < 2 { + 4 + } else { + 0 + }; + + match &stream.state.gzhead { + None => { + let bytes = [0, 0, 0, 0, 0, extra_flags, gz_header::OS_CODE]; + stream.state.bit_writer.pending.extend(&bytes); + stream.state.status = Status::Busy; + + /* Compression must start with an empty pending buffer */ + flush_pending(stream); + if !stream.state.bit_writer.pending.pending().is_empty() { + stream.state.last_flush = -1; + return ReturnCode::Ok; + } + } + Some(gzhead) => { + stream.state.bit_writer.pending.extend(&[gzhead.flags()]); + let bytes = (gzhead.time as u32).to_le_bytes(); + stream.state.bit_writer.pending.extend(&bytes); + stream + .state + .bit_writer + .pending + .extend(&[extra_flags, gzhead.os as u8]); + + if !gzhead.extra.is_null() { + let bytes = (gzhead.extra_len as u16).to_le_bytes(); + stream.state.bit_writer.pending.extend(&bytes); + } + + if gzhead.hcrc > 0 { + stream.adler = crc32( + stream.adler as u32, + stream.state.bit_writer.pending.pending(), + ) as z_checksum + } + + stream.state.gzindex = 0; + stream.state.status = Status::Extra; + } + } + } + + if stream.state.status == Status::Extra { + if let Some(gzhead) = stream.state.gzhead.as_ref() { + if !gzhead.extra.is_null() { + let gzhead_extra = gzhead.extra; + + let extra = unsafe { + core::slice::from_raw_parts( + gzhead_extra.add(stream.state.gzindex), + (gzhead.extra_len & 0xffff) as usize - stream.state.gzindex, + ) + }; + + if let ControlFlow::Break(err) = flush_bytes(stream, extra) { + return err; + } + } + } + stream.state.status = Status::Name; + } + + if stream.state.status == Status::Name { + if let Some(gzhead) = stream.state.gzhead.as_ref() { + if !gzhead.name.is_null() { + let gzhead_name = unsafe { CStr::from_ptr(gzhead.name.cast()) }; + let bytes = gzhead_name.to_bytes_with_nul(); + if let ControlFlow::Break(err) = flush_bytes(stream, bytes) { + return err; + } + } + stream.state.status = Status::Comment; + } + } + + if stream.state.status == Status::Comment { + if let Some(gzhead) = stream.state.gzhead.as_ref() { + if !gzhead.comment.is_null() { + let gzhead_comment = unsafe { CStr::from_ptr(gzhead.comment.cast()) }; + let bytes = gzhead_comment.to_bytes_with_nul(); + if let ControlFlow::Break(err) = flush_bytes(stream, bytes) { + return err; + } + } + stream.state.status = Status::Hcrc; + } + } + + if stream.state.status == Status::Hcrc { + if let Some(gzhead) = stream.state.gzhead.as_ref() { + if gzhead.hcrc != 0 { + let bytes = (stream.adler as u16).to_le_bytes(); + if let ControlFlow::Break(err) = flush_bytes(stream, &bytes) { + return err; + } + } + } + + stream.state.status = Status::Busy; + + // compression must start with an empty pending buffer + flush_pending(stream); + if !stream.state.bit_writer.pending.pending().is_empty() { + stream.state.last_flush = -1; + return ReturnCode::Ok; + } + } + + // Start a new block or continue the current one. + let state = &mut stream.state; + if stream.avail_in != 0 + || state.lookahead != 0 + || (flush != DeflateFlush::NoFlush && state.status != Status::Finish) + { + let bstate = self::algorithm::run(stream, flush); + + let state = &mut stream.state; + + if matches!(bstate, BlockState::FinishStarted | BlockState::FinishDone) { + state.status = Status::Finish; + } + + match bstate { + BlockState::NeedMore | BlockState::FinishStarted => { + if stream.avail_out == 0 { + state.last_flush = -1; /* avoid BUF_ERROR next call, see above */ + } + return ReturnCode::Ok; + /* If flush != Z_NO_FLUSH && avail_out == 0, the next call + * of deflate should use the same flush parameter to make sure + * that the flush is complete. So we don't have to output an + * empty block here, this will be done at next call. This also + * ensures that for a very small output buffer, we emit at most + * one empty block. + */ + } + BlockState::BlockDone => { + match flush { + DeflateFlush::NoFlush => unreachable!("condition of inner surrounding if"), + DeflateFlush::PartialFlush => { + state.bit_writer.align(); + } + DeflateFlush::SyncFlush => { + // add an empty stored block that is marked as not final. This is useful for + // parallel deflate where we want to make sure the intermediate blocks are not + // marked as "last block". + zng_tr_stored_block(state, 0..0, false); + } + DeflateFlush::FullFlush => { + // add an empty stored block that is marked as not final. This is useful for + // parallel deflate where we want to make sure the intermediate blocks are not + // marked as "last block". + zng_tr_stored_block(state, 0..0, false); + + state.head.fill(0); // forget history + + if state.lookahead == 0 { + state.strstart = 0; + state.block_start = 0; + state.insert = 0; + } + } + DeflateFlush::Block => { /* fall through */ } + DeflateFlush::Finish => unreachable!("condition of outer surrounding if"), + } + + flush_pending(stream); + + if stream.avail_out == 0 { + stream.state.last_flush = -1; /* avoid BUF_ERROR at next call, see above */ + return ReturnCode::Ok; + } + } + BlockState::FinishDone => { /* do nothing */ } + } + } + + if flush != DeflateFlush::Finish { + return ReturnCode::Ok; + } + + // write the trailer + if stream.state.wrap == 2 { + let crc_fold = core::mem::take(&mut stream.state.crc_fold); + stream.adler = crc_fold.finish() as z_checksum; + + let adler = stream.adler as u32; + stream.state.bit_writer.pending.extend(&adler.to_le_bytes()); + + let total_in = stream.total_in as u32; + stream + .state + .bit_writer + .pending + .extend(&total_in.to_le_bytes()); + } else if stream.state.wrap == 1 { + let adler = stream.adler as u32; + stream.state.bit_writer.pending.extend(&adler.to_be_bytes()); + } + + flush_pending(stream); + + // If avail_out is zero, the application will call deflate again to flush the rest. + if stream.state.wrap > 0 { + stream.state.wrap = -stream.state.wrap; /* write the trailer only once! */ + } + + if stream.state.bit_writer.pending.pending().is_empty() { + assert_eq!(stream.state.bit_writer.bits_used, 0, "bi_buf not flushed"); + return ReturnCode::StreamEnd; + } + ReturnCode::Ok +} + +pub(crate) fn flush_pending(stream: &mut DeflateStream) { + let state = &mut stream.state; + + state.bit_writer.flush_bits(); + + let pending = state.bit_writer.pending.pending(); + let len = Ord::min(pending.len(), stream.avail_out as usize); + + if len == 0 { + return; + } + + trace!("\n[FLUSH {len} bytes]"); + unsafe { core::ptr::copy_nonoverlapping(pending.as_ptr(), stream.next_out, len) }; + + stream.next_out = stream.next_out.wrapping_add(len); + stream.total_out += len as crate::c_api::z_size; + stream.avail_out -= len as crate::c_api::uInt; + + state.bit_writer.pending.advance(len); +} + +pub fn compress_slice<'a>( + output: &'a mut [u8], + input: &[u8], + config: DeflateConfig, +) -> (&'a mut [u8], ReturnCode) { + let output_uninit = unsafe { + core::slice::from_raw_parts_mut(output.as_mut_ptr() as *mut MaybeUninit, output.len()) + }; + + compress(output_uninit, input, config) +} + +pub fn compress<'a>( + output: &'a mut [MaybeUninit], + input: &[u8], + config: DeflateConfig, +) -> (&'a mut [u8], ReturnCode) { + compress_with_flush(output, input, config, DeflateFlush::Finish) +} + +pub fn compress_slice_with_flush<'a>( + output: &'a mut [u8], + input: &[u8], + config: DeflateConfig, + flush: DeflateFlush, +) -> (&'a mut [u8], ReturnCode) { + let output_uninit = unsafe { + core::slice::from_raw_parts_mut(output.as_mut_ptr() as *mut MaybeUninit, output.len()) + }; + + compress_with_flush(output_uninit, input, config, flush) +} + +pub fn compress_with_flush<'a>( + output: &'a mut [MaybeUninit], + input: &[u8], + config: DeflateConfig, + final_flush: DeflateFlush, +) -> (&'a mut [u8], ReturnCode) { + let mut stream = z_stream { + next_in: input.as_ptr() as *mut u8, + avail_in: 0, // for special logic in the first iteration + total_in: 0, + next_out: output.as_mut_ptr() as *mut u8, + avail_out: 0, // for special logic on the first iteration + total_out: 0, + msg: core::ptr::null_mut(), + state: core::ptr::null_mut(), + zalloc: None, + zfree: None, + opaque: core::ptr::null_mut(), + data_type: 0, + adler: 0, + reserved: 0, + }; + + let err = init(&mut stream, config); + if err != ReturnCode::Ok { + return (&mut [], err); + } + + let max = core::ffi::c_uint::MAX as usize; + + let mut left = output.len(); + let mut source_len = input.len(); + + loop { + if stream.avail_out == 0 { + stream.avail_out = Ord::min(left, max) as _; + left -= stream.avail_out as usize; + } + + if stream.avail_in == 0 { + stream.avail_in = Ord::min(source_len, max) as _; + source_len -= stream.avail_in as usize; + } + + let flush = if source_len > 0 { + DeflateFlush::NoFlush + } else { + final_flush + }; + + let err = if let Some(stream) = unsafe { DeflateStream::from_stream_mut(&mut stream) } { + deflate(stream, flush) + } else { + ReturnCode::StreamError + }; + + if err != ReturnCode::Ok { + break; + } + } + + // SAFETY: we have now initialized these bytes + let output_slice = unsafe { + core::slice::from_raw_parts_mut(output.as_mut_ptr() as *mut u8, stream.total_out as usize) + }; + + // may DataError if insufficient output space + let return_code = if let Some(stream) = unsafe { DeflateStream::from_stream_mut(&mut stream) } { + match end(stream) { + Ok(_) => ReturnCode::Ok, + Err(_) => ReturnCode::DataError, + } + } else { + ReturnCode::Ok + }; + + (output_slice, return_code) +} + +pub const fn compress_bound(source_len: usize) -> usize { + compress_bound_help(source_len, ZLIB_WRAPLEN) +} + +const fn compress_bound_help(source_len: usize, wrap_len: usize) -> usize { + source_len // The source size itself */ + // Always at least one byte for any input + .wrapping_add(if source_len == 0 { 1 } else { 0 }) + // One extra byte for lengths less than 9 + .wrapping_add(if source_len < 9 { 1 } else { 0 }) + // Source encoding overhead, padded to next full byte + .wrapping_add(deflate_quick_overhead(source_len)) + // Deflate block overhead bytes + .wrapping_add(DEFLATE_BLOCK_OVERHEAD) + // none, zlib or gzip wrapper + .wrapping_add(wrap_len) +} + +/// heap used to build the Huffman trees + +/// The sons of heap[n] are heap[2*n] and heap[2*n+1]. heap[0] is not used. +/// The same heap array is used to build all trees. +#[derive(Clone)] +struct Heap { + heap: [u32; 2 * L_CODES + 1], + + /// number of elements in the heap + heap_len: usize, + + /// element of the largest frequency + heap_max: usize, + + depth: [u8; 2 * L_CODES + 1], +} + +impl Heap { + // an empty heap + fn new() -> Self { + Self { + heap: [0; 2 * L_CODES + 1], + heap_len: 0, + heap_max: 0, + depth: [0; 2 * L_CODES + 1], + } + } + + /// Construct the initial heap, with least frequent element in + /// heap[SMALLEST]. The sons of heap[n] are heap[2*n] and heap[2*n+1]. heap[0] is not used. + fn initialize(&mut self, tree: &mut [Value]) -> isize { + let mut max_code = -1; + + self.heap_len = 0; + self.heap_max = HEAP_SIZE; + + for (n, node) in tree.iter_mut().enumerate() { + if node.freq() > 0 { + self.heap_len += 1; + self.heap[self.heap_len] = n as u32; + max_code = n as isize; + self.depth[n] = 0; + } else { + *node.len_mut() = 0; + } + } + + max_code + } + + /// Index within the heap array of least frequent node in the Huffman tree + const SMALLEST: usize = 1; + + fn smaller(tree: &[Value], n: u32, m: u32, depth: &[u8]) -> bool { + let (n, m) = (n as usize, m as usize); + + match Ord::cmp(&tree[n].freq(), &tree[m].freq()) { + core::cmp::Ordering::Less => true, + core::cmp::Ordering::Equal => depth[n] <= depth[m], + core::cmp::Ordering::Greater => false, + } + } + + fn pqdownheap(&mut self, tree: &[Value], mut k: usize) { + /* tree: the tree to restore */ + /* k: node to move down */ + + let v = self.heap[k]; + let mut j = k << 1; /* left son of k */ + + while j <= self.heap_len { + /* Set j to the smallest of the two sons: */ + if j < self.heap_len { + let cond = Self::smaller(tree, self.heap[j + 1], self.heap[j], &self.depth); + if cond { + j += 1; + } + } + + /* Exit if v is smaller than both sons */ + if Self::smaller(tree, v, self.heap[j], &self.depth) { + break; + } + + /* Exchange v with the smallest son */ + self.heap[k] = self.heap[j]; + k = j; + + /* And continue down the tree, setting j to the left son of k */ + j <<= 1; + } + + self.heap[k] = v; + } + + /// Remove the smallest element from the heap and recreate the heap with + /// one less element. Updates heap and heap_len. + fn pqremove(&mut self, tree: &[Value]) -> u32 { + let top = self.heap[Self::SMALLEST]; + self.heap[Self::SMALLEST] = self.heap[self.heap_len]; + self.heap_len -= 1; + + self.pqdownheap(tree, Self::SMALLEST); + + top + } + + /// Construct the Huffman tree by repeatedly combining the least two frequent nodes. + fn construct_huffman_tree(&mut self, tree: &mut [Value], mut node: usize) { + loop { + let n = self.pqremove(tree) as usize; /* n = node of least frequency */ + let m = self.heap[Heap::SMALLEST] as usize; /* m = node of next least frequency */ + + self.heap_max -= 1; + self.heap[self.heap_max] = n as u32; /* keep the nodes sorted by frequency */ + self.heap_max -= 1; + self.heap[self.heap_max] = m as u32; + + /* Create a new node father of n and m */ + *tree[node].freq_mut() = tree[n].freq() + tree[m].freq(); + self.depth[node] = Ord::max(self.depth[n], self.depth[m]) + 1; + + *tree[n].dad_mut() = node as u16; + *tree[m].dad_mut() = node as u16; + + /* and insert the new node in the heap */ + self.heap[Heap::SMALLEST] = node as u32; + node += 1; + + self.pqdownheap(tree, Heap::SMALLEST); + + if self.heap_len < 2 { + break; + } + } + + self.heap_max -= 1; + self.heap[self.heap_max] = self.heap[Heap::SMALLEST]; + } +} + +pub fn set_header<'a>( + stream: &mut DeflateStream<'a>, + head: Option<&'a mut gz_header>, +) -> ReturnCode { + if stream.state.wrap != 2 { + ReturnCode::StreamError as _ + } else { + stream.state.gzhead = head; + ReturnCode::Ok as _ + } +} + +// zlib format overhead +const ZLIB_WRAPLEN: usize = 6; +// gzip format overhead +const GZIP_WRAPLEN: usize = 18; + +const DEFLATE_HEADER_BITS: usize = 3; +const DEFLATE_EOBS_BITS: usize = 15; +const DEFLATE_PAD_BITS: usize = 6; +const DEFLATE_BLOCK_OVERHEAD: usize = + (DEFLATE_HEADER_BITS + DEFLATE_EOBS_BITS + DEFLATE_PAD_BITS) >> 3; + +const DEFLATE_QUICK_LIT_MAX_BITS: usize = 9; +const fn deflate_quick_overhead(x: usize) -> usize { + let sum = x + .wrapping_mul(DEFLATE_QUICK_LIT_MAX_BITS - 8) + .wrapping_add(7); + + // imitate zlib-ng rounding behavior (on windows, c_ulong is 32 bits) + (sum as core::ffi::c_ulong >> 3) as usize +} + +/// For the default windowBits of 15 and memLevel of 8, this function returns +/// a close to exact, as well as small, upper bound on the compressed size. +/// They are coded as constants here for a reason--if the #define's are +/// changed, then this function needs to be changed as well. The return +/// value for 15 and 8 only works for those exact settings. +/// +/// For any setting other than those defaults for windowBits and memLevel, +/// the value returned is a conservative worst case for the maximum expansion +/// resulting from using fixed blocks instead of stored blocks, which deflate +/// can emit on compressed data for some combinations of the parameters. +/// +/// This function could be more sophisticated to provide closer upper bounds for +/// every combination of windowBits and memLevel. But even the conservative +/// upper bound of about 14% expansion does not seem onerous for output buffer +/// allocation. +pub fn bound(stream: Option<&mut DeflateStream>, source_len: usize) -> usize { + // on windows, c_ulong is only a 32-bit integer + let mask = core::ffi::c_ulong::MAX as usize; + + // conservative upper bound for compressed data + let comp_len = source_len + .wrapping_add((source_len.wrapping_add(7) & mask) >> 3) + .wrapping_add((source_len.wrapping_add(63) & mask) >> 6) + .wrapping_add(5); + + let Some(stream) = stream else { + // return conservative bound plus zlib wrapper + return comp_len.wrapping_add(6); + }; + + /* compute wrapper length */ + let wrap_len = match stream.state.wrap { + 0 => { + // raw deflate + 0 + } + 1 => { + // zlib wrapper + if stream.state.strstart != 0 { + ZLIB_WRAPLEN + 4 + } else { + ZLIB_WRAPLEN + } + } + 2 => { + // gzip wrapper + let mut gz_wrap_len = GZIP_WRAPLEN; + + if let Some(header) = &stream.state.gzhead { + if !header.extra.is_null() { + gz_wrap_len += 2 + header.extra_len as usize; + } + + let mut c_string = header.name; + if !c_string.is_null() { + loop { + gz_wrap_len += 1; + unsafe { + if *c_string == 0 { + break; + } + c_string = c_string.add(1); + } + } + } + + let mut c_string = header.comment; + if !c_string.is_null() { + loop { + gz_wrap_len += 1; + unsafe { + if *c_string == 0 { + break; + } + c_string = c_string.add(1); + } + } + } + + if header.hcrc != 0 { + gz_wrap_len += 2; + } + } + + gz_wrap_len + } + _ => { + // default + ZLIB_WRAPLEN + } + }; + + if stream.state.w_bits != MAX_WBITS as usize || HASH_BITS < 15 { + if stream.state.level == 0 { + /* upper bound for stored blocks with length 127 (memLevel == 1) ~4% overhead plus a small constant */ + source_len + .wrapping_add(source_len >> 5) + .wrapping_add(source_len >> 7) + .wrapping_add(source_len >> 11) + .wrapping_add(7) + .wrapping_add(wrap_len) + } else { + comp_len.wrapping_add(wrap_len) + } + } else { + compress_bound_help(source_len, wrap_len) + } +} + +#[cfg(test)] +mod test { + use crate::{ + inflate::{uncompress_slice, InflateConfig, InflateStream}, + InflateFlush, + }; + + use super::*; + + use core::{ + ffi::{c_char, c_int, c_uint, CStr}, + sync::atomic::AtomicUsize, + }; + + #[test] + fn detect_data_type_basic() { + let empty = || [Value::new(0, 0); LITERALS]; + + assert_eq!(State::detect_data_type(&empty()), DataType::Binary); + + let mut binary = empty(); + binary[0] = Value::new(1, 0); + assert_eq!(State::detect_data_type(&binary), DataType::Binary); + + let mut text = empty(); + text[b'\r' as usize] = Value::new(1, 0); + assert_eq!(State::detect_data_type(&text), DataType::Text); + + let mut text = empty(); + text[b'a' as usize] = Value::new(1, 0); + assert_eq!(State::detect_data_type(&text), DataType::Text); + + let mut non_text = empty(); + non_text[7] = Value::new(1, 0); + assert_eq!(State::detect_data_type(&non_text), DataType::Binary); + } + + const PAPER_100K: &[u8] = include_bytes!("deflate/test-data/paper-100k.pdf"); + const FIREWORKS: &[u8] = include_bytes!("deflate/test-data/fireworks.jpg"); + const LCET10: &str = include_str!("deflate/test-data/lcet10.txt"); + + #[test] + #[cfg_attr(miri, ignore)] + fn compress_lcet10() { + fuzz_based_test(LCET10.as_bytes(), DeflateConfig::default(), &[]) + } + + #[test] + #[cfg_attr( + target_arch = "aarch64", + ignore = "https://github.com/memorysafety/zlib-rs/issues/91" + )] + #[cfg_attr(miri, ignore)] + fn compress_paper_100k() { + let mut config = DeflateConfig::default(); + + for n in 0..=9 { + config.level = n; + fuzz_based_test(PAPER_100K, config, &[]) + } + } + + #[test] + #[cfg_attr( + target_arch = "aarch64", + ignore = "https://github.com/memorysafety/zlib-rs/issues/91" + )] + #[cfg_attr(miri, ignore)] + fn compress_fireworks() { + let mut config = DeflateConfig::default(); + + for n in 0..=9 { + config.level = n; + fuzz_based_test(FIREWORKS, config, &[]) + } + } + + #[test] + fn from_stream_mut() { + unsafe { + assert!(DeflateStream::from_stream_mut(core::ptr::null_mut()).is_none()); + + let mut stream = z_stream::default(); + assert!(DeflateStream::from_stream_mut(&mut stream).is_none()); + + // state is still NULL + assert!(DeflateStream::from_stream_mut(&mut stream).is_none()); + + init(&mut stream, DeflateConfig::default()); + let stream = DeflateStream::from_stream_mut(&mut stream); + assert!(stream.is_some()); + + assert!(end(stream.unwrap()).is_ok()); + } + } + + unsafe extern "C" fn fail_nth_allocation( + opaque: crate::c_api::voidpf, + items: crate::c_api::uInt, + size: crate::c_api::uInt, + ) -> crate::c_api::voidpf { + let count = unsafe { &*(opaque as *const AtomicUsize) }; + + if count.fetch_add(1, core::sync::atomic::Ordering::Relaxed) != N { + // must use the C allocator internally because (de)allocation is based on function + // pointer values and because we don't use the rust allocator directly, the allocation + // logic will store the pointer to the start at the start of the allocation. + crate::allocate::zalloc_c(opaque, items, size) + } else { + core::ptr::null_mut() + } + } + + #[test] + fn init_invalid_allocator() { + { + let atomic = AtomicUsize::new(0); + let mut stream = z_stream { + zalloc: Some(fail_nth_allocation::<0>), + zfree: Some(crate::allocate::zfree_c), + opaque: &atomic as *const _ as *const core::ffi::c_void as *mut _, + ..z_stream::default() + }; + assert_eq!( + init(&mut stream, DeflateConfig::default()), + ReturnCode::MemError + ); + } + + { + let atomic = AtomicUsize::new(0); + let mut stream = z_stream { + zalloc: Some(fail_nth_allocation::<3>), + zfree: Some(crate::allocate::zfree_c), + opaque: &atomic as *const _ as *const core::ffi::c_void as *mut _, + ..z_stream::default() + }; + assert_eq!( + init(&mut stream, DeflateConfig::default()), + ReturnCode::MemError + ); + } + + { + let atomic = AtomicUsize::new(0); + let mut stream = z_stream { + zalloc: Some(fail_nth_allocation::<5>), + zfree: Some(crate::allocate::zfree_c), + opaque: &atomic as *const _ as *const core::ffi::c_void as *mut _, + ..z_stream::default() + }; + assert_eq!( + init(&mut stream, DeflateConfig::default()), + ReturnCode::MemError + ); + } + } + + mod copy_invalid_allocator { + use super::*; + + #[test] + fn fail_0() { + let mut stream = z_stream::default(); + + let atomic = AtomicUsize::new(0); + stream.opaque = &atomic as *const _ as *const core::ffi::c_void as *mut _; + stream.zalloc = Some(fail_nth_allocation::<6>); + stream.zfree = Some(crate::allocate::zfree_c); + + // init performs 6 allocations; we don't want those to fail + assert_eq!(init(&mut stream, DeflateConfig::default()), ReturnCode::Ok); + + let Some(stream) = (unsafe { DeflateStream::from_stream_mut(&mut stream) }) else { + unreachable!() + }; + + let mut stream_copy = MaybeUninit::::zeroed(); + + assert_eq!(copy(&mut stream_copy, stream), ReturnCode::MemError); + + assert!(end(stream).is_ok()); + } + + #[test] + fn fail_3() { + let mut stream = z_stream::default(); + + let atomic = AtomicUsize::new(0); + stream.zalloc = Some(fail_nth_allocation::<{ 6 + 3 }>); + stream.zfree = Some(crate::allocate::zfree_c); + stream.opaque = &atomic as *const _ as *const core::ffi::c_void as *mut _; + + // init performs 6 allocations; we don't want those to fail + assert_eq!(init(&mut stream, DeflateConfig::default()), ReturnCode::Ok); + + let Some(stream) = (unsafe { DeflateStream::from_stream_mut(&mut stream) }) else { + unreachable!() + }; + + let mut stream_copy = MaybeUninit::::zeroed(); + + assert_eq!(copy(&mut stream_copy, stream), ReturnCode::MemError); + + assert!(end(stream).is_ok()); + } + + #[test] + fn fail_5() { + let mut stream = z_stream::default(); + + let atomic = AtomicUsize::new(0); + stream.zalloc = Some(fail_nth_allocation::<{ 6 + 5 }>); + stream.zfree = Some(crate::allocate::zfree_c); + stream.opaque = &atomic as *const _ as *const core::ffi::c_void as *mut _; + + // init performs 6 allocations; we don't want those to fail + assert_eq!(init(&mut stream, DeflateConfig::default()), ReturnCode::Ok); + + let Some(stream) = (unsafe { DeflateStream::from_stream_mut(&mut stream) }) else { + unreachable!() + }; + + let mut stream_copy = MaybeUninit::::zeroed(); + + assert_eq!(copy(&mut stream_copy, stream), ReturnCode::MemError); + + assert!(end(stream).is_ok()); + } + } + + mod invalid_deflate_config { + use super::*; + + #[test] + fn sanity_check() { + let mut stream = z_stream::default(); + assert_eq!(init(&mut stream, DeflateConfig::default()), ReturnCode::Ok); + + assert!(stream.zalloc.is_some()); + assert!(stream.zfree.is_some()); + + // this should be the default level + let stream = unsafe { DeflateStream::from_stream_mut(&mut stream) }.unwrap(); + assert_eq!(stream.state.level, 6); + + assert!(end(stream).is_ok()); + } + + #[test] + fn window_bits_correction() { + // window_bits of 8 gets turned into 9 internally + let mut stream = z_stream::default(); + let config = DeflateConfig { + window_bits: 8, + ..Default::default() + }; + assert_eq!(init(&mut stream, config), ReturnCode::Ok); + let stream = unsafe { DeflateStream::from_stream_mut(&mut stream) }.unwrap(); + assert_eq!(stream.state.w_bits, 9); + + assert!(end(stream).is_ok()); + } + + #[test] + fn window_bits_too_low() { + let mut stream = z_stream::default(); + let config = DeflateConfig { + window_bits: -16, + ..Default::default() + }; + assert_eq!(init(&mut stream, config), ReturnCode::StreamError); + } + + #[test] + fn window_bits_too_high() { + // window bits too high + let mut stream = z_stream::default(); + let config = DeflateConfig { + window_bits: 42, + ..Default::default() + }; + assert_eq!(init(&mut stream, config), ReturnCode::StreamError); + } + } + + #[test] + fn end_data_error() { + let mut stream = z_stream::default(); + assert_eq!(init(&mut stream, DeflateConfig::default()), ReturnCode::Ok); + let stream = unsafe { DeflateStream::from_stream_mut(&mut stream) }.unwrap(); + + // next deflate into too little space + let input = b"Hello World\n"; + stream.next_in = input.as_ptr() as *mut u8; + stream.avail_in = input.len() as _; + let output = &mut [0, 0, 0]; + stream.next_out = output.as_mut_ptr(); + stream.avail_out = output.len() as _; + + // the deflate is fine + assert_eq!(deflate(stream, DeflateFlush::NoFlush), ReturnCode::Ok); + + // but end is not + assert!(end(stream).is_err()); + } + + #[test] + fn test_reset_keep() { + let mut stream = z_stream::default(); + assert_eq!(init(&mut stream, DeflateConfig::default()), ReturnCode::Ok); + let stream = unsafe { DeflateStream::from_stream_mut(&mut stream) }.unwrap(); + + // next deflate into too little space + let input = b"Hello World\n"; + stream.next_in = input.as_ptr() as *mut u8; + stream.avail_in = input.len() as _; + + let output = &mut [0; 1024]; + stream.next_out = output.as_mut_ptr(); + stream.avail_out = output.len() as _; + assert_eq!(deflate(stream, DeflateFlush::Finish), ReturnCode::StreamEnd); + + assert_eq!(reset_keep(stream), ReturnCode::Ok); + + let output = &mut [0; 1024]; + stream.next_out = output.as_mut_ptr(); + stream.avail_out = output.len() as _; + assert_eq!(deflate(stream, DeflateFlush::Finish), ReturnCode::StreamEnd); + + assert!(end(stream).is_ok()); + } + + #[test] + fn hello_world_huffman_only() { + const EXPECTED: &[u8] = &[ + 0x78, 0x01, 0xf3, 0x48, 0xcd, 0xc9, 0xc9, 0x57, 0x08, 0xcf, 0x2f, 0xca, 0x49, 0x51, + 0xe4, 0x02, 0x00, 0x20, 0x91, 0x04, 0x48, + ]; + + let input = "Hello World!\n"; + + let mut output = vec![0; 128]; + + let config = DeflateConfig { + level: 6, + method: Method::Deflated, + window_bits: crate::MAX_WBITS, + mem_level: DEF_MEM_LEVEL, + strategy: Strategy::HuffmanOnly, + }; + + let (output, err) = compress_slice(&mut output, input.as_bytes(), config); + + assert_eq!(err, ReturnCode::Ok); + + assert_eq!(output.len(), EXPECTED.len()); + + assert_eq!(EXPECTED, output); + } + + #[test] + fn hello_world_quick() { + const EXPECTED: &[u8] = &[ + 0x78, 0x01, 0xf3, 0x48, 0xcd, 0xc9, 0xc9, 0x57, 0x08, 0xcf, 0x2f, 0xca, 0x49, 0x51, + 0xe4, 0x02, 0x00, 0x20, 0x91, 0x04, 0x48, + ]; + + let input = "Hello World!\n"; + + let mut output = vec![0; 128]; + + let config = DeflateConfig { + level: 1, + method: Method::Deflated, + window_bits: crate::MAX_WBITS, + mem_level: DEF_MEM_LEVEL, + strategy: Strategy::Default, + }; + + let (output, err) = compress_slice(&mut output, input.as_bytes(), config); + + assert_eq!(err, ReturnCode::Ok); + + assert_eq!(output.len(), EXPECTED.len()); + + assert_eq!(EXPECTED, output); + } + + #[test] + fn hello_world_quick_random() { + const EXPECTED: &[u8] = &[ + 0x78, 0x01, 0x53, 0xe1, 0x50, 0x51, 0xe1, 0x52, 0x51, 0x51, 0x01, 0x00, 0x03, 0xec, + 0x00, 0xeb, + ]; + + let input = "$\u{8}$$\n$$$"; + + let mut output = vec![0; 128]; + + let config = DeflateConfig { + level: 1, + method: Method::Deflated, + window_bits: crate::MAX_WBITS, + mem_level: DEF_MEM_LEVEL, + strategy: Strategy::Default, + }; + + let (output, err) = compress_slice(&mut output, input.as_bytes(), config); + + assert_eq!(err, ReturnCode::Ok); + + assert_eq!(output.len(), EXPECTED.len()); + + assert_eq!(EXPECTED, output); + } + + fn compress_slice_ng<'a>( + output: &'a mut [u8], + input: &[u8], + config: DeflateConfig, + ) -> (&'a mut [u8], ReturnCode) { + compress_slice_with_flush_ng(output, input, config, DeflateFlush::Finish) + } + + fn compress_slice_with_flush_ng<'a>( + output: &'a mut [u8], + input: &[u8], + config: DeflateConfig, + final_flush: DeflateFlush, + ) -> (&'a mut [u8], ReturnCode) { + let mut stream = libz_ng_sys::z_stream { + next_in: input.as_ptr() as *mut u8, + avail_in: 0, // for special logic in the first iteration + total_in: 0, + next_out: output.as_mut_ptr(), + avail_out: 0, // for special logic on the first iteration + total_out: 0, + msg: core::ptr::null_mut(), + state: core::ptr::null_mut(), + zalloc: crate::allocate::zalloc_c, + zfree: crate::allocate::zfree_c, + opaque: core::ptr::null_mut(), + data_type: 0, + adler: 0, + reserved: 0, + }; + + const VERSION: *const c_char = "2.1.4\0".as_ptr() as *const c_char; + const STREAM_SIZE: c_int = core::mem::size_of::() as c_int; + + let err = unsafe { + libz_ng_sys::deflateInit2_( + &mut stream, + config.level, + config.method as i32, + config.window_bits, + config.mem_level, + config.strategy as i32, + VERSION, + STREAM_SIZE, + ) + }; + + if err != libz_ng_sys::Z_OK { + return (&mut [], ReturnCode::from(err)); + } + + let max = c_uint::MAX as usize; + + let mut left = output.len(); + let mut source_len = input.len(); + + loop { + if stream.avail_out == 0 { + stream.avail_out = Ord::min(left, max) as _; + left -= stream.avail_out as usize; + } + + if stream.avail_in == 0 { + stream.avail_in = Ord::min(source_len, max) as _; + source_len -= stream.avail_in as usize; + } + + let flush = if source_len > 0 { + DeflateFlush::NoFlush + } else { + final_flush + }; + + let err = unsafe { libz_ng_sys::deflate(&mut stream, flush as i32) }; + + if err != libz_ng_sys::Z_OK { + break; + } + } + + // may DataError if there was insufficient output space + let err = unsafe { libz_ng_sys::deflateEnd(&mut stream) }; + let return_code: ReturnCode = ReturnCode::from(err); + + (&mut output[..stream.total_out as usize], return_code) + } + + fn cve_test(input: &[u8]) { + let mut output_ng = [0; 1 << 17]; + // flush type 4 = Finish is the default + let config = DeflateConfig { + window_bits: 15, + mem_level: 1, + ..DeflateConfig::default() + }; + let (output_ng, err) = compress_slice_ng(&mut output_ng, input, config); + assert_eq!(err, ReturnCode::Ok); + + let mut output_rs = [0; 1 << 17]; + let (output_rs, err) = compress_slice(&mut output_rs, input, config); + assert_eq!(err, ReturnCode::Ok); + + assert_eq!(output_ng, output_rs); + + let mut output = vec![0; input.len()]; + let config = crate::inflate::InflateConfig { window_bits: 15 }; + let (output, err) = crate::inflate::uncompress_slice(&mut output, output_rs, config); + assert_eq!(err, ReturnCode::Ok); + + assert_eq!(input, output); + } + + #[test] + #[cfg_attr(miri, ignore)] + fn zlib_ng_cve_2018_25032_default() { + const DEFAULT: &str = include_str!("deflate/test-data/zlib-ng/CVE-2018-25032/default.txt"); + cve_test(DEFAULT.as_bytes()) + } + + #[test] + #[cfg_attr(miri, ignore)] + fn zlib_ng_cve_2018_25032_fixed() { + const FIXED: &str = include_str!("deflate/test-data/zlib-ng/CVE-2018-25032/fixed.txt"); + cve_test(FIXED.as_bytes()) + } + + #[test] + #[cfg_attr(miri, ignore)] + fn zlib_ng_gh_382() { + const DEFNEG: &[u8] = include_bytes!("deflate/test-data/zlib-ng/GH-382/defneg3.dat"); + cve_test(DEFNEG) + } + + fn fuzz_based_test(input: &[u8], config: DeflateConfig, expected: &[u8]) { + let mut output_rs = [0; 1 << 17]; + let (output_rs, err) = compress_slice(&mut output_rs, input, config); + assert_eq!(err, ReturnCode::Ok); + + if !cfg!(miri) { + let mut output_ng = [0; 1 << 17]; + let (output_ng, err) = compress_slice_ng(&mut output_ng, input, config); + assert_eq!(err, ReturnCode::Ok); + + assert_eq!(output_rs, output_ng); + + if !expected.is_empty() { + assert_eq!(output_rs, expected); + } + } + } + + #[test] + fn simple_rle() { + fuzz_based_test( + "\0\0\0\0\u{6}".as_bytes(), + DeflateConfig { + level: -1, + method: Method::Deflated, + window_bits: 11, + mem_level: 4, + strategy: Strategy::Rle, + }, + &[56, 17, 99, 0, 2, 54, 0, 0, 11, 0, 7], + ) + } + + #[test] + fn fill_window_out_of_bounds() { + const INPUT: &[u8] = &[ + 0x71, 0x71, 0x71, 0x71, 0x71, 0x6a, 0x71, 0x71, 0x71, 0x71, 0x71, 0x71, 0x71, 0x71, + 0x71, 0x71, 0x71, 0x71, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1d, 0x1d, 0x1d, 0x1d, 0x63, + 0x63, 0x63, 0x63, 0x63, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, + 0x1d, 0x27, 0x0, 0x0, 0x0, 0x1d, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x71, 0x71, 0x71, + 0x71, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x31, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x1d, 0x1d, 0x0, 0x0, 0x0, 0x0, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, + 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x48, 0x50, + 0x50, 0x50, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2c, 0x0, 0x0, 0x0, 0x0, 0x4a, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x71, 0x71, 0x71, 0x71, 0x71, 0x71, + 0x71, 0x71, 0x71, 0x71, 0x71, 0x71, 0x71, 0x71, 0x71, 0x71, 0x70, 0x71, 0x71, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x71, 0x71, 0x71, 0x71, 0x6a, 0x0, 0x0, 0x0, 0x0, + 0x71, 0x0, 0x71, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x31, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x71, 0x71, 0x71, 0x71, 0x71, 0x71, 0x71, 0x71, 0x71, 0x71, 0x71, + 0x71, 0x71, 0x0, 0x4a, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x71, 0x71, + 0x71, 0x71, 0x71, 0x71, 0x71, 0x71, 0x71, 0x71, 0x71, 0x71, 0x71, 0x71, 0x71, 0x71, + 0x70, 0x71, 0x71, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x71, 0x71, 0x71, 0x71, + 0x6a, 0x0, 0x0, 0x0, 0x0, 0x71, 0x0, 0x71, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x31, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1d, 0x1d, 0x0, 0x0, 0x0, 0x0, + 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, + 0x50, 0x50, 0x50, 0x50, 0x48, 0x50, 0x0, 0x0, 0x71, 0x71, 0x71, 0x71, 0x3b, 0x3f, 0x71, + 0x71, 0x71, 0x71, 0x71, 0x71, 0x71, 0x50, 0x50, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x2c, 0x0, 0x0, 0x0, 0x0, 0x4a, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x71, + 0x71, 0x71, 0x71, 0x71, 0x71, 0x71, 0x71, 0x71, 0x71, 0x71, 0x71, 0x71, 0x71, 0x71, + 0x71, 0x70, 0x71, 0x71, 0x0, 0x0, 0x0, 0x6, 0x0, 0x0, 0x0, 0x0, 0x0, 0x71, 0x71, 0x71, + 0x71, 0x71, 0x71, 0x70, 0x71, 0x71, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x71, 0x71, 0x71, 0x71, 0x3b, 0x3f, 0x71, 0x71, 0x71, + 0x71, 0x71, 0x71, 0x71, 0x71, 0x71, 0x71, 0x71, 0x71, 0x71, 0x71, 0x71, 0x71, 0x71, + 0x71, 0x3b, 0x3f, 0x71, 0x71, 0x71, 0x71, 0x71, 0x71, 0x71, 0x20, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x71, 0x75, 0x71, 0x71, 0x71, 0x71, 0x71, 0x71, 0x71, 0x71, 0x71, 0x71, + 0x71, 0x71, 0x71, 0x71, 0x71, 0x71, 0x71, 0x71, 0x71, 0x71, 0x10, 0x0, 0x71, 0x71, + 0x71, 0x71, 0x71, 0x71, 0x71, 0x71, 0x71, 0x71, 0x3b, 0x71, 0x71, 0x71, 0x71, 0x71, + 0x71, 0x76, 0x71, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x71, 0x71, 0x71, 0x71, 0x71, + 0x71, 0x71, 0x71, 0x10, 0x0, 0x71, 0x71, 0x71, 0x71, 0x71, 0x71, 0x71, 0x71, 0x71, + 0x71, 0x3b, 0x71, 0x71, 0x71, 0x71, 0x71, 0x71, 0x76, 0x71, 0x34, 0x34, 0x34, 0x34, + 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, + 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x0, 0x0, 0x0, 0x0, 0x0, 0x34, 0x34, 0x34, 0x34, + 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, + 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, + 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, + 0x34, 0x34, 0x30, 0x34, 0x34, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x71, 0x0, 0x0, 0x0, 0x0, 0x6, + ]; + + fuzz_based_test( + INPUT, + DeflateConfig { + level: -1, + method: Method::Deflated, + window_bits: 9, + mem_level: 1, + strategy: Strategy::HuffmanOnly, + }, + &[ + 0x18, 0x19, 0x4, 0xc1, 0x21, 0x1, 0xc4, 0x0, 0x10, 0x3, 0xb0, 0x18, 0x29, 0x1e, + 0x7e, 0x17, 0x83, 0xf5, 0x70, 0x6c, 0xac, 0xfe, 0xc9, 0x27, 0xdb, 0xb6, 0x6f, 0xdb, + 0xb6, 0x6d, 0xdb, 0x80, 0x24, 0xb9, 0xbb, 0xbb, 0x24, 0x49, 0x92, 0x24, 0xf, 0x2, + 0xd8, 0x36, 0x0, 0xf0, 0x3, 0x0, 0x0, 0x24, 0xd0, 0xb6, 0x6d, 0xdb, 0xb6, 0x6d, + 0xdb, 0xbe, 0x6d, 0xf9, 0x13, 0x4, 0xc7, 0x4, 0x0, 0x80, 0x30, 0x0, 0xc3, 0x22, + 0x68, 0xf, 0x36, 0x90, 0xc2, 0xb5, 0xfa, 0x7f, 0x48, 0x80, 0x81, 0xb, 0x40, 0x55, + 0x55, 0x55, 0xd5, 0x16, 0x80, 0xaa, 0x7, 0x9, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0xe, 0x7c, 0x82, 0xe0, 0x98, 0x0, 0x0, 0x0, 0x4, 0x60, 0x10, 0xf9, 0x8c, 0xe2, + 0xe5, 0xfa, 0x3f, 0x2, 0x54, 0x55, 0x55, 0x65, 0x0, 0xa8, 0xaa, 0xaa, 0xaa, 0xba, + 0x2, 0x50, 0xb5, 0x90, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x78, 0x82, 0xe0, 0xd0, + 0x8a, 0x41, 0x0, 0x0, 0xa2, 0x58, 0x54, 0xb7, 0x60, 0x83, 0x9a, 0x6a, 0x4, 0x96, + 0x87, 0xba, 0x51, 0xf8, 0xfb, 0x9b, 0x26, 0xfc, 0x0, 0x1c, 0x7, 0x6c, 0xdb, 0xb6, + 0x6d, 0xdb, 0xb6, 0x6d, 0xf7, 0xa8, 0x3a, 0xaf, 0xaa, 0x6a, 0x3, 0xf8, 0xc2, 0x3, + 0x40, 0x55, 0x55, 0x55, 0xd5, 0x5b, 0xf8, 0x80, 0xaa, 0x7a, 0xb, 0x0, 0x7f, 0x82, + 0xe0, 0x98, 0x0, 0x40, 0x18, 0x0, 0x82, 0xd8, 0x49, 0x40, 0x2, 0x22, 0x7e, 0xeb, + 0x80, 0xa6, 0xc, 0xa0, 0x9f, 0xa4, 0x2a, 0x38, 0xf, 0x0, 0x0, 0xe7, 0x1, 0xdc, + 0x55, 0x95, 0x17, 0x0, 0x0, 0xae, 0x0, 0x38, 0xc0, 0x67, 0xdb, 0x36, 0x80, 0x2b, + 0x0, 0xe, 0xf0, 0xd9, 0xf6, 0x13, 0x4, 0xc7, 0x4, 0x0, 0x0, 0x30, 0xc, 0x83, 0x22, + 0x69, 0x7, 0xc6, 0xea, 0xff, 0x19, 0x0, 0x0, 0x80, 0xaa, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x8e, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x6a, + 0xf5, 0x63, 0x60, 0x60, 0x3, 0x0, 0xee, 0x8a, 0x88, 0x67, + ], + ) + } + + #[test] + fn read_buf_window_uninitialized() { + // copies more in `read_buf_window` than is initialized at that point + const INPUT: &str = include_str!("deflate/test-data/read_buf_window_uninitialized.txt"); + + fuzz_based_test( + INPUT.as_bytes(), + DeflateConfig { + level: 0, + method: Method::Deflated, + window_bits: 10, + mem_level: 6, + strategy: Strategy::Default, + }, + &[], + ) + } + + #[test] + fn gzip_no_header() { + let config = DeflateConfig { + level: 9, + method: Method::Deflated, + window_bits: 31, // gzip + ..Default::default() + }; + + let input = b"Hello World!"; + let os = gz_header::OS_CODE; + + fuzz_based_test( + input, + config, + &[ + 31, 139, 8, 0, 0, 0, 0, 0, 2, os, 243, 72, 205, 201, 201, 87, 8, 207, 47, 202, 73, + 81, 4, 0, 163, 28, 41, 28, 12, 0, 0, 0, + ], + ) + } + + #[test] + fn gzip_stored_block_checksum() { + fuzz_based_test( + &[ + 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 9, 0, + ], + DeflateConfig { + level: 0, + method: Method::Deflated, + window_bits: 26, + mem_level: 6, + strategy: Strategy::Default, + }, + &[], + ) + } + + #[test] + fn gzip_header_pending_flush() { + let extra = "aaaaaaaaaaaaaaaaaaaa\0"; + let name = "bbbbbbbbbbbbbbbbbbbb\0"; + let comment = "cccccccccccccccccccc\0"; + + let mut header = gz_header { + text: 0, + time: 0, + xflags: 0, + os: 0, + extra: extra.as_ptr() as *mut _, + extra_len: extra.len() as _, + extra_max: 0, + name: name.as_ptr() as *mut _, + name_max: 0, + comment: comment.as_ptr() as *mut _, + comm_max: 0, + hcrc: 1, + done: 0, + }; + + let config = DeflateConfig { + window_bits: 31, + mem_level: 1, + ..Default::default() + }; + + let mut stream = z_stream::default(); + assert_eq!(init(&mut stream, config), ReturnCode::Ok); + + let Some(stream) = (unsafe { DeflateStream::from_stream_mut(&mut stream) }) else { + unreachable!() + }; + + set_header(stream, Some(&mut header)); + + let input = b"Hello World\n"; + stream.next_in = input.as_ptr() as *mut _; + stream.avail_in = input.len() as _; + + let mut output = [0u8; 1024]; + stream.next_out = output.as_mut_ptr(); + stream.avail_out = 100; + + assert_eq!(stream.state.bit_writer.pending.capacity(), 512); + + // only 12 bytes remain, so to write the name the pending buffer must be flushed. + // but there is insufficient output space to flush (only 100 bytes) + stream.state.bit_writer.pending.extend(&[0; 500]); + + assert_eq!(deflate(stream, DeflateFlush::Finish), ReturnCode::Ok); + + // now try that again but with sufficient output space + stream.avail_out = output.len() as _; + assert_eq!(deflate(stream, DeflateFlush::Finish), ReturnCode::StreamEnd); + + let n = stream.total_out as usize; + + assert!(end(stream).is_ok()); + + let output_rs = &mut output[..n]; + + assert_eq!(output_rs.len(), 500 + 99); + } + + #[test] + fn gzip_with_header() { + let extra = "some extra stuff\0"; + let name = "nomen est omen\0"; + let comment = "such comment\0"; + + let mut header = gz_header { + text: 0, + time: 0, + xflags: 0, + os: 0, + extra: extra.as_ptr() as *mut _, + extra_len: extra.len() as _, + extra_max: 0, + name: name.as_ptr() as *mut _, + name_max: 0, + comment: comment.as_ptr() as *mut _, + comm_max: 0, + hcrc: 1, + done: 0, + }; + + let config = DeflateConfig { + window_bits: 31, + ..Default::default() + }; + + let mut stream = z_stream::default(); + assert_eq!(init(&mut stream, config), ReturnCode::Ok); + + let Some(stream) = (unsafe { DeflateStream::from_stream_mut(&mut stream) }) else { + unreachable!() + }; + + set_header(stream, Some(&mut header)); + + let input = b"Hello World\n"; + stream.next_in = input.as_ptr() as *mut _; + stream.avail_in = input.len() as _; + + let mut output = [0u8; 256]; + stream.next_out = output.as_mut_ptr(); + stream.avail_out = output.len() as _; + + assert_eq!(deflate(stream, DeflateFlush::Finish), ReturnCode::StreamEnd); + + let n = stream.total_out as usize; + + assert!(end(stream).is_ok()); + + let output_rs = &mut output[..n]; + + assert_eq!(output_rs.len(), 81); + + #[cfg(not(miri))] + { + let mut stream = MaybeUninit::::zeroed(); + + const VERSION: *const c_char = "2.1.4\0".as_ptr() as *const c_char; + const STREAM_SIZE: c_int = core::mem::size_of::() as c_int; + + let err = unsafe { + libz_ng_sys::deflateInit2_( + stream.as_mut_ptr(), + config.level, + config.method as i32, + config.window_bits, + config.mem_level, + config.strategy as i32, + VERSION, + STREAM_SIZE, + ) + }; + assert_eq!(err, 0); + + let stream = unsafe { stream.assume_init_mut() }; + + let mut header = libz_ng_sys::gz_header { + text: 0, + time: 0, + xflags: 0, + os: 0, + extra: extra.as_ptr() as *mut _, + extra_len: extra.len() as _, + extra_max: 0, + name: name.as_ptr() as *mut _, + name_max: 0, + comment: comment.as_ptr() as *mut _, + comm_max: 0, + hcrc: 1, + done: 0, + }; + + let err = unsafe { libz_ng_sys::deflateSetHeader(stream, &mut header) }; + assert_eq!(err, 0); + + let input = b"Hello World\n"; + stream.next_in = input.as_ptr() as *mut _; + stream.avail_in = input.len() as _; + + let mut output = [0u8; 256]; + stream.next_out = output.as_mut_ptr(); + stream.avail_out = output.len() as _; + + let err = unsafe { libz_ng_sys::deflate(stream, DeflateFlush::Finish as _) }; + assert_eq!(err, ReturnCode::StreamEnd as i32); + + let n = stream.total_out; + + let err = unsafe { libz_ng_sys::deflateEnd(stream) }; + assert_eq!(err, 0); + + assert_eq!(&output[..n], output_rs); + } + + #[cfg(not(miri))] + { + let mut stream = MaybeUninit::::zeroed(); + + const VERSION: *const c_char = "2.1.4\0".as_ptr() as *const c_char; + const STREAM_SIZE: c_int = core::mem::size_of::() as c_int; + + let err = unsafe { + libz_ng_sys::inflateInit2_( + stream.as_mut_ptr(), + config.window_bits, + VERSION, + STREAM_SIZE, + ) + }; + assert_eq!(err, 0); + + let stream = unsafe { stream.assume_init_mut() }; + + stream.next_in = output_rs.as_mut_ptr() as _; + stream.avail_in = output_rs.len() as _; + + let mut output = [0u8; 12]; + stream.next_out = output.as_mut_ptr(); + stream.avail_out = output.len() as _; + + let mut extra_buf = [0u8; 64]; + let mut name_buf = [0u8; 64]; + let mut comment_buf = [0u8; 64]; + + let mut header = libz_ng_sys::gz_header { + text: 0, + time: 0, + xflags: 0, + os: 0, + extra: extra_buf.as_mut_ptr(), + extra_len: 0, + extra_max: extra_buf.len() as _, + name: name_buf.as_mut_ptr(), + name_max: name_buf.len() as _, + comment: comment_buf.as_mut_ptr(), + comm_max: comment_buf.len() as _, + hcrc: 0, + done: 0, + }; + + let err = unsafe { libz_ng_sys::inflateGetHeader(stream, &mut header) }; + assert_eq!(err, 0); + + let err = unsafe { libz_ng_sys::inflate(stream, DeflateFlush::NoFlush as _) }; + assert_eq!( + err, + ReturnCode::StreamEnd as i32, + "{:?}", + if stream.msg.is_null() { + None + } else { + Some(unsafe { CStr::from_ptr(stream.msg) }) + } + ); + + assert!(!header.comment.is_null()); + assert_eq!( + unsafe { CStr::from_ptr(header.comment.cast()) } + .to_str() + .unwrap(), + comment.trim_end_matches('\0') + ); + + assert!(!header.name.is_null()); + assert_eq!( + unsafe { CStr::from_ptr(header.name.cast()) } + .to_str() + .unwrap(), + name.trim_end_matches('\0') + ); + + assert!(!header.extra.is_null()); + assert_eq!( + unsafe { CStr::from_ptr(header.extra.cast()) } + .to_str() + .unwrap(), + extra.trim_end_matches('\0') + ); + } + + { + let mut stream = z_stream::default(); + + let config = InflateConfig { + window_bits: config.window_bits, + }; + + assert_eq!(crate::inflate::init(&mut stream, config), ReturnCode::Ok); + + let Some(stream) = (unsafe { InflateStream::from_stream_mut(&mut stream) }) else { + unreachable!(); + }; + + stream.next_in = output_rs.as_mut_ptr() as _; + stream.avail_in = output_rs.len() as _; + + let mut output = [0u8; 12]; + stream.next_out = output.as_mut_ptr(); + stream.avail_out = output.len() as _; + + let mut extra_buf = [0u8; 64]; + let mut name_buf = [0u8; 64]; + let mut comment_buf = [0u8; 64]; + + let mut header = gz_header { + text: 0, + time: 0, + xflags: 0, + os: 0, + extra: extra_buf.as_mut_ptr(), + extra_len: 0, + extra_max: extra_buf.len() as _, + name: name_buf.as_mut_ptr(), + name_max: name_buf.len() as _, + comment: comment_buf.as_mut_ptr(), + comm_max: comment_buf.len() as _, + hcrc: 0, + done: 0, + }; + + assert_eq!( + crate::inflate::get_header(stream, Some(&mut header)), + ReturnCode::Ok + ); + + assert_eq!( + unsafe { crate::inflate::inflate(stream, InflateFlush::Finish) }, + ReturnCode::StreamEnd + ); + + crate::inflate::end(stream); + + assert!(!header.comment.is_null()); + assert_eq!( + unsafe { CStr::from_ptr(header.comment.cast()) } + .to_str() + .unwrap(), + comment.trim_end_matches('\0') + ); + + assert!(!header.name.is_null()); + assert_eq!( + unsafe { CStr::from_ptr(header.name.cast()) } + .to_str() + .unwrap(), + name.trim_end_matches('\0') + ); + + assert!(!header.extra.is_null()); + assert_eq!( + unsafe { CStr::from_ptr(header.extra.cast()) } + .to_str() + .unwrap(), + extra.trim_end_matches('\0') + ); + } + } + + #[cfg(not(miri))] + quickcheck::quickcheck! { + fn rs_is_ng(bytes: Vec) -> bool { + fuzz_based_test(&bytes, DeflateConfig::default(), &[]); + + true + } + } + + #[test] + fn insufficient_compress_space() { + const DATA: &[u8] = include_bytes!("deflate/test-data/inflate_buf_error.dat"); + + fn helper(deflate_buf: &mut [u8]) -> ReturnCode { + let config = DeflateConfig { + level: 0, + method: Method::Deflated, + window_bits: 10, + mem_level: 6, + strategy: Strategy::Default, + }; + + let (output, err) = compress_slice(deflate_buf, DATA, config); + assert_eq!(err, ReturnCode::Ok); + + let config = InflateConfig { + window_bits: config.window_bits, + }; + + let mut uncompr = [0; 1 << 17]; + let (uncompr, err) = uncompress_slice(&mut uncompr, output, config); + + if err == ReturnCode::Ok { + assert_eq!(DATA, uncompr); + } + + err + } + + let mut output = [0; 1 << 17]; + + // this is too little space + assert_eq!(helper(&mut output[..1 << 16]), ReturnCode::DataError); + + // this is sufficient space + assert_eq!(helper(&mut output), ReturnCode::Ok); + } + + fn test_flush(flush: DeflateFlush) { + let input = b"Hello World!\n"; + + let config = DeflateConfig { + level: 6, // use gzip + method: Method::Deflated, + window_bits: 16 + crate::MAX_WBITS, + mem_level: DEF_MEM_LEVEL, + strategy: Strategy::Default, + }; + + let mut output_rs = vec![0; 128]; + let mut output_ng = vec![0; 128]; + + // with the flush modes that we test here, the deflate process still has `Status::Busy`, + // and the `deflateEnd` function will return `DataError`. + let expected = ReturnCode::DataError; + + let (rs, err) = compress_slice_with_flush(&mut output_rs, input, config, flush); + assert_eq!(expected, err); + + if !cfg!(miri) { + let (ng, err) = compress_slice_with_flush_ng(&mut output_ng, input, config, flush); + assert_eq!(expected, err); + + assert_eq!(rs, ng); + } + } + + #[test] + fn sync_flush() { + test_flush(DeflateFlush::SyncFlush) + } + + #[test] + fn partial_flush() { + test_flush(DeflateFlush::PartialFlush); + } + + #[test] + fn full_flush() { + test_flush(DeflateFlush::FullFlush); + } + + #[test] + fn block_flush() { + test_flush(DeflateFlush::Block); + } + + #[test] + // splits the input into two, deflates them seperately and then joins the deflated byte streams + // into something that can be correctly inflated again. This is the basic idea behind pigz, and + // allows for parallel compression. + fn split_deflate() { + let input = "Hello World!\n"; + + let (input1, input2) = input.split_at(6); + + let mut output1 = vec![0; 128]; + let mut output2 = vec![0; 128]; + + let config = DeflateConfig { + level: 6, // use gzip + method: Method::Deflated, + window_bits: 16 + crate::MAX_WBITS, + mem_level: DEF_MEM_LEVEL, + strategy: Strategy::Default, + }; + + // see also the docs on `SyncFlush`. it makes sure everything is flushed, ends on a byte + // boundary, and that the final block does not have the "last block" bit set. + let (prefix, err) = compress_slice_with_flush( + &mut output1, + input1.as_bytes(), + config, + DeflateFlush::SyncFlush, + ); + assert_eq!(err, ReturnCode::DataError); + + let (output2, err) = compress_slice_with_flush( + &mut output2, + input2.as_bytes(), + config, + DeflateFlush::Finish, + ); + assert_eq!(err, ReturnCode::Ok); + + let inflate_config = crate::inflate::InflateConfig { + window_bits: 16 + 15, + }; + + // cuts off the length and crc + let (suffix, end) = output2.split_at(output2.len() - 8); + let (crc2, len2) = end.split_at(4); + let crc2 = u32::from_ne_bytes(crc2.try_into().unwrap()); + + // cuts off the gzip header (10 bytes) from the front + let suffix = &suffix[10..]; + + let mut result: Vec = Vec::new(); + result.extend(prefix.iter()); + result.extend(suffix); + + // it would be more proper to use `stream.total_in` here, but the slice helpers hide the + // stream so we're cheating a bit here + let len1 = input1.len() as u32; + let len2 = u32::from_ne_bytes(len2.try_into().unwrap()); + assert_eq!(len2 as usize, input2.len()); + + let crc1 = crate::crc32(0, input1.as_bytes()); + let crc = crate::crc32_combine(crc1, crc2, len2 as u64); + + // combined crc of the parts should be the crc of the whole + let crc_cheating = crate::crc32(0, input.as_bytes()); + assert_eq!(crc, crc_cheating); + + // write the trailer + result.extend(crc.to_le_bytes()); + result.extend((len1 + len2).to_le_bytes()); + + let mut output = vec![0; 128]; + let (output, err) = crate::inflate::uncompress_slice(&mut output, &result, inflate_config); + assert_eq!(err, ReturnCode::Ok); + + assert_eq!(output, input.as_bytes()); + } + + #[test] + fn inflate_window_copy_slice() { + let uncompressed = [ + 9, 126, 0, 0, 0, 0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 76, 33, 8, 2, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 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, 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, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 12, + 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 76, 33, 8, 2, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 12, 10, 0, 0, 0, 0, 14, 0, 0, 0, 0, 0, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, + 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 14, 0, 0, 0, 0, 0, 69, 69, 69, 69, 69, 69, 69, + 69, 69, 69, 69, 69, 69, 69, 69, 9, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, + 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, + 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, + 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 12, 28, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 12, 10, 0, 0, 0, 0, 14, 0, 0, 0, 0, 0, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, + 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 14, 0, 0, 0, 0, 0, 69, 69, 69, 69, 69, 69, 69, + 69, 69, 69, 69, 69, 69, 69, 69, 9, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, + 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, + 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, + 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 12, 28, 0, 2, 0, 0, 0, 63, 1, 0, 12, 2, + 36, 0, 28, 0, 0, 0, 1, 0, 0, 63, 63, 13, 0, 0, 0, 0, 0, 0, 0, 63, 63, 63, 63, 0, 0, 0, + 0, 0, 0, 65, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 45, 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, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 91, 0, 0, 0, 9, 0, 0, 0, 9, 0, 0, 12, 33, 2, 0, 0, 8, + 0, 4, 0, 0, 0, 12, 10, 41, 12, 10, 47, + ]; + + let compressed = &[ + 31, 139, 8, 0, 0, 0, 0, 0, 4, 3, 181, 193, 49, 14, 194, 32, 24, 128, 209, 175, 192, 0, + 228, 151, 232, 206, 66, 226, 226, 96, 60, 2, 113, 96, 235, 13, 188, 139, 103, 23, 106, + 104, 108, 100, 49, 169, 239, 185, 39, 11, 199, 7, 51, 39, 171, 248, 118, 226, 63, 52, + 157, 120, 86, 102, 78, 86, 209, 104, 58, 241, 84, 129, 166, 12, 4, 154, 178, 229, 202, + 30, 36, 130, 166, 19, 79, 21, 104, 202, 64, 160, 41, 91, 174, 236, 65, 34, 10, 200, 19, + 162, 206, 68, 96, 130, 156, 15, 188, 229, 138, 197, 157, 161, 35, 3, 87, 126, 245, 0, + 28, 224, 64, 146, 2, 139, 1, 196, 95, 196, 223, 94, 10, 96, 92, 33, 86, 2, 0, 0, + ]; + + let config = InflateConfig { window_bits: 25 }; + + let mut dest_vec_rs = vec![0u8; uncompressed.len()]; + let (output_rs, error) = + crate::inflate::uncompress_slice(&mut dest_vec_rs, compressed, config); + + assert_eq!(ReturnCode::Ok, error); + assert_eq!(output_rs, uncompressed); + } + + #[test] + fn small_aarch64_difference() { + let input = [ + 0, 0, 0, 0, 0, 43, 0, 0, 0, 0, 0, 0, 43, 0, 0, 0, 0, 0, 0, 0, 0, 48, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 49, 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, 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, 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, 0, 0, 0, 0, 29, 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, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 0, 0, 0, 0, 0, + 0, 0, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 55, 0, 64, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 48, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 102, 102, 102, 102, 102, + 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, + 102, 102, 102, 102, 102, 102, 102, 102, 112, 102, 102, 102, 102, 102, 102, 102, 102, + 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 0, + 0, 0, 0, 0, 0, 49, 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, 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, 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, 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, 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, 19, 0, 0, 0, 0, 0, 0, 0, 64, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 55, 0, 64, 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, 42, 0, 0, 0, + 50, 0, + ]; + + let config = DeflateConfig { + level: -1, + method: Method::Deflated, + window_bits: 9, + mem_level: 8, + strategy: Strategy::Default, + }; + + let _x86_64 = [ + 24, 149, 99, 96, 96, 96, 96, 208, 6, 17, 112, 138, 129, 193, 128, 1, 29, 24, 50, 208, + 1, 200, 146, 169, 79, 24, 74, 59, 96, 147, 52, 71, 22, 70, 246, 88, 26, 94, 80, 128, + 83, 6, 162, 219, 144, 76, 183, 210, 5, 8, 67, 105, 7, 108, 146, 230, 216, 133, 145, + 129, 22, 3, 3, 131, 17, 3, 0, 3, 228, 25, 128, + ]; + + let _aarch64 = [ + 24, 149, 99, 96, 96, 96, 96, 208, 6, 17, 112, 138, 129, 193, 128, 1, 29, 24, 50, 208, + 1, 200, 146, 169, 79, 24, 74, 59, 96, 147, 52, 71, 22, 70, 246, 88, 26, 94, 80, 128, + 83, 6, 162, 219, 144, 76, 183, 210, 5, 8, 67, 105, 36, 159, 35, 128, 57, 118, 97, 100, + 160, 197, 192, 192, 96, 196, 0, 0, 3, 228, 25, 128, + ]; + + #[cfg(target_arch = "x86_64")] + fuzz_based_test(&input, config, &_x86_64); + + #[cfg(target_arch = "aarch64")] + fuzz_based_test(&input, config, &_aarch64); + } +} diff --git a/third_party/rust/zlib-rs/src/deflate/algorithm/fast.rs b/third_party/rust/zlib-rs/src/deflate/algorithm/fast.rs new file mode 100644 index 000000000000..fedb38db2418 --- /dev/null +++ b/third_party/rust/zlib-rs/src/deflate/algorithm/fast.rs @@ -0,0 +1,109 @@ +#![forbid(unsafe_code)] + +use crate::{ + deflate::{ + fill_window, BlockState, DeflateStream, MIN_LOOKAHEAD, STD_MIN_MATCH, WANT_MIN_MATCH, + }, + flush_block, DeflateFlush, +}; + +pub fn deflate_fast(stream: &mut DeflateStream, flush: DeflateFlush) -> BlockState { + let mut bflush; /* set if current block must be flushed */ + let mut dist; + let mut match_len = 0; + + loop { + // Make sure that we always have enough lookahead, except + // at the end of the input file. We need STD_MAX_MATCH bytes + // for the next match, plus WANT_MIN_MATCH bytes to insert the + // string following the next match. + if stream.state.lookahead < MIN_LOOKAHEAD { + fill_window(stream); + if stream.state.lookahead < MIN_LOOKAHEAD && flush == DeflateFlush::NoFlush { + return BlockState::NeedMore; + } + if stream.state.lookahead == 0 { + break; /* flush the current block */ + } + } + + let state = &mut stream.state; + + // Insert the string window[strstart .. strstart+2] in the + // dictionary, and set hash_head to the head of the hash chain: + + if state.lookahead >= WANT_MIN_MATCH { + let hash_head = state.quick_insert_string(state.strstart); + dist = state.strstart as isize - hash_head as isize; + + /* Find the longest match, discarding those <= prev_length. + * At this point we have always match length < WANT_MIN_MATCH + */ + if dist <= state.max_dist() as isize && dist > 0 && hash_head != 0 { + // To simplify the code, we prevent matches with the string + // of window index 0 (in particular we have to avoid a match + // of the string with itself at the start of the input file). + (match_len, state.match_start) = + crate::deflate::longest_match::longest_match(state, hash_head); + } + } + + if match_len >= WANT_MIN_MATCH { + // check_match(s, s->strstart, s->match_start, match_len); + + // bflush = zng_tr_tally_dist(s, s->strstart - s->match_start, match_len - STD_MIN_MATCH); + bflush = state.tally_dist( + state.strstart - state.match_start, + match_len - STD_MIN_MATCH, + ); + + state.lookahead -= match_len; + + /* Insert new strings in the hash table only if the match length + * is not too large. This saves time but degrades compression. + */ + if match_len <= state.max_insert_length() && state.lookahead >= WANT_MIN_MATCH { + match_len -= 1; /* string at strstart already in table */ + state.strstart += 1; + + state.insert_string(state.strstart, match_len); + state.strstart += match_len; + } else { + state.strstart += match_len; + state.quick_insert_string(state.strstart + 2 - STD_MIN_MATCH); + + /* If lookahead < STD_MIN_MATCH, ins_h is garbage, but it does not + * matter since it will be recomputed at next deflate call. + */ + } + match_len = 0; + } else { + /* No match, output a literal byte */ + let lc = state.window.filled()[state.strstart]; + bflush = state.tally_lit(lc); + state.lookahead -= 1; + state.strstart += 1; + } + + if bflush { + flush_block!(stream, false); + } + } + + stream.state.insert = if stream.state.strstart < (STD_MIN_MATCH - 1) { + stream.state.strstart + } else { + STD_MIN_MATCH - 1 + }; + + if flush == DeflateFlush::Finish { + flush_block!(stream, true); + return BlockState::FinishDone; + } + + if !stream.state.sym_buf.is_empty() { + flush_block!(stream, false); + } + + BlockState::BlockDone +} diff --git a/third_party/rust/zlib-rs/src/deflate/algorithm/huff.rs b/third_party/rust/zlib-rs/src/deflate/algorithm/huff.rs new file mode 100644 index 000000000000..58a6ae980aeb --- /dev/null +++ b/third_party/rust/zlib-rs/src/deflate/algorithm/huff.rs @@ -0,0 +1,45 @@ +#![forbid(unsafe_code)] + +use crate::{ + deflate::{fill_window, BlockState, DeflateStream}, + flush_block, DeflateFlush, +}; + +pub fn deflate_huff(stream: &mut DeflateStream, flush: DeflateFlush) -> BlockState { + loop { + /* Make sure that we have a literal to write. */ + if stream.state.lookahead == 0 { + fill_window(stream); + + if stream.state.lookahead == 0 { + match flush { + DeflateFlush::NoFlush => return BlockState::NeedMore, + _ => break, /* flush the current block */ + } + } + } + + /* Output a literal byte */ + let state = &mut stream.state; + let lc = state.window.filled()[state.strstart]; + let bflush = state.tally_lit(lc); + state.lookahead -= 1; + state.strstart += 1; + if bflush { + flush_block!(stream, false); + } + } + + stream.state.insert = 0; + + if flush == DeflateFlush::Finish { + flush_block!(stream, true); + return BlockState::FinishDone; + } + + if !stream.state.sym_buf.is_empty() { + flush_block!(stream, false); + } + + BlockState::BlockDone +} diff --git a/third_party/rust/zlib-rs/src/deflate/algorithm/medium.rs b/third_party/rust/zlib-rs/src/deflate/algorithm/medium.rs new file mode 100644 index 000000000000..030279470e3c --- /dev/null +++ b/third_party/rust/zlib-rs/src/deflate/algorithm/medium.rs @@ -0,0 +1,339 @@ +#![forbid(unsafe_code)] + +use crate::{ + deflate::{ + fill_window, BlockState, DeflateStream, State, MIN_LOOKAHEAD, STD_MIN_MATCH, WANT_MIN_MATCH, + }, + flush_block, DeflateFlush, +}; + +pub fn deflate_medium(stream: &mut DeflateStream, flush: DeflateFlush) -> BlockState { + let mut state = &mut stream.state; + + // For levels below 5, don't check the next position for a better match + let early_exit = state.level < 5; + + let mut current_match = Match { + match_start: 0, + match_length: 0, + strstart: 0, + orgstart: 0, + }; + let mut next_match = Match { + match_start: 0, + match_length: 0, + strstart: 0, + orgstart: 0, + }; + + loop { + let mut hash_head; + + /* Make sure that we always have enough lookahead, except + * at the end of the input file. We need STD_MAX_MATCH bytes + * for the next match, plus WANT_MIN_MATCH bytes to insert the + * string following the next match. + */ + if stream.state.lookahead < MIN_LOOKAHEAD { + fill_window(stream); + + if stream.state.lookahead < MIN_LOOKAHEAD && flush == DeflateFlush::NoFlush { + return BlockState::NeedMore; + } + + if stream.state.lookahead == 0 { + break; /* flush the current block */ + } + + next_match.match_length = 0; + } + + state = &mut stream.state; + + // Insert the string window[strstart .. strstart+2] in the + // dictionary, and set hash_head to the head of the hash chain: + + /* If we already have a future match from a previous round, just use that */ + if !early_exit && next_match.match_length > 0 { + current_match = next_match; + next_match.match_length = 0; + } else { + hash_head = 0; + if state.lookahead >= WANT_MIN_MATCH { + hash_head = state.quick_insert_string(state.strstart); + } + + current_match.strstart = state.strstart as u16; + current_match.orgstart = current_match.strstart; + + /* Find the longest match, discarding those <= prev_length. + * At this point we have always match_length < WANT_MIN_MATCH + */ + + let dist = state.strstart as i64 - hash_head as i64; + if dist <= state.max_dist() as i64 && dist > 0 && hash_head != 0 { + /* To simplify the code, we prevent matches with the string + * of window index 0 (in particular we have to avoid a match + * of the string with itself at the start of the input file). + */ + let (match_length, match_start) = + crate::deflate::longest_match::longest_match(state, hash_head); + state.match_start = match_start; + current_match.match_length = match_length as u16; + current_match.match_start = match_start as u16; + if (current_match.match_length as usize) < WANT_MIN_MATCH { + current_match.match_length = 1; + } + if current_match.match_start >= current_match.strstart { + /* this can happen due to some restarts */ + current_match.match_length = 1; + } + } else { + /* Set up the match to be a 1 byte literal */ + current_match.match_start = 0; + current_match.match_length = 1; + } + } + + insert_match(state, current_match); + + /* now, look ahead one */ + if !early_exit + && state.lookahead > MIN_LOOKAHEAD + && ((current_match.strstart + current_match.match_length) as usize) + < (state.window_size - MIN_LOOKAHEAD) + { + state.strstart = (current_match.strstart + current_match.match_length) as usize; + hash_head = state.quick_insert_string(state.strstart); + + next_match.strstart = state.strstart as u16; + next_match.orgstart = next_match.strstart; + + /* Find the longest match, discarding those <= prev_length. + * At this point we have always match_length < WANT_MIN_MATCH + */ + + let dist = state.strstart as i64 - hash_head as i64; + if dist <= state.max_dist() as i64 && dist > 0 && hash_head != 0 { + /* To simplify the code, we prevent matches with the string + * of window index 0 (in particular we have to avoid a match + * of the string with itself at the start of the input file). + */ + let (match_length, match_start) = + crate::deflate::longest_match::longest_match(state, hash_head); + state.match_start = match_start; + next_match.match_length = match_length as u16; + next_match.match_start = match_start as u16; + + if next_match.match_start >= next_match.strstart { + /* this can happen due to some restarts */ + next_match.match_length = 1; + } + if (next_match.match_length as usize) < WANT_MIN_MATCH { + next_match.match_length = 1; + } else { + fizzle_matches( + state.window.filled(), + state.max_dist(), + &mut current_match, + &mut next_match, + ); + } + } else { + /* Set up the match to be a 1 byte literal */ + next_match.match_start = 0; + next_match.match_length = 1; + } + + state.strstart = current_match.strstart as usize; + } else { + next_match.match_length = 0; + } + + /* now emit the current match */ + let bflush = emit_match(state, current_match); + + /* move the "cursor" forward */ + state.strstart += current_match.match_length as usize; + + if bflush { + flush_block!(stream, false); + } + } + + stream.state.insert = Ord::min(stream.state.strstart, STD_MIN_MATCH - 1); + + if flush == DeflateFlush::Finish { + flush_block!(stream, true); + return BlockState::FinishDone; + } + + if !stream.state.sym_buf.is_empty() { + flush_block!(stream, false); + } + + BlockState::BlockDone +} + +#[repr(C)] +#[derive(Debug, Clone, Copy)] +struct Match { + match_start: u16, + match_length: u16, + strstart: u16, + orgstart: u16, +} + +fn emit_match(state: &mut State, mut m: Match) -> bool { + let mut bflush = false; + + /* matches that are not long enough we need to emit as literals */ + if (m.match_length as usize) < WANT_MIN_MATCH { + while m.match_length > 0 { + let lc = state.window.filled()[state.strstart]; + bflush |= state.tally_lit(lc); + state.lookahead -= 1; + m.strstart += 1; + m.match_length -= 1; + } + return bflush; + } + + // check_match(s, m.strstart, m.match_start, m.match_length); + + bflush |= state.tally_dist( + (m.strstart - m.match_start) as usize, + m.match_length as usize - STD_MIN_MATCH, + ); + + state.lookahead -= m.match_length as usize; + + bflush +} + +fn insert_match(state: &mut State, mut m: Match) { + if state.lookahead <= (m.match_length as usize + WANT_MIN_MATCH) { + return; + } + + /* matches that are not long enough we need to emit as literals */ + if (m.match_length as usize) < WANT_MIN_MATCH { + m.strstart += 1; + m.match_length -= 1; + if m.match_length > 0 && m.strstart >= m.orgstart { + if m.strstart + m.match_length > m.orgstart { + state.insert_string(m.strstart as usize, m.match_length as usize); + } else { + state.insert_string(m.strstart as usize, (m.orgstart - m.strstart + 1) as usize); + } + m.strstart += m.match_length; + m.match_length = 0; + } + return; + } + + /* Insert new strings in the hash table only if the match length + * is not too large. This saves time but degrades compression. + */ + if (m.match_length as usize) <= 16 * state.max_insert_length() + && state.lookahead >= WANT_MIN_MATCH + { + m.match_length -= 1; /* string at strstart already in table */ + m.strstart += 1; + + if m.strstart >= m.orgstart { + if m.strstart + m.match_length > m.orgstart { + state.insert_string(m.strstart as usize, m.match_length as usize); + } else { + state.insert_string(m.strstart as usize, (m.orgstart - m.strstart + 1) as usize); + } + } else if m.orgstart < m.strstart + m.match_length { + state.insert_string( + m.orgstart as usize, + (m.strstart + m.match_length - m.orgstart) as usize, + ); + } + m.strstart += m.match_length; + m.match_length = 0; + } else { + m.strstart += m.match_length; + m.match_length = 0; + + if (m.strstart as usize) >= (STD_MIN_MATCH - 2) { + state.quick_insert_string(m.strstart as usize + 2 - STD_MIN_MATCH); + } + + /* If lookahead < WANT_MIN_MATCH, ins_h is garbage, but it does not + * matter since it will be recomputed at next deflate call. + */ + } +} + +fn fizzle_matches(window: &[u8], max_dist: usize, current: &mut Match, next: &mut Match) { + /* step zero: sanity checks */ + + if current.match_length <= 1 { + return; + } + + if current.match_length > 1 + next.match_start { + return; + } + + if current.match_length > 1 + next.strstart { + return; + } + + let m = &window[(-(current.match_length as isize) + 1 + next.match_start as isize) as usize..]; + let orig = &window[(-(current.match_length as isize) + 1 + next.strstart as isize) as usize..]; + + /* quick exit check.. if this fails then don't bother with anything else */ + if m[0] != orig[0] { + return; + } + + /* step one: try to move the "next" match to the left as much as possible */ + let limit = next.strstart.saturating_sub(max_dist as u16); + + let mut c = *current; + let mut n = *next; + + let m = &window[..n.match_start as usize]; + let orig = &window[..n.strstart as usize]; + + let mut m = m.iter().rev(); + let mut orig = orig.iter().rev(); + + let mut changed = 0; + + while m.next() == orig.next() { + if c.match_length < 1 { + break; + } + if n.strstart <= limit { + break; + } + if n.match_length >= 256 { + break; + } + if n.match_start <= 1 { + break; + } + + n.strstart -= 1; + n.match_start -= 1; + n.match_length += 1; + c.match_length -= 1; + changed += 1; + } + + if changed == 0 { + return; + } + + if c.match_length <= 1 && n.match_length != 2 { + n.orgstart += 1; + *current = c; + *next = n; + } +} diff --git a/third_party/rust/zlib-rs/src/deflate/algorithm/mod.rs b/third_party/rust/zlib-rs/src/deflate/algorithm/mod.rs new file mode 100644 index 000000000000..af62f38ebe20 --- /dev/null +++ b/third_party/rust/zlib-rs/src/deflate/algorithm/mod.rs @@ -0,0 +1,83 @@ +use crate::{ + deflate::{BlockState, DeflateStream, Strategy}, + DeflateFlush, +}; + +use self::{huff::deflate_huff, rle::deflate_rle, stored::deflate_stored}; + +mod fast; +mod huff; +mod medium; +mod quick; +mod rle; +mod slow; +mod stored; + +#[macro_export] +macro_rules! flush_block { + ($stream:expr, $is_last_block:expr) => { + $crate::deflate::flush_block_only($stream, $is_last_block); + + if $stream.avail_out == 0 { + return match $is_last_block { + true => BlockState::FinishStarted, + false => BlockState::NeedMore, + }; + } + }; +} + +pub fn run(stream: &mut DeflateStream, flush: DeflateFlush) -> BlockState { + match stream.state.strategy { + _ if stream.state.level == 0 => deflate_stored(stream, flush), + Strategy::HuffmanOnly => deflate_huff(stream, flush), + Strategy::Rle => deflate_rle(stream, flush), + Strategy::Default | Strategy::Filtered | Strategy::Fixed => { + (CONFIGURATION_TABLE[stream.state.level as usize].func)(stream, flush) + } + } +} + +type CompressFunc = fn(&mut DeflateStream, flush: DeflateFlush) -> BlockState; + +#[allow(unused)] +pub struct Config { + pub good_length: u16, /* reduce lazy search above this match length */ + pub max_lazy: u16, /* do not perform lazy search above this match length */ + pub nice_length: u16, /* quit search above this match length */ + pub max_chain: u16, + pub func: CompressFunc, +} + +impl Config { + const fn new( + good_length: u16, + max_lazy: u16, + nice_length: u16, + max_chain: u16, + func: CompressFunc, + ) -> Self { + Self { + good_length, + max_lazy, + nice_length, + max_chain, + func, + } + } +} + +pub const CONFIGURATION_TABLE: [Config; 10] = { + [ + Config::new(0, 0, 0, 0, stored::deflate_stored), // 0 /* store only */ + Config::new(0, 0, 0, 0, quick::deflate_quick), // 1 + Config::new(4, 4, 8, 4, fast::deflate_fast), // 2 /* max speed, no lazy matches */ + Config::new(4, 6, 16, 6, medium::deflate_medium), // 3 + Config::new(4, 12, 32, 24, medium::deflate_medium), // 4 /* lazy matches */ + Config::new(8, 16, 32, 32, medium::deflate_medium), // 5 + Config::new(8, 16, 128, 128, medium::deflate_medium), // 6 + Config::new(8, 32, 128, 256, slow::deflate_slow), // 7 + Config::new(32, 128, 258, 1024, slow::deflate_slow), // 8 + Config::new(32, 258, 258, 4096, slow::deflate_slow), // 9 /* max compression */ + ] +}; diff --git a/third_party/rust/zlib-rs/src/deflate/algorithm/quick.rs b/third_party/rust/zlib-rs/src/deflate/algorithm/quick.rs new file mode 100644 index 000000000000..ae5870103716 --- /dev/null +++ b/third_party/rust/zlib-rs/src/deflate/algorithm/quick.rs @@ -0,0 +1,149 @@ +#![forbid(unsafe_code)] + +use crate::{ + deflate::{ + fill_window, flush_pending, BlockState, BlockType, DeflateStream, State, StaticTreeDesc, + MIN_LOOKAHEAD, STD_MAX_MATCH, STD_MIN_MATCH, WANT_MIN_MATCH, + }, + DeflateFlush, +}; + +pub fn deflate_quick(stream: &mut DeflateStream, flush: DeflateFlush) -> BlockState { + let mut state = &mut stream.state; + + let last = matches!(flush, DeflateFlush::Finish); + + macro_rules! quick_start_block { + () => { + state.bit_writer.emit_tree(BlockType::StaticTrees, last); + state.block_open = 1 + last as u8; + state.block_start = state.strstart as isize; + }; + } + + macro_rules! quick_end_block { + () => { + if state.block_open > 0 { + state + .bit_writer + .emit_end_block_and_align(&StaticTreeDesc::L.static_tree, last); + state.block_open = 0; + state.block_start = state.strstart as isize; + flush_pending(stream); + #[allow(unused_assignments)] + { + state = &mut stream.state; + } + if stream.avail_out == 0 { + return match last { + true => BlockState::FinishStarted, + false => BlockState::NeedMore, + }; + } + } + }; + } + + if last && state.block_open != 2 { + /* Emit end of previous block */ + quick_end_block!(); + /* Emit start of last block */ + quick_start_block!(); + } else if state.block_open == 0 && state.lookahead > 0 { + /* Start new block only when we have lookahead data, so that if no + input data is given an empty block will not be written */ + quick_start_block!(); + } + + loop { + if state.bit_writer.pending.pending + State::BIT_BUF_SIZE.div_ceil(8) as usize + >= state.pending_buf_size() + { + flush_pending(stream); + state = &mut stream.state; + if stream.avail_out == 0 { + return if last + && stream.avail_in == 0 + && state.bit_writer.bits_used == 0 + && state.block_open == 0 + { + BlockState::FinishStarted + } else { + BlockState::NeedMore + }; + } + } + + if state.lookahead < MIN_LOOKAHEAD { + fill_window(stream); + state = &mut stream.state; + + if state.lookahead < MIN_LOOKAHEAD && matches!(flush, DeflateFlush::NoFlush) { + return BlockState::NeedMore; + } + if state.lookahead == 0 { + break; + } + + if state.block_open == 0 { + // Start new block when we have lookahead data, + // so that if no input data is given an empty block will not be written + quick_start_block!(); + } + } + + if state.lookahead >= WANT_MIN_MATCH { + let hash_head = state.quick_insert_string(state.strstart); + let dist = state.strstart as isize - hash_head as isize; + + if dist <= state.max_dist() as isize && dist > 0 { + let str_start = &state.window.filled()[state.strstart..]; + let match_start = &state.window.filled()[hash_head as usize..]; + + if str_start[0] == match_start[0] && str_start[1] == match_start[1] { + let mut match_len = crate::deflate::compare256::compare256_slice( + &str_start[2..], + &match_start[2..], + ) + 2; + + if match_len >= WANT_MIN_MATCH { + match_len = Ord::min(match_len, state.lookahead); + match_len = Ord::min(match_len, STD_MAX_MATCH); + + // TODO do this with a debug_assert? + // check_match(s, state.strstart, hash_head, match_len); + + state.bit_writer.emit_dist( + StaticTreeDesc::L.static_tree, + StaticTreeDesc::D.static_tree, + (match_len - STD_MIN_MATCH) as u8, + dist as usize, + ); + state.lookahead -= match_len; + state.strstart += match_len; + continue; + } + } + } + } + + let lc = state.window.filled()[state.strstart]; + state.bit_writer.emit_lit(StaticTreeDesc::L.static_tree, lc); + state.strstart += 1; + state.lookahead -= 1; + } + + state.insert = if state.strstart < (STD_MIN_MATCH - 1) { + state.strstart + } else { + STD_MIN_MATCH - 1 + }; + + if last { + quick_end_block!(); + return BlockState::FinishDone; + } + + quick_end_block!(); + BlockState::BlockDone +} diff --git a/third_party/rust/zlib-rs/src/deflate/algorithm/rle.rs b/third_party/rust/zlib-rs/src/deflate/algorithm/rle.rs new file mode 100644 index 000000000000..d01d18c48cdd --- /dev/null +++ b/third_party/rust/zlib-rs/src/deflate/algorithm/rle.rs @@ -0,0 +1,83 @@ +#![forbid(unsafe_code)] + +use crate::{ + deflate::{ + compare256::compare256_rle_slice, fill_window, BlockState, DeflateStream, MIN_LOOKAHEAD, + STD_MAX_MATCH, STD_MIN_MATCH, + }, + flush_block, DeflateFlush, +}; + +pub fn deflate_rle(stream: &mut DeflateStream, flush: DeflateFlush) -> BlockState { + let mut match_len = 0; + let mut bflush; + + loop { + // Make sure that we always have enough lookahead, except + // at the end of the input file. We need STD_MAX_MATCH bytes + // for the next match, plus WANT_MIN_MATCH bytes to insert the + // string following the next match. + if stream.state.lookahead < MIN_LOOKAHEAD { + fill_window(stream); + if stream.state.lookahead < MIN_LOOKAHEAD && flush == DeflateFlush::NoFlush { + return BlockState::NeedMore; + } + if stream.state.lookahead == 0 { + break; /* flush the current block */ + } + } + + /* See how many times the previous byte repeats */ + let state = &mut stream.state; + if state.lookahead >= STD_MIN_MATCH && state.strstart > 0 { + let scan = &state.window.filled()[state.strstart - 1..][..3 + 256]; + + { + if scan[0] == scan[1] && scan[1] == scan[2] { + match_len = compare256_rle_slice(scan[0], &scan[3..]) + 2; + match_len = Ord::min(match_len, state.lookahead); + match_len = Ord::min(match_len, STD_MAX_MATCH); + } + } + + assert!( + state.strstart - 1 + match_len <= state.window_size - 1, + "wild scan" + ); + } + + /* Emit match if have run of STD_MIN_MATCH or longer, else emit literal */ + if match_len >= STD_MIN_MATCH { + // check_match(s, s->strstart, s->strstart - 1, match_len); + + bflush = state.tally_dist(1, match_len - STD_MIN_MATCH); + + state.lookahead -= match_len; + state.strstart += match_len; + match_len = 0; + } else { + /* No match, output a literal byte */ + let lc = state.window.filled()[state.strstart]; + bflush = state.tally_lit(lc); + state.lookahead -= 1; + state.strstart += 1; + } + + if bflush { + flush_block!(stream, false); + } + } + + stream.state.insert = 0; + + if flush == DeflateFlush::Finish { + flush_block!(stream, true); + return BlockState::FinishDone; + } + + if !stream.state.sym_buf.is_empty() { + flush_block!(stream, false); + } + + BlockState::BlockDone +} diff --git a/third_party/rust/zlib-rs/src/deflate/algorithm/slow.rs b/third_party/rust/zlib-rs/src/deflate/algorithm/slow.rs new file mode 100644 index 000000000000..3a0fe644d7ef --- /dev/null +++ b/third_party/rust/zlib-rs/src/deflate/algorithm/slow.rs @@ -0,0 +1,160 @@ +#![forbid(unsafe_code)] + +use crate::{ + deflate::{ + fill_window, flush_block_only, BlockState, DeflateStream, Strategy, MIN_LOOKAHEAD, + STD_MIN_MATCH, WANT_MIN_MATCH, + }, + flush_block, DeflateFlush, +}; + +pub fn deflate_slow(stream: &mut DeflateStream, flush: DeflateFlush) -> BlockState { + let mut hash_head; /* head of hash chain */ + let mut bflush; /* set if current block must be flushed */ + let mut dist; + let mut match_len; + + let use_longest_match_slow = stream.state.max_chain_length > 1024; + let valid_distance_range = 1..=stream.state.max_dist() as isize; + + let mut match_available = stream.state.match_available; + + /* Process the input block. */ + loop { + /* Make sure that we always have enough lookahead, except + * at the end of the input file. We need STD_MAX_MATCH bytes + * for the next match, plus WANT_MIN_MATCH bytes to insert the + * string following the next match. + */ + if stream.state.lookahead < MIN_LOOKAHEAD { + fill_window(stream); + if stream.state.lookahead < MIN_LOOKAHEAD && flush == DeflateFlush::NoFlush { + return BlockState::NeedMore; + } + + if stream.state.lookahead == 0 { + break; /* flush the current block */ + } + } + + let state = &mut stream.state; + + /* Insert the string window[strstart .. strstart+2] in the + * dictionary, and set hash_head to the head of the hash chain: + */ + hash_head = if state.lookahead >= WANT_MIN_MATCH { + state.quick_insert_string(state.strstart) + } else { + 0 + }; + + // Find the longest match, discarding those <= prev_length. + state.prev_match = state.match_start as u16; + match_len = STD_MIN_MATCH - 1; + dist = state.strstart as isize - hash_head as isize; + + if valid_distance_range.contains(&dist) + && state.prev_length < state.max_lazy_match + && hash_head != 0 + { + // To simplify the code, we prevent matches with the string + // of window index 0 (in particular we have to avoid a match + // of the string with itself at the start of the input file). + (match_len, state.match_start) = if use_longest_match_slow { + crate::deflate::longest_match::longest_match_slow(state, hash_head) + } else { + crate::deflate::longest_match::longest_match(state, hash_head) + }; + + if match_len <= 5 && (state.strategy == Strategy::Filtered) { + /* If prev_match is also WANT_MIN_MATCH, match_start is garbage + * but we will ignore the current match anyway. + */ + match_len = STD_MIN_MATCH - 1; + } + } + + // If there was a match at the previous step and the current + // match is not better, output the previous match: + if state.prev_length >= STD_MIN_MATCH && match_len <= state.prev_length { + let max_insert = state.strstart + state.lookahead - STD_MIN_MATCH; + /* Do not insert strings in hash table beyond this. */ + + // check_match(s, state.strstart-1, state.prev_match, state.prev_length); + + bflush = state.tally_dist( + state.strstart - 1 - state.prev_match as usize, + state.prev_length - STD_MIN_MATCH, + ); + + /* Insert in hash table all strings up to the end of the match. + * strstart-1 and strstart are already inserted. If there is not + * enough lookahead, the last two strings are not inserted in + * the hash table. + */ + state.prev_length -= 1; + state.lookahead -= state.prev_length; + + let mov_fwd = state.prev_length - 1; + if max_insert > state.strstart { + let insert_cnt = Ord::min(mov_fwd, max_insert - state.strstart); + state.insert_string(state.strstart + 1, insert_cnt); + } + state.prev_length = 0; + state.match_available = false; + match_available = false; + state.strstart += mov_fwd + 1; + + if bflush { + flush_block!(stream, false); + } + } else if match_available { + // If there was no match at the previous position, output a + // single literal. If there was a match but the current match + // is longer, truncate the previous match to a single literal. + let lc = state.window.filled()[state.strstart - 1]; + bflush = state.tally_lit(lc); + if bflush { + flush_block_only(stream, false); + } + + stream.state.prev_length = match_len; + stream.state.strstart += 1; + stream.state.lookahead -= 1; + if stream.avail_out == 0 { + return BlockState::NeedMore; + } + } else { + // There is no previous match to compare with, wait for + // the next step to decide. + state.prev_length = match_len; + state.match_available = true; + match_available = true; + state.strstart += 1; + state.lookahead -= 1; + } + } + + assert_ne!(flush, DeflateFlush::NoFlush, "no flush?"); + + let state = &mut stream.state; + + if state.match_available { + let lc = state.window.filled()[state.strstart - 1]; + let _ = state.tally_lit(lc); + state.match_available = false; + } + + state.insert = Ord::min(state.strstart, STD_MIN_MATCH - 1); + + if flush == DeflateFlush::Finish { + flush_block!(stream, true); + return BlockState::FinishDone; + } + + if !stream.state.sym_buf.is_empty() { + flush_block!(stream, false); + } + + BlockState::BlockDone +} diff --git a/third_party/rust/zlib-rs/src/deflate/algorithm/stored.rs b/third_party/rust/zlib-rs/src/deflate/algorithm/stored.rs new file mode 100644 index 000000000000..172bf3a9189f --- /dev/null +++ b/third_party/rust/zlib-rs/src/deflate/algorithm/stored.rs @@ -0,0 +1,271 @@ +use crate::{ + deflate::{ + flush_pending, read_buf_window, zng_tr_stored_block, BlockState, DeflateStream, MAX_STORED, + }, + DeflateFlush, +}; + +pub fn deflate_stored(stream: &mut DeflateStream, flush: DeflateFlush) -> BlockState { + // Smallest worthy block size when not flushing or finishing. By default + // this is 32K. This can be as small as 507 bytes for memLevel == 1. For + // large input and output buffers, the stored block size will be larger. + let min_block = Ord::min( + stream.state.bit_writer.pending.capacity() - 5, + stream.state.w_size, + ); + + // Copy as many min_block or larger stored blocks directly to next_out as + // possible. If flushing, copy the remaining available input to next_out as + // stored blocks, if there is enough space. + + // unsigned len, left, have, last = 0; + let mut have; + let mut last = false; + let mut used = stream.avail_in; + loop { + // maximum deflate stored block length + let mut len = MAX_STORED; + + // number of header bytes + have = ((stream.state.bit_writer.bits_used + 42) / 8) as usize; + + // we need room for at least the header + if stream.avail_out < have as u32 { + break; + } + + let left = stream.state.strstart as isize - stream.state.block_start; + let left = Ord::max(0, left) as usize; + + have = stream.avail_out as usize - have; + + if len > left + stream.avail_in as usize { + // limit len to the input + len = left + stream.avail_in as usize; + } + + len = Ord::min(len, have); + + // If the stored block would be less than min_block in length, or if + // unable to copy all of the available input when flushing, then try + // copying to the window and the pending buffer instead. Also don't + // write an empty block when flushing -- deflate() does that. + if len < min_block + && ((len == 0 && flush != DeflateFlush::Finish) + || flush == DeflateFlush::NoFlush + || len != left + stream.avail_in as usize) + { + break; + } + + // Make a dummy stored block in pending to get the header bytes, + // including any pending bits. This also updates the debugging counts. + last = flush == DeflateFlush::Finish && len == left + stream.avail_in as usize; + zng_tr_stored_block(stream.state, 0..0, last); + + /* Replace the lengths in the dummy stored block with len. */ + stream.state.bit_writer.pending.rewind(4); + stream + .state + .bit_writer + .pending + .extend(&(len as u16).to_le_bytes()); + stream + .state + .bit_writer + .pending + .extend(&(!len as u16).to_le_bytes()); + + // Write the stored block header bytes. + flush_pending(stream); + + // TODO debug counts? + + if left > 0 { + let left = Ord::min(left, len); + let src = &stream.state.window.filled()[stream.state.block_start as usize..]; + + unsafe { core::ptr::copy_nonoverlapping(src.as_ptr(), stream.next_out, left) }; + + stream.next_out = stream.next_out.wrapping_add(left); + stream.avail_out = stream.avail_out.wrapping_sub(left as _); + stream.total_out = stream.total_out.wrapping_add(left as _); + stream.state.block_start += left as isize; + len -= left; + } + + // Copy uncompressed bytes directly from next_in to next_out, updating the check value. + if len > 0 { + read_buf_direct_copy(stream, len); + } + + if last { + break; + } + } + + // Update the sliding window with the last s->w_size bytes of the copied + // data, or append all of the copied data to the existing window if less + // than s->w_size bytes were copied. Also update the number of bytes to + // insert in the hash tables, in the event that deflateParams() switches to + // a non-zero compression level. + used -= stream.avail_in; /* number of input bytes directly copied */ + + if used > 0 { + let state = &mut stream.state; + // If any input was used, then no unused input remains in the window, therefore s->block_start == s->strstart. + if used as usize >= state.w_size { + /* supplant the previous history */ + state.matches = 2; /* clear hash */ + + let src = stream.next_in.wrapping_sub(state.w_size); + + unsafe { state.window.copy_and_initialize(0..state.w_size, src) }; + + state.strstart = state.w_size; + state.insert = state.strstart; + } else { + if state.window_size - state.strstart <= used as usize { + /* Slide the window down. */ + state.strstart -= state.w_size; + + state + .window + .filled_mut() + .copy_within(state.w_size..state.w_size + state.strstart, 0); + + if state.matches < 2 { + state.matches += 1; /* add a pending slide_hash() */ + } + state.insert = Ord::min(state.insert, state.strstart); + } + + let src = stream.next_in.wrapping_sub(used as usize); + let dst = state.strstart..state.strstart + used as usize; + unsafe { state.window.copy_and_initialize(dst, src) }; + + state.strstart += used as usize; + state.insert += Ord::min(used as usize, state.w_size - state.insert); + } + state.block_start = state.strstart as isize; + } + + if last { + return BlockState::FinishDone; + } + + // If flushing and all input has been consumed, then done. + if flush != DeflateFlush::NoFlush + && flush != DeflateFlush::Finish + && stream.avail_in == 0 + && stream.state.strstart as isize == stream.state.block_start + { + return BlockState::BlockDone; + } + + // Fill the window with any remaining input + let mut have = stream.state.window_size - stream.state.strstart; + if stream.avail_in as usize > have && stream.state.block_start >= stream.state.w_size as isize { + // slide the window down + let state = &mut stream.state; + state.block_start -= state.w_size as isize; + state.strstart -= state.w_size; + state + .window + .filled_mut() + .copy_within(state.w_size..state.w_size + state.strstart, 0); + + if state.matches < 2 { + // add a pending slide_hash + state.matches += 1; + } + + have += state.w_size; // more space now + state.insert = Ord::min(state.insert, state.strstart); + } + + let have = Ord::min(have, stream.avail_in as usize); + if have > 0 { + read_buf_window(stream, stream.state.strstart, have); + + let state = &mut stream.state; + state.strstart += have; + state.insert += Ord::min(have, state.w_size - state.insert); + } + + // There was not enough avail_out to write a complete worthy or flushed + // stored block to next_out. Write a stored block to pending instead, if we + // have enough input for a worthy block, or if flushing and there is enough + // room for the remaining input as a stored block in the pending buffer. + + // number of header bytes + let state = &mut stream.state; + let have = ((state.bit_writer.bits_used + 42) >> 3) as usize; + + // maximum stored block length that will fit in pending: + let have = Ord::min(state.bit_writer.pending.capacity() - have, MAX_STORED); + let min_block = Ord::min(have, state.w_size); + let left = state.strstart as isize - state.block_start; + + if left >= min_block as isize + || ((left > 0 || flush == DeflateFlush::Finish) + && flush != DeflateFlush::NoFlush + && stream.avail_in == 0 + && left <= have as isize) + { + let len = Ord::min(left as usize, have); // TODO wrapping? + last = flush == DeflateFlush::Finish && stream.avail_in == 0 && len == (left as usize); + + let range = state.block_start as usize..state.block_start as usize + len; + zng_tr_stored_block(state, range, last); + + state.block_start += len as isize; + flush_pending(stream); + } + + // We've done all we can with the available input and output. + if last { + BlockState::FinishStarted + } else { + BlockState::NeedMore + } +} + +fn read_buf_direct_copy(stream: &mut DeflateStream, size: usize) -> usize { + let len = Ord::min(stream.avail_in as usize, size); + let output = stream.next_out; + + if len == 0 { + return 0; + } + + stream.avail_in -= len as u32; + + if stream.state.wrap == 2 { + // we likely cannot fuse the crc32 and the copy here because the input can be changed by + // a concurrent thread. Therefore it cannot be converted into a slice! + unsafe { core::ptr::copy_nonoverlapping(stream.next_in, output, len) } + + let data = unsafe { core::slice::from_raw_parts(output, len) }; + stream.state.crc_fold.fold(data, 0); + } else if stream.state.wrap == 1 { + // we cannot fuse the adler and the copy in our case, because adler32 takes a slice. + // Another process is allowed to concurrently modify stream.next_in, so we cannot turn it + // into a rust slice (violates its safety requirements) + unsafe { core::ptr::copy_nonoverlapping(stream.next_in, output, len) } + + let data = unsafe { core::slice::from_raw_parts(output, len) }; + stream.adler = crate::adler32::adler32(stream.adler as u32, data) as _; + } else { + unsafe { core::ptr::copy_nonoverlapping(stream.next_in, output, len) } + } + + stream.next_in = stream.next_in.wrapping_add(len); + stream.total_in += len as crate::c_api::z_size; + + stream.next_out = stream.next_out.wrapping_add(len as _); + stream.avail_out = stream.avail_out.wrapping_sub(len as _); + stream.total_out = stream.total_out.wrapping_add(len as _); + + len +} diff --git a/third_party/rust/zlib-rs/src/deflate/compare256.rs b/third_party/rust/zlib-rs/src/deflate/compare256.rs new file mode 100644 index 000000000000..89688584f701 --- /dev/null +++ b/third_party/rust/zlib-rs/src/deflate/compare256.rs @@ -0,0 +1,216 @@ +#[cfg(test)] +const MAX_COMPARE_SIZE: usize = 256; + +pub fn compare256_slice(src0: &[u8], src1: &[u8]) -> usize { + let src0 = first_chunk::<_, 256>(src0).unwrap(); + let src1 = first_chunk::<_, 256>(src1).unwrap(); + + compare256(src0, src1) +} + +fn compare256(src0: &[u8; 256], src1: &[u8; 256]) -> usize { + #[cfg(all(target_arch = "x86_64", feature = "std"))] + if std::is_x86_feature_detected!("avx2") { + debug_assert_eq!(avx2::compare256(src0, src1), rust::compare256(src0, src1)); + + return avx2::compare256(src0, src1); + } + + #[cfg(all(target_arch = "aarch64", feature = "std"))] + if std::arch::is_aarch64_feature_detected!("neon") { + debug_assert_eq!(neon::compare256(src0, src1), rust::compare256(src0, src1)); + + return neon::compare256(src0, src1); + } + + rust::compare256(src0, src1) +} + +pub fn compare256_rle_slice(byte: u8, src: &[u8]) -> usize { + rust::compare256_rle(byte, src) +} + +#[inline] +pub const fn first_chunk(slice: &[T]) -> Option<&[T; N]> { + if slice.len() < N { + None + } else { + // SAFETY: We explicitly check for the correct number of elements, + // and do not let the reference outlive the slice. + Some(unsafe { &*(slice.as_ptr() as *const [T; N]) }) + } +} + +mod rust { + + pub fn compare256(src0: &[u8; 256], src1: &[u8; 256]) -> usize { + // only unrolls 4 iterations; zlib-ng unrolls 8 + src0.iter().zip(src1).take_while(|(x, y)| x == y).count() + } + + // run-length encoding + pub fn compare256_rle(byte: u8, src: &[u8]) -> usize { + assert!(src.len() >= 256, "too short {}", src.len()); + + let mut sv = byte as u64; + sv |= sv << 8; + sv |= sv << 16; + sv |= sv << 32; + + let mut len = 0; + + // this optimizes well because we statically limit the slice to 256 bytes. + // the loop gets unrolled 4 times automatically. + for chunk in src[..256].chunks_exact(8) { + let mv = u64::from_ne_bytes(chunk.try_into().unwrap()); + + let diff = sv ^ mv; + + if diff > 0 { + let match_byte = diff.trailing_zeros() / 8; + return len + match_byte as usize; + } + + len += 8 + } + + 256 + } + + #[test] + fn test_compare256() { + let str1 = [b'a'; super::MAX_COMPARE_SIZE]; + let mut str2 = [b'a'; super::MAX_COMPARE_SIZE]; + + for i in 0..str1.len() { + str2[i] = 0; + + let match_len = compare256(&str1, &str2); + assert_eq!(match_len, i); + + str2[i] = b'a'; + } + } + + #[test] + fn test_compare256_rle() { + let mut string = [b'a'; super::MAX_COMPARE_SIZE]; + + for i in 0..string.len() { + string[i] = 0; + + let match_len = compare256_rle(b'a', &string); + assert_eq!(match_len, i); + + string[i] = b'a'; + } + } +} + +#[cfg(target_arch = "aarch64")] +mod neon { + use core::arch::aarch64::{ + uint8x16_t, veorq_u8, vgetq_lane_u64, vld1q_u8, vreinterpretq_u64_u8, + }; + + pub fn compare256(src0: &[u8; 256], src1: &[u8; 256]) -> usize { + let src0: &[[u8; 16]; 16] = unsafe { core::mem::transmute(src0) }; + let src1: &[[u8; 16]; 16] = unsafe { core::mem::transmute(src1) }; + + let mut len = 0; + + for (a, b) in src0.iter().zip(src1) { + unsafe { + let a: uint8x16_t = vld1q_u8(a.as_ptr()); + let b: uint8x16_t = vld1q_u8(b.as_ptr()); + + let cmp = veorq_u8(a, b); + + let lane = vgetq_lane_u64(vreinterpretq_u64_u8(cmp), 0); + if lane != 0 { + let match_byte = lane.trailing_zeros() / 8; + return len + match_byte as usize; + } + + len += 8; + + let lane = vgetq_lane_u64(vreinterpretq_u64_u8(cmp), 1); + if lane != 0 { + let match_byte = lane.trailing_zeros() / 8; + return len + match_byte as usize; + } + + len += 8; + } + } + + 256 + } + + #[test] + fn test_compare256() { + if std::arch::is_aarch64_feature_detected!("neon") { + let str1 = [b'a'; super::MAX_COMPARE_SIZE]; + let mut str2 = [b'a'; super::MAX_COMPARE_SIZE]; + + for i in 0..str1.len() { + str2[i] = 0; + + let match_len = compare256(&str1, &str2); + assert_eq!(match_len, i); + + str2[i] = b'a'; + } + } + } +} + +#[cfg(target_arch = "x86_64")] +mod avx2 { + use core::arch::x86_64::{ + __m256i, _mm256_cmpeq_epi8, _mm256_loadu_si256, _mm256_movemask_epi8, + }; + + pub fn compare256(src0: &[u8; 256], src1: &[u8; 256]) -> usize { + let src0: &[[u8; 32]; 8] = unsafe { core::mem::transmute(src0) }; + let src1: &[[u8; 32]; 8] = unsafe { core::mem::transmute(src1) }; + + let mut len = 0; + + unsafe { + for (chunk0, chunk1) in src0.iter().zip(src1) { + let ymm_src0 = _mm256_loadu_si256(chunk0.as_ptr() as *const __m256i); + let ymm_src1 = _mm256_loadu_si256(chunk1.as_ptr() as *const __m256i); + + let ymm_cmp = _mm256_cmpeq_epi8(ymm_src0, ymm_src1); /* non-identical bytes = 00, identical bytes = FF */ + let mask = _mm256_movemask_epi8(ymm_cmp) as u32; + + if mask != 0xFFFFFFFF { + let match_byte = (!mask).trailing_zeros(); /* Invert bits so identical = 0 */ + return len + match_byte as usize; + } + + len += 32; + } + } + + 256 + } + + #[test] + fn test_compare256() { + if std::arch::is_x86_feature_detected!("avx2") { + let str1 = [b'a'; super::MAX_COMPARE_SIZE]; + let mut str2 = [b'a'; super::MAX_COMPARE_SIZE]; + + for i in 0..str1.len() { + str2[i] = 0; + + let match_len = compare256(&str1, &str2); + assert_eq!(match_len, i); + + str2[i] = b'a'; + } + } + } +} diff --git a/third_party/rust/zlib-rs/src/deflate/hash_calc.rs b/third_party/rust/zlib-rs/src/deflate/hash_calc.rs new file mode 100644 index 000000000000..57b503798f31 --- /dev/null +++ b/third_party/rust/zlib-rs/src/deflate/hash_calc.rs @@ -0,0 +1,209 @@ +use crate::deflate::{State, HASH_SIZE, STD_MIN_MATCH}; + +#[derive(Debug, Clone, Copy)] +pub enum HashCalcVariant { + Standard, + Crc32, + Roll, +} + +pub trait HashCalc { + const HASH_CALC_OFFSET: usize; + const HASH_CALC_MASK: u32; + + fn hash_calc(h: u32, val: u32) -> u32; + + fn update_hash(h: u32, val: u32) -> u32 { + Self::hash_calc(h, val) & Self::HASH_CALC_MASK + } + + fn quick_insert_string(state: &mut State, string: usize) -> u16 { + let slice = &state.window.filled()[string + Self::HASH_CALC_OFFSET..]; + let val = u32::from_ne_bytes(slice[..4].try_into().unwrap()); + + let hm = (Self::hash_calc(0, val) & Self::HASH_CALC_MASK) as usize; + + let head = state.head[hm]; + if head != string as u16 { + state.prev[string & state.w_mask] = head; + state.head[hm] = string as u16; + } + + head + } + + fn insert_string(state: &mut State, string: usize, count: usize) { + let slice = &state.window.filled()[string + Self::HASH_CALC_OFFSET..]; + + // .take(count) generates worse assembly + for (i, w) in slice[..count + 3].windows(4).enumerate() { + let idx = string as u16 + i as u16; + + let val = u32::from_ne_bytes(w.try_into().unwrap()); + + let hm = (Self::hash_calc(0, val) & Self::HASH_CALC_MASK) as usize; + + let head = state.head[hm]; + if head != idx { + state.prev[idx as usize & state.w_mask] = head; + state.head[hm] = idx; + } + } + } +} + +pub struct StandardHashCalc; + +impl HashCalc for StandardHashCalc { + const HASH_CALC_OFFSET: usize = 0; + + const HASH_CALC_MASK: u32 = (HASH_SIZE - 1) as u32; + + fn hash_calc(_: u32, val: u32) -> u32 { + const HASH_SLIDE: u32 = 16; + val.wrapping_mul(2654435761) >> HASH_SLIDE + } +} + +pub struct RollHashCalc; + +impl HashCalc for RollHashCalc { + const HASH_CALC_OFFSET: usize = STD_MIN_MATCH - 1; + + const HASH_CALC_MASK: u32 = (1 << 15) - 1; + + fn hash_calc(h: u32, val: u32) -> u32 { + const HASH_SLIDE: u32 = 5; + (h << HASH_SLIDE) ^ val + } + + fn quick_insert_string(state: &mut State, string: usize) -> u16 { + let val = state.window.filled()[string + Self::HASH_CALC_OFFSET] as u32; + + state.ins_h = Self::hash_calc(state.ins_h as u32, val) as usize; + state.ins_h &= Self::HASH_CALC_MASK as usize; + + let hm = state.ins_h; + + let head = state.head[hm]; + if head != string as u16 { + state.prev[string & state.w_mask] = head; + state.head[hm] = string as u16; + } + + head + } + + fn insert_string(state: &mut State, string: usize, count: usize) { + let slice = &state.window.filled()[string + Self::HASH_CALC_OFFSET..][..count]; + + for (i, val) in slice.iter().copied().enumerate() { + let idx = string as u16 + i as u16; + + state.ins_h = Self::hash_calc(state.ins_h as u32, val as u32) as usize; + state.ins_h &= Self::HASH_CALC_MASK as usize; + let hm = state.ins_h; + + let head = state.head[hm]; + if head != idx { + state.prev[idx as usize & state.w_mask] = head; + state.head[hm] = idx; + } + } + } +} + +pub struct Crc32HashCalc; + +impl Crc32HashCalc { + pub fn is_supported() -> bool { + if cfg!(target_arch = "x86") || cfg!(target_arch = "x86_64") { + return true; + } + + // zlib-ng no longer special-cases on aarch64 + #[cfg(all(target_arch = "aarch64", feature = "std"))] + // return std::arch::is_aarch64_feature_detected!("crc"); + return false; + + #[allow(unreachable_code)] + false + } +} + +impl HashCalc for Crc32HashCalc { + const HASH_CALC_OFFSET: usize = 0; + + const HASH_CALC_MASK: u32 = (HASH_SIZE - 1) as u32; + + #[cfg(target_arch = "x86")] + fn hash_calc(h: u32, val: u32) -> u32 { + unsafe { core::arch::x86::_mm_crc32_u32(h, val) } + } + + #[cfg(target_arch = "x86_64")] + fn hash_calc(h: u32, val: u32) -> u32 { + unsafe { core::arch::x86_64::_mm_crc32_u32(h, val) } + } + + #[cfg(target_arch = "aarch64")] + fn hash_calc(h: u32, val: u32) -> u32 { + unsafe { crate::crc32::acle::__crc32cw(h, val) } + } + + #[cfg(not(any(target_arch = "x86", target_arch = "x86_64", target_arch = "aarch64")))] + fn hash_calc(h: u32, val: u32) -> u32 { + assert!(!Self::is_supported()); + unimplemented!("there is no hardware support on this platform") + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn crc32_hash_calc() { + assert_eq!(Crc32HashCalc::hash_calc(0, 807411760), 2423125009); + assert_eq!(Crc32HashCalc::hash_calc(0, 540024864), 1452438466); + assert_eq!(Crc32HashCalc::hash_calc(0, 538980384), 435552201); + assert_eq!(Crc32HashCalc::hash_calc(0, 807411760), 2423125009); + assert_eq!(Crc32HashCalc::hash_calc(0, 540024864), 1452438466); + assert_eq!(Crc32HashCalc::hash_calc(0, 538980384), 435552201); + assert_eq!(Crc32HashCalc::hash_calc(0, 807411760), 2423125009); + assert_eq!(Crc32HashCalc::hash_calc(0, 540024864), 1452438466); + assert_eq!(Crc32HashCalc::hash_calc(0, 538980384), 435552201); + assert_eq!(Crc32HashCalc::hash_calc(0, 807411760), 2423125009); + assert_eq!(Crc32HashCalc::hash_calc(0, 540024864), 1452438466); + assert_eq!(Crc32HashCalc::hash_calc(0, 538980384), 435552201); + assert_eq!(Crc32HashCalc::hash_calc(0, 807411760), 2423125009); + assert_eq!(Crc32HashCalc::hash_calc(0, 170926112), 500028708); + assert_eq!(Crc32HashCalc::hash_calc(0, 537538592), 3694129053); + assert_eq!(Crc32HashCalc::hash_calc(0, 538970672), 373925026); + assert_eq!(Crc32HashCalc::hash_calc(0, 538976266), 4149335727); + assert_eq!(Crc32HashCalc::hash_calc(0, 538976288), 1767342659); + assert_eq!(Crc32HashCalc::hash_calc(0, 941629472), 4090502627); + assert_eq!(Crc32HashCalc::hash_calc(0, 775430176), 1744703325); + } + + #[test] + fn roll_hash_calc() { + assert_eq!(RollHashCalc::hash_calc(2565, 93), 82173); + assert_eq!(RollHashCalc::hash_calc(16637, 10), 532394); + assert_eq!(RollHashCalc::hash_calc(8106, 100), 259364); + assert_eq!(RollHashCalc::hash_calc(29988, 101), 959717); + assert_eq!(RollHashCalc::hash_calc(9445, 98), 302274); + assert_eq!(RollHashCalc::hash_calc(7362, 117), 235573); + assert_eq!(RollHashCalc::hash_calc(6197, 103), 198343); + assert_eq!(RollHashCalc::hash_calc(1735, 32), 55488); + assert_eq!(RollHashCalc::hash_calc(22720, 61), 727101); + assert_eq!(RollHashCalc::hash_calc(6205, 32), 198528); + assert_eq!(RollHashCalc::hash_calc(3826, 117), 122421); + assert_eq!(RollHashCalc::hash_calc(24117, 101), 771781); + } + + #[test] + fn standard_hash_calc() { + assert_eq!(StandardHashCalc::hash_calc(0, 721420288), 47872); + } +} diff --git a/third_party/rust/zlib-rs/src/deflate/longest_match.rs b/third_party/rust/zlib-rs/src/deflate/longest_match.rs new file mode 100644 index 000000000000..72f200b48d51 --- /dev/null +++ b/third_party/rust/zlib-rs/src/deflate/longest_match.rs @@ -0,0 +1,318 @@ +use crate::deflate::{State, MIN_LOOKAHEAD, STD_MAX_MATCH, STD_MIN_MATCH}; + +type Pos = u16; + +const EARLY_EXIT_TRIGGER_LEVEL: i8 = 5; + +pub fn longest_match(state: &crate::deflate::State, cur_match: u16) -> (usize, usize) { + longest_match_help::(state, cur_match) +} + +pub fn longest_match_slow(state: &crate::deflate::State, cur_match: u16) -> (usize, usize) { + longest_match_help::(state, cur_match) +} + +fn longest_match_help( + state: &crate::deflate::State, + mut cur_match: u16, +) -> (usize, usize) { + let mut match_start = state.match_start; + + let strstart = state.strstart; + let wmask = state.w_mask; + let window = state.window.filled(); + let scan = &window[strstart..]; + let mut limit: Pos; + let limit_base: Pos; + let early_exit: bool; + + let mut chain_length: usize; + let mut best_len: usize; + + let lookahead = state.lookahead; + let mut match_offset = 0; + + let mut scan_start = [0u8; 8]; + let mut scan_end = [0u8; 8]; + + macro_rules! goto_next_in_chain { + () => { + chain_length -= 1; + if chain_length > 0 { + cur_match = state.prev[cur_match as usize & wmask]; + + if cur_match > limit { + continue; + } + } + + return (best_len, match_start); + }; + } + + // The code is optimized for STD_MAX_MATCH-2 multiple of 16. + assert_eq!(STD_MAX_MATCH, 258, "Code too clever"); + + best_len = if state.prev_length > 0 { + state.prev_length + } else { + STD_MIN_MATCH - 1 + }; + + let mut offset = best_len - 1; + + // we're assuming we can do a fast(ish) unaligned 64-bit read + if best_len >= core::mem::size_of::() { + offset -= 4; + } + + if best_len >= core::mem::size_of::() { + offset -= 2; + } + + scan_start.copy_from_slice(&scan[..core::mem::size_of::()]); + scan_end.copy_from_slice(&scan[offset..][..core::mem::size_of::()]); + + let mut mbase_start = window.as_ptr(); + let mut mbase_end = window[offset..].as_ptr(); + + // Don't waste too much time by following a chain if we already have a good match + chain_length = state.max_chain_length; + if best_len >= state.good_match { + chain_length >>= 2; + } + let nice_match = state.nice_match; + + // Stop when cur_match becomes <= limit. To simplify the code, + // we prevent matches with the string of window index 0 + limit = strstart.saturating_sub(state.max_dist()) as Pos; + + // look for a better string offset + if SLOW { + limit_base = limit; + + if best_len >= STD_MIN_MATCH { + /* We're continuing search (lazy evaluation). */ + let mut pos: Pos; + + // Find a most distant chain starting from scan with index=1 (index=0 corresponds + // to cur_match). We cannot use s->prev[strstart+1,...] immediately, because + // these strings are not yet inserted into the hash table. + let Some([_cur_match, scan1, scan2, scanrest @ ..]) = scan.get(..best_len + 1) else { + panic!("invalid scan"); + }; + + let mut hash = 0; + hash = state.update_hash(hash, *scan1 as u32); + hash = state.update_hash(hash, *scan2 as u32); + + for (i, b) in scanrest.iter().enumerate() { + hash = state.update_hash(hash, *b as u32); + + /* If we're starting with best_len >= 3, we can use offset search. */ + pos = state.head[hash as usize]; + if pos < cur_match { + match_offset = (i + 1) as Pos; + cur_match = pos; + } + } + + /* Update offset-dependent variables */ + limit = limit_base + match_offset; + if cur_match <= limit { + return break_matching(state, best_len, match_start); + } + + mbase_start = mbase_start.wrapping_sub(match_offset as usize); + mbase_end = mbase_end.wrapping_sub(match_offset as usize); + } + + early_exit = false; + } else { + // must initialize this variable + limit_base = 0; + early_exit = state.level < EARLY_EXIT_TRIGGER_LEVEL; + } + + assert!( + strstart <= state.window_size - MIN_LOOKAHEAD, + "need lookahead" + ); + + loop { + if cur_match as usize >= strstart { + break; + } + + // Skip to next match if the match length cannot increase or if the match length is + // less than 2. Note that the checks below for insufficient lookahead only occur + // occasionally for performance reasons. + // Therefore uninitialized memory will be accessed and conditional jumps will be made + // that depend on those values. However the length of the match is limited to the + // lookahead, so the output of deflate is not affected by the uninitialized values. + + // # Safety + // + // The two pointers must be valid for reads of N bytes. + #[inline(always)] + unsafe fn memcmp_n_ptr(src0: *const u8, src1: *const u8) -> bool { + let src0_cmp = core::ptr::read(src0 as *const [u8; N]); + let src1_cmp = core::ptr::read(src1 as *const [u8; N]); + + src0_cmp == src1_cmp + } + + #[inline(always)] + unsafe fn is_match( + cur_match: u16, + mbase_start: *const u8, + mbase_end: *const u8, + scan_start: *const u8, + scan_end: *const u8, + ) -> bool { + let be = mbase_end.wrapping_add(cur_match as usize); + let bs = mbase_start.wrapping_add(cur_match as usize); + + memcmp_n_ptr::(be, scan_end) && memcmp_n_ptr::(bs, scan_start) + } + + // first, do a quick check on the start and end bytes. Go to the next item in the chain if + // these bytes don't match. + unsafe { + let scan_start = scan_start.as_ptr(); + let scan_end = scan_end.as_ptr(); + + if best_len < core::mem::size_of::() { + loop { + if is_match::<2>(cur_match, mbase_start, mbase_end, scan_start, scan_end) { + break; + } + + goto_next_in_chain!(); + } + } else if best_len >= core::mem::size_of::() { + loop { + if is_match::<8>(cur_match, mbase_start, mbase_end, scan_start, scan_end) { + break; + } + + goto_next_in_chain!(); + } + } else { + loop { + if is_match::<4>(cur_match, mbase_start, mbase_end, scan_start, scan_end) { + break; + } + + goto_next_in_chain!(); + } + } + } + + // we know that there is at least some match. Now count how many bytes really match + let len = { + // TODO this just looks so incredibly unsafe! + let src1: &[u8; 256] = + unsafe { &*mbase_start.wrapping_add(cur_match as usize + 2).cast() }; + + crate::deflate::compare256::compare256_slice(&scan[2..], src1) + 2 + }; + + assert!( + scan.as_ptr() as usize + len <= window.as_ptr() as usize + (state.window_size - 1), + "wild scan" + ); + + if len > best_len { + match_start = (cur_match - match_offset) as usize; + + /* Do not look for matches beyond the end of the input. */ + if len > lookahead { + return (lookahead, match_start); + } + best_len = len; + if best_len >= nice_match { + return (best_len, match_start); + } + + offset = best_len - 1; + if best_len >= core::mem::size_of::() { + offset -= 2; + if best_len >= core::mem::size_of::() { + offset -= 4; + } + } + + scan_end.copy_from_slice(&scan[offset..][..core::mem::size_of::()]); + + // Look for a better string offset + if SLOW && len > STD_MIN_MATCH && match_start + len < strstart { + let mut pos: Pos; + // uint32_t i, hash; + // unsigned char *scan_endstr; + + /* Go back to offset 0 */ + cur_match -= match_offset; + match_offset = 0; + let mut next_pos = cur_match; + + for i in 0..=len - STD_MIN_MATCH { + pos = state.prev[(cur_match as usize + i) & wmask]; + if pos < next_pos { + /* Hash chain is more distant, use it */ + if pos <= limit_base + i as Pos { + return break_matching(state, best_len, match_start); + } + next_pos = pos; + match_offset = i as Pos; + } + } + /* Switch cur_match to next_pos chain */ + cur_match = next_pos; + + /* Try hash head at len-(STD_MIN_MATCH-1) position to see if we could get + * a better cur_match at the end of string. Using (STD_MIN_MATCH-1) lets + * us include one more byte into hash - the byte which will be checked + * in main loop now, and which allows to grow match by 1. + */ + let [scan0, scan1, scan2, ..] = scan[len - (STD_MIN_MATCH + 1)..] else { + panic!("index out of bounds"); + }; + + let mut hash = 0; + hash = state.update_hash(hash, scan0 as u32); + hash = state.update_hash(hash, scan1 as u32); + hash = state.update_hash(hash, scan2 as u32); + + pos = state.head[hash as usize]; + if pos < cur_match { + match_offset = (len - (STD_MIN_MATCH + 1)) as Pos; + if pos <= limit_base + match_offset { + return break_matching(state, best_len, match_start); + } + cur_match = pos; + } + + /* Update offset-dependent variables */ + limit = limit_base + match_offset; + mbase_start = window.as_ptr().wrapping_sub(match_offset as usize); + mbase_end = mbase_start.wrapping_add(offset); + continue; + } + + mbase_end = mbase_start.wrapping_add(offset); + } else if !SLOW && early_exit { + // The probability of finding a match later if we here is pretty low, so for + // performance it's best to outright stop here for the lower compression levels + break; + } + + goto_next_in_chain!(); + } + + (best_len, match_start) +} + +fn break_matching(state: &State, best_len: usize, match_start: usize) -> (usize, usize) { + (Ord::min(best_len, state.lookahead), match_start) +} diff --git a/third_party/rust/zlib-rs/src/deflate/pending.rs b/third_party/rust/zlib-rs/src/deflate/pending.rs new file mode 100644 index 000000000000..c7c9c4d99508 --- /dev/null +++ b/third_party/rust/zlib-rs/src/deflate/pending.rs @@ -0,0 +1,95 @@ +use core::marker::PhantomData; + +use crate::allocate::Allocator; + +pub struct Pending<'a> { + buf: *mut u8, + out: *mut u8, + pub(crate) pending: usize, + end: *mut u8, + _marker: PhantomData<&'a mut [u8]>, +} + +impl<'a> Pending<'a> { + pub fn reset_keep(&mut self) { + // keep the buffer as it is + self.pending = 0; + } + + pub fn pending(&self) -> &[u8] { + unsafe { core::slice::from_raw_parts(self.out, self.pending) } + } + + pub(crate) fn remaining(&self) -> usize { + self.end as usize - self.out as usize + } + + pub(crate) fn capacity(&self) -> usize { + self.end as usize - self.buf as usize + } + + #[inline(always)] + #[track_caller] + pub fn advance(&mut self, n: usize) { + assert!(n <= self.remaining(), "advancing past the end"); + debug_assert!(self.pending >= n); + + self.out = self.out.wrapping_add(n); + self.pending -= n; + + if self.pending == 0 { + self.out = self.buf; + } + } + + #[inline(always)] + #[track_caller] + pub fn rewind(&mut self, n: usize) { + assert!(n <= self.pending, "rewinding past then start"); + + self.pending -= n; + } + + #[inline(always)] + #[track_caller] + pub fn extend(&mut self, buf: &[u8]) { + assert!( + self.remaining() >= buf.len(), + "buf.len() must fit in remaining()" + ); + + unsafe { + core::ptr::copy_nonoverlapping(buf.as_ptr(), self.out.add(self.pending), buf.len()); + } + + self.pending += buf.len(); + } + + pub(crate) fn new_in(alloc: &Allocator<'a>, len: usize) -> Option { + let range = alloc.allocate_slice::(len)?.as_mut_ptr_range(); + + Some(Self { + buf: range.start as *mut u8, + out: range.start as *mut u8, + end: range.end as *mut u8, + pending: 0, + _marker: PhantomData, + }) + } + + pub(crate) fn clone_in(&self, alloc: &Allocator<'a>) -> Option { + let len = self.end as usize - self.buf as usize; + let mut clone = Self::new_in(alloc, len)?; + + unsafe { core::ptr::copy_nonoverlapping(self.buf, clone.buf, len) }; + clone.out = unsafe { clone.buf.add(self.out as usize - self.buf as usize) }; + clone.pending = self.pending; + + Some(clone) + } + + pub(crate) unsafe fn drop_in(&self, alloc: &Allocator) { + let len = self.end as usize - self.buf as usize; + alloc.deallocate(self.buf, len); + } +} diff --git a/third_party/rust/zlib-rs/src/deflate/slide_hash.rs b/third_party/rust/zlib-rs/src/deflate/slide_hash.rs new file mode 100644 index 000000000000..0b003fb93bc7 --- /dev/null +++ b/third_party/rust/zlib-rs/src/deflate/slide_hash.rs @@ -0,0 +1,164 @@ +pub fn slide_hash(state: &mut crate::deflate::State) { + let wsize = state.w_size as u16; + + slide_hash_chain(state.head, wsize); + slide_hash_chain(state.prev, wsize); +} + +fn slide_hash_chain(table: &mut [u16], wsize: u16) { + #[cfg(all(target_arch = "x86_64", feature = "std"))] + if std::is_x86_feature_detected!("avx2") { + return avx2::slide_hash_chain(table, wsize); + } + + #[cfg(all(target_arch = "aarch64", feature = "std"))] + if std::arch::is_aarch64_feature_detected!("neon") { + return neon::slide_hash_chain(table, wsize); + } + + rust::slide_hash_chain(table, wsize); +} + +mod rust { + pub fn slide_hash_chain(table: &mut [u16], wsize: u16) { + for m in table.iter_mut() { + *m = m.saturating_sub(wsize); + } + } +} + +#[cfg(target_arch = "aarch64")] +mod neon { + use core::arch::aarch64::{ + uint16x8_t, uint16x8x4_t, vdupq_n_u16, vld1q_u16_x4, vqsubq_u16, vst1q_u16_x4, + }; + + pub fn slide_hash_chain(table: &mut [u16], wsize: u16) { + assert!(std::arch::is_aarch64_feature_detected!("neon")); + unsafe { slide_hash_chain_internal(table, wsize) } + } + + #[target_feature(enable = "neon")] + unsafe fn slide_hash_chain_internal(table: &mut [u16], wsize: u16) { + debug_assert_eq!(table.len() % 32, 0); + + let v = unsafe { vdupq_n_u16(wsize) }; + + for chunk in table.chunks_exact_mut(32) { + unsafe { + let p0 = vld1q_u16_x4(chunk.as_ptr()); + let p0 = vqsubq_u16_x4_x1(p0, v); + vst1q_u16_x4(chunk.as_mut_ptr(), p0); + } + } + } + + #[target_feature(enable = "neon")] + unsafe fn vqsubq_u16_x4_x1(a: uint16x8x4_t, b: uint16x8_t) -> uint16x8x4_t { + uint16x8x4_t( + vqsubq_u16(a.0, b), + vqsubq_u16(a.1, b), + vqsubq_u16(a.2, b), + vqsubq_u16(a.3, b), + ) + } +} + +#[cfg(target_arch = "x86_64")] +mod avx2 { + use core::arch::x86_64::{ + __m256i, _mm256_loadu_si256, _mm256_set1_epi16, _mm256_storeu_si256, _mm256_subs_epu16, + }; + + pub fn slide_hash_chain(table: &mut [u16], wsize: u16) { + assert!(std::is_x86_feature_detected!("avx2")); + unsafe { slide_hash_chain_internal(table, wsize) } + } + + #[target_feature(enable = "avx2")] + unsafe fn slide_hash_chain_internal(table: &mut [u16], wsize: u16) { + debug_assert_eq!(table.len() % 16, 0); + + let ymm_wsize = unsafe { _mm256_set1_epi16(wsize as i16) }; + + for chunk in table.chunks_exact_mut(16) { + let chunk = chunk.as_mut_ptr() as *mut __m256i; + + unsafe { + let value = _mm256_loadu_si256(chunk); + let result = _mm256_subs_epu16(value, ymm_wsize); + _mm256_storeu_si256(chunk, result); + } + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + + const WSIZE: u16 = 32768; + + const INPUT: [u16; 64] = [ + 0, 0, 28790, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 43884, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 64412, 0, 0, 0, 0, 0, 21043, 0, 0, 0, 0, 0, 23707, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 64026, 0, 0, 20182, + ]; + + const OUTPUT: [u16; 64] = [ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11116, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 31644, 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, 31258, 0, 0, 0, + ]; + + #[test] + fn test_slide_hash_rust() { + let mut input = INPUT; + + rust::slide_hash_chain(&mut input, WSIZE); + + assert_eq!(input, OUTPUT); + } + + #[test] + #[cfg(target_arch = "x86_64")] + fn test_slide_hash_avx2() { + if std::arch::is_x86_feature_detected!("avx2") { + let mut input = INPUT; + + avx2::slide_hash_chain(&mut input, WSIZE); + + assert_eq!(input, OUTPUT); + } + } + + #[test] + #[cfg(target_arch = "aarch64")] + fn test_slide_hash_neon() { + if std::arch::is_aarch64_feature_detected!("neon") { + let mut input = INPUT; + + neon::slide_hash_chain(&mut input, WSIZE); + + assert_eq!(input, OUTPUT); + } + } + + quickcheck::quickcheck! { + fn slide_is_rust_slide(v: Vec, wsize: u16) -> bool { + // pad to a multiple of 32 + let difference = v.len().next_multiple_of(32) - v.len(); + let mut v = v; + v.extend(core::iter::repeat(u16::MAX).take(difference)); + + + let mut a = v.clone(); + let mut b = v; + + rust::slide_hash_chain(&mut a, wsize); + slide_hash_chain(&mut b, wsize); + + a == b + } + } +} diff --git a/third_party/rust/zlib-rs/src/deflate/test-data/fireworks.jpg b/third_party/rust/zlib-rs/src/deflate/test-data/fireworks.jpg new file mode 100644 index 0000000000000000000000000000000000000000..078cf1755dc0853e97ad30fc7af4d6af0b67047e GIT binary patch literal 123093 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
ma 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

3ZRBxkF?%H#_f~x|{{V*%h1A?S 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 AYXATM literal 0 HcmV?d00001 diff --git a/third_party/rust/zlib-rs/src/deflate/test-data/inflate_buf_error.dat b/third_party/rust/zlib-rs/src/deflate/test-data/inflate_buf_error.dat new file mode 100644 index 0000000000000000000000000000000000000000..2b937a7f43ee323e096b319e7a0269c47bca53a4 GIT binary patch literal 67008 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 + + C=10 M=100 Y=50 K=0 + CMYK + PROCESS + 10.000002 + 100.000000 + 50.000000 + 0.000000 + + + C=0 M=95 Y=20 K=0 + CMYK + PROCESS + 0.000000 + 94.999999 + 19.999999 + 0.000000 + + + C=25 M=25 Y=40 K=0 + CMYK + PROCESS + 25.000000 + 25.000000 + 39.999998 + 0.000000 + + + C=40 M=45 Y=50 K=5 + CMYK + PROCESS + 39.999998 + 44.999999 + 50.000000 + 5.000001 + + + C=50 M=50 Y=60 K=25 + CMYK + PROCESS + 50.000000 + 50.000000 + 60.000002 + 25.000000 + + + C=55 M=60 Y=65 K=40 + CMYK + PROCESS + 55.000001 + 60.000002 + 64.999998 + 39.999998 + + + C=25 M=40 Y=65 K=0 + CMYK + PROCESS + 25.000000 + 39.999998 + 64.999998 + 0.000000 + + + C=30 M=50 Y=75 K=10 + CMYK + PROCESS + 30.000001 + 50.000000 + 75.000000 + 10.000002 + + + C=35 M=60 Y=80 K=25 + CMYK + PROCESS + 35.000002 + 60.000002 + 80.000001 + 25.000000 + + + C=40 M=65 Y=90 K=35 + CMYK + PROCESS + 39.999998 + 64.999998 + 90.000004 + 35.000002 + + + C=40 M=70 Y=100 K=50 + CMYK + PROCESS + 39.999998 + 69.999999 + 100.000000 + 50.000000 + + + C=50 M=70 Y=80 K=70 + CMYK + PROCESS + 50.000000 + 69.999999 + 80.000001 + 69.999999 + + + + + + Grays + 1 + + + + C=0 M=0 Y=0 K=100 + CMYK + PROCESS + 0.000000 + 0.000000 + 0.000000 + 100.000000 + + + C=0 M=0 Y=0 K=90 + CMYK + PROCESS + 0.000000 + 0.000000 + 0.000000 + 89.999402 + + + C=0 M=0 Y=0 K=80 + CMYK + PROCESS + 0.000000 + 0.000000 + 0.000000 + 79.998797 + + + C=0 M=0 Y=0 K=70 + CMYK + PROCESS + 0.000000 + 0.000000 + 0.000000 + 69.999701 + + + C=0 M=0 Y=0 K=60 + CMYK + PROCESS + 0.000000 + 0.000000 + 0.000000 + 59.999102 + + + C=0 M=0 Y=0 K=50 + CMYK + PROCESS + 0.000000 + 0.000000 + 0.000000 + 50.000000 + + + C=0 M=0 Y=0 K=40 + CMYK + PROCESS + 0.000000 + 0.000000 + 0.000000 + 39.999402 + + + C=0 M=0 Y=0 K=30 + CMYK + PROCESS + 0.000000 + 0.000000 + 0.000000 + 29.998803 + + + C=0 M=0 Y=0 K=20 + CMYK + PROCESS + 0.000000 + 0.000000 + 0.000000 + 19.999701 + + + C=0 M=0 Y=0 K=10 + CMYK + PROCESS + 0.000000 + 0.000000 + 0.000000 + 9.999102 + + + C=0 M=0 Y=0 K=5 + CMYK + PROCESS + 0.000000 + 0.000000 + 0.000000 + 4.998803 + + + + + + Brights + 1 + + + + C=0 M=100 Y=100 K=0 + CMYK + PROCESS + 0.000000 + 100.000000 + 100.000000 + 0.000000 + + + C=0 M=75 Y=100 K=0 + CMYK + PROCESS + 0.000000 + 75.000000 + 100.000000 + 0.000000 + + + C=0 M=10 Y=95 K=0 + CMYK + PROCESS + 0.000000 + 10.000002 + 94.999999 + 0.000000 + + + C=85 M=10 Y=100 K=0 + CMYK + PROCESS + 84.999996 + 10.000002 + 100.000000 + 0.000000 + + + C=100 M=90 Y=0 K=0 + CMYK + PROCESS + 100.000000 + 90.000004 + 0.000000 + 0.000000 + + + C=60 M=90 Y=0 K=0 + CMYK + PROCESS + 60.000002 + 90.000004 + 0.003099 + 0.003099 + + + + + + + + + Adobe PDF library 9.00 + + + + + + + + + + + + + + + + + + + + + + + + + +endstream endobj 145 0 obj<> endobj 1 0 obj<> endobj 2 0 obj<>/Font<>/ProcSet[/PDF/Text]/ExtGState<>>> endobj 3 0 obj<>stream +hÞ”[MsÜF’½ëWðnmU(s™e{¥ÝñØkjw²`7ÈƨhhÒœÝ_±‡ù½›ïe€&›rl(BÑÄG¡ª2óåËúæ_o’‹ûáÍ·ß|óƒ»H.>Þ½)V¥sæ"–þ§ËWq’\X¯âØ¥÷obÞïïåÇÇ5þ{|ó)ú¥^×íxyºl•D]ÿE~gÅ*vMû¥Þè_YôþÇAÚ¨jqÕÙèÝ·?ób¾*¢]ýPïøW¹rÑØñ‰UÝ×mž©?ôõ04]‹»±\¹}ºüüñßÞ\¯Ê²¼¸NVIîd=ßɼöuÕÊp6wòñîN~¹re¢ßŽU;6c565î–2éc³®v¸„uì» gƒ¿ŠèSšü3Í>_áïD04í½¬îçQwñ#*Îåã¿Èׇ}µ“ÁL%´ÇýmÝË_9f€¹˜ÜÊ0Ü“²^YצYÓN¾9nëpsìe)ë¾9Œ²òŠÃ&ò„|÷€O›"–Ý~lÆíüýms¿•=2yT­×ǾZ?­ø'Ñ=ÊV÷Wø;“ù¨`L)·T0¦XåA4&ÅåÝq'×»êIGJd½×©Å·ÍC7bb©1QßíêðtÓrJ1EãÊ\ES·Ã±çR!â"º«dîwÇ +?‰ÖÝþ°«G³ÞqÏ p§Û¢õÝ_ß⧑«}}؉øü+.ÅDûöAèþ¹˜É¤$&þ¼ +*÷vÐoˆ¼:UçTæ¿išÍ‘ksØô÷?ây'ÒÛVƒ^4Ñm]Oß½ëŽA½©Ä$x‹I;#ŠúŠ¹4Õ.|ö®ëý®oîýŽQˆwÇv­KÊ,ăñ2kd‡6ÕX‹³,–‰4#.CÍ›¿ ²]ó¥Þ=é‹F6­õw¡â–QD1ü{~Û´Õ(µ}ÒËE´œK_ßw•*hZ@CtûEAËgÛ/Ê)rjöòìJÿ´Ñ‡vS×è\a¼ #ŸxhêGý­FšæØ“õ¶ïöøØü}l¶cYŒh)ùª¨â(»·ÇTþæNšÒÉþ¨ñÈSb”²áû[,Ê”¥W%üÊ£MswW÷/S2²¨ÌXËGåO¨¥ªáï5Œ´Ìåþr>ë®ýû,ž„Ø ¼Îb`'%ÉóÍÅE,Bþ>ö|$•G0§,1%ñž@ÜèÏT/¿2Ž;ë‡,žBQC)e¸‡™]…MÎR™Ø¶±~˜Rmê[Qž¾ +P c§ ƒ] î©QÉkO‡NFšáJ_¶Øù•É‡·Íz{θ‡C½nîš5”ÚÉ<Âòe’ƒÚH²˜¥‚Q`Su/JCSI£cÛüvôf“F·M·ëî¡asÖ£ßpΪ?™äŸÆ²óy»·Ý€˜'°#‘ó¡°ø;¥nåi*s¨ð#–}ðêÞõO¸‚ß×ëmÕ6າˆY‚Â^õzÉ .R`cß­aôXg|_Ž½~¬á"ÒÜhjñ@÷þͼ ú,Îø=qr‚Ðf²Î®½Â¥Œš40ÆP“Ûu}€ž`‘Ë@4Ë ë;ÂzRìÏ—¶{í»¯u,"ÞM¡ØOµ&SÔ›&´©÷"a™*W`èÕ"IˆF$—,Ñb¥OÚè¦És=<¦Ò#jáâå¬ú{ˆ~ñ›rå-"ß"· .êYF}V$¹[ù'=ùžªJ’}ÛJéZÄgŽÂ6`v©õÆ&v—‹¬Àeøœ¬z|$Üã¥lUr«»«iÚƒþ]ªÀ³øŽ=Xê3M7ª˜‰-ÉuÕ®• ÛîQ/ç1y°Ü8âöî8ˆÑ@š®ôv…—’å´pËÎÓ:c²‘Ș‰…€ei$ˆŸeTW=]C +Çè]•¼E³Á;ÍÈ»p×~Í +åU{¯»Q*0÷5á.õxr"ÎCŽ¾ë»¡;l›]uùñï³$ÍJĘ‘C…8Þ÷22´?¡Õá×@Hr… ü4AïØÉð$[ˆ­Z«ë3‰£X+!M²·Í?86À[T°¢>yúÙœh×ÝÒ°q ¢Pç$áð +ŒY¸p%«öb¥#XŠ5¡|–b¥^Q*B;óN™ºËJ:”à§3RÕÿüã…ò»¬Èå*ðÄ›9"‰a½­÷x¼pNA +è +S²b' –Uäp‹~tÜ…å6ûC×äs$Œt€Wh¿eÞ¢»+hªq², GFÙIHÆø[W5‡SØa<DèŽìßXÝî¦ÝSq-¾Í˜Ô1æ¨+£"G[»†‘!&f,Ý­pág‘ âä|ùž‰ùç­v0EÂQÍ`ÒŽIYZå)Ž+S ÄÔåðˆwMïï¹@Å]ÁàÚçG\¡Ñµc¬v[ŸøCÝ?0˜!ÿ¨Öâÿ8äÖC1Rµ<*—ªåùŸ`yqY¦ˆ!K5¦_¨Ñq7ß|èM ¾õQS›:¦Y0âªްYuÈIaf>]"B”ç] <-W½{0psõïÛ涹¼f^HãGØè¾Ñ¸ÍÆÁ†dV`)0¥ÉÐÒØYohjVÆBÕ訅ôù¤aRpvã)øP¬¾ßO¢ûÓí%‰Ãâ̹ Wˆ-%Œ~©×— >ì-œ@¨Üe‚\›:¹‘Ô¬¸ ‡+pÌXÈËðI”ûRt/€·¸'* ÓO€.©áXIMh=N`B—šû©epxcš_ ±¾~¿»dâ¦~–§žÐR„‡'%¤ÚWº( &­£o×·+,NyL'³$RxÜa9™KBˆYXW2¿ÆòÓ¨ò³/0Ã,sJý1yX>(f$ÆWò(»J +쇋®ŒÃD~äŸ1R­ÎáîûîQg#¨p©øpœ2 :}R·ŠHX0 ‹â= ³#Î1pëë:º­]³cö®ÕQ3&ŸsdÊëÙÖ̤j¸¾×íoF?¦ÛË8âV&Ñþ–Ó’™âñSnÞ#ÅÂ:tÂb0£2.£»±¡×žz••D-º‹;„¸+,ø=߃`®p©ð!jΰL “D]asÉ ›ÀäáF½cÊÌT óÊ\0ø¦>I/LPaªf¡¿ rF“´ HKìØ™e(ÕÎçO/ìe£ì;ex~ÎZôYï þPŽÉò3c³»d|¾¸Võ4ádOЇÒ)óñZ~Fë$¸Ö•K$tI¦‰@[µAuÆ0\¼d‚ ™FdõÕZ¸sËj†?K~ºoXŽå&=xÕï ìØ6U8¬~.PTZ;@°WaNCnuÿ›ðùè¡ùPä(Ψ-ñ&âfM’¿Ȳñ!<™ó±×4¬lÿ×ÈÄømC ãåÑ5cÂ^A®Ö—Y‹1xU_§–2Ðg¦t´i¦´Mc¡¾%='0Ä>ÿâ·¢ÖÚ“uWHh*ZC‘w3ÿ¨‚ÌH£¶ÛVwAûðкÛa Hœ¯‰Êð“*^¶I˜Ø½SÄ®¡lÖ«p*>Q„!:MÖ¥¥€Ml±µ’™¡Õ²"rÙ9ù1LAéëDà‹m]X؆¡IÓ)ÑW”'Szó»¾S4CBå…lĉ‡™&6¼q“j¦È‚Ÿ©:î ·ŠS³”H+z·ý ãG?_KtÉŒb~£Ùî> 4=t£Uÿ¦® *¡8g2a¨¼Šj£DÖÒ&§üý_ß©Büô¬å{õ +™ Åg­B$E»Ä³Mõt|G +þǨ>#!›8ÂJM:>ž„3ðw•Îy².ê#®­Á’˜3—Ÿ:0QãIó.Žµ8k±"t›NÈZ}õGÍøØ%@i"çÜ·µL¥ž€·5)³½w?/Æ>Ñ+ú$´.&Ž¡NØô3ꔈ{[ª“-R 韹¡n>Êuš e›ã‰P 4~ð€z¥£åZÝË](œiæîð~ð|¢Máë 6A8°*¡Ÿî‰®;Ù:±üMãõê‡ùh‚!÷¥GÍ°þÁÖ#;ÌB­Î¡±jPëDía•¦h±¶S~‚¯È—wjyÇ¡Q£|¨ÃãáE‰½êQ÷©ú'ࢳ»ªX +Î|J1c@«Ø"ëA¾'cÝeI3ÈŠ°Z²G£#s>]žME÷Ìnó,ÓÑR\ÉFuNT':òƒnÉöjœD“JÁXI…¹gc÷ëq«¸Ðm¼†7óÌ°¬Ž‚5“zÚŽDyò®Öý¬ú¶F ÇAN;·etS?L°£óÙ…1g«B†üÔþBÐ@¨Ï3V̶žºžuÙD»|±“Ão‚nh®ÓAìJF*§ƒgyÆhL¤“V¨²â±VÎBb¬eh£¿¯‚Ì×”†|é0*n7AHRiDª£ÆH‹‚§Ä*ÎH,puÉ¢—)?Ëe —÷°;šÐÉÍ55§îåÎܬÓ_눉8Û3¯¼SíYéMÙˆ tþ¾mî4„BXIâÞŽA…õ•<.}ûú"!‡.ðüõÌd>?3Aq«ÝæÌ‹xîHÁã—Šžt} lh*Qô„®ðLPô3ÉC{ËA+Í¥Þ[Ù²Ìü½“Äþêz'ñw’—/ýéÙKiž„·ŠsoÉEúú›×óý$ö¤¡(ž +{giÉÿ´â0sä +úäIÌÑŸŽ›¬â8õ48²'eö—ŪLL"ã\FxË _¬BOù!¬óÑ'o¯=µ`$žjð† Ï̵õ4ËÝ©Â#,$Y¡·†×»ÛØãÛµì½ÈR²…Gíª,|{`²Œ§öWlÐŒš•/†¬Âpïí¿«aÕšÉ%ã/·÷Š—è[Ó$¦G’¢RŸ"/ŸAØiôŒ£;F«ÓË6ä”’+um`P­þ,ÎåÑkë‹€À••¿¥‘ŠŒ^T½tÄÇfTˆ‚'Íã)É{.\¯Ur!|©ÖOÚÄ +ÛùÙS¹ªÔËvíÿ* + ¡ó«…Å!Xwµrñ»»Fá,ÄûäýXÑ•vvºhë™0z +õ'wJ)s² üüî]hµízoá‰/1#œ—AËû-—ø+Æ/ÇÎ6ñ=ân–ò„f©Ý˜`7‰µötÄòåˆ/­-óÉî(þÀ†¨¿ežÍ>Ίe£h"ÙAOàä'Þê¡ñ¶yôám(‡K@ ®6®~J2U#œ +Òã<‹â†²ÖãrñJqÃä¢óé[ä $ÊÓê‚o0-ó¸xf>f¥A´Q'n¼C*Ë9»Ṳ́ÇOÚ–œè VJ|×vœœØ‚ðª?2*“×( XŠ¦dø\îÓ0)IPÐù«sföèOˆœ§ñ.Í7Î'‡£N£ +„àÅâ8ÉltGÖšÈü®,Ìœ¡Œ¬Kñ‰dîÆG´ÆdOšH^e1g³µ›pÆ5ö%Æ‹$æ$¯Aé¤/9hoZK¿Ä`_Z%SæBõPVçß[þZ¦ì´P7‘ô/¬¥±ŽwV•S6p½O®´‡Quîl6à ×” ˜­F±akï׊¬–'d§yvÕèyi¸ù*m4,Å>éÑ ÜG]ž“Õ 9D7ÿ"˜¶*™éœ¨ºWíAØh8ªD\©›1¥qšuÄ51Ëc¯ƒ÷u«YÔéñyÜתkÒæÌŒÏݱ+ezuœˆÝ¡80T,•ŠÉÀôäÜJµ®™*y‚+š¢Â”L^5•³Fæ–µ¿îzãV1àÜ›gª¼ì¡eþu×­µL[yzÝü#ä·¦cƒñŒA¬m“´×GôüDÛþL-d>ô©šâ{[sGžíÉ•,£ê5yþ¥i5,çiKàèäÖç ôv7eÈä™W +ïĺ‰ái´”[v¡Ÿªx~ÊÖe@UpžéRDOÿï¢ÂUhâåV•F;€uCǾ4Ö&Èä!ˆÖ¼æ3Ð,§3xeÁ(ÏCHϵÍìŬ,Ì{Ë¢j ¯ðAsùJè6ǯBäõ OÆÌÏ€+œ}ø ɯp9)êÈeš;Á)¨g…ùäe»ÓrŸb­Z«Ã‘7N}Ç£4)[V~¥ñæš‹ãóVû@õ‡›¿©P?œe·ýÏ_~‡ +—%Šø_ßþ ëæ¼-wQ[ž ól‡¯²EÏ6bÙ¤çåjc{޷뫾ÖÀs”ÈÉøLÆ2=éÂÿZ%Ë‘H0èÛi4>v:ò26¿ +#œDiæyé +m—È8#ˆuïK˜€àhÑæK#ziT”\Ýûá =e̽òݲ±ž%œ>â¸'o?þ¬¹Þ¨'–{H4Ày±'›ªõ•LŸ=ÇÌëÞ‡x‹ŒŸ¯…ŸÇ‹»jí1|}óc£ª‘^i‹¾ïÝÉÕùtB×}¥[Ñ~¾„VÀ;-9¼l¯ÔNï§[pô#[rÂÙ–øùäë«s¨n!à†¹OŒEtôp·`ÓÜôÖí|v+bþE‚R»šyoXT€`Ûãz§Uw(#äE¸ ¥žRõm÷à3Oý•+´©-ÖÍBoU`úÇÆ{ÌmóŠäÎUÐî”jë›0ÎvU0ù{òÜÕØÓ4AÔ#x/kqC8øÉ&‹(Ž£/^Ôs²äÓY×g2›ê"@grÞ½É6Ò™™â6˜ÚðÕÑL9À9·.o³KùœMPºWtôu)="kúÔRfH©ûkßÊÓoØQ‹Î¤Ä¼B[ÎHi}?Üqí‹sSŠg“°©èxËOhï¢ý” ­S )·C¥Ìa)žÔºYð:ìk=ƱYóÅÑ—".òS²èar/{˜DÒ¦Lç¢t:µ h¢MlÈæÏÚ²KL¾ŒbxD®ºÑÌAÆ/­'–V˜å¥#”_lÇ×wŨŽ{ù-“å™P3´¯°ŒaæÄÚç„ô09úpŒ,Æœ,†ÿsÕ¾;Ð+šW!ÀEëÏ _Ehí¾çÔ­•D6•vÃ$Ñtxéd›ôŒ¢ß&ÜwÑc£my82Ñ+pÔÕFO)ŠW%_6‘AˆgYý<ÈUÈ*:p|+ó<öá¬ðºîµ„Æt}8…,!e„óÉü4@áË„R\s!{ô>ú%!–e +éÌþ¶·É0ÒZw?ŒO~cÇ=L"RÈ'mSQhkŸ£Y¯ð9 +¨ëŸtË žÿ>·ç}½¯T-ŒwÆS0k Í»ªG ®‚Ý÷µÿKâËV6Uøg½’l×ûšç"ñªcéOGžQ¢ëe÷âtd=ÎÙyyÜ<…*‘J-V›Þ©Òoq€ z[áå…X@4¯Va`ñ) ‚º? Ù-aoN`,‡ÝiîšÙÀ´*¦Í…æ¿ü™v6j›øi–dçØÅS…4DÎõš¸ :QßæÜð°ƒ>ü·Z‹¼l­êúQ]güÎõYêà"ÁïÍb}$ˆ âP#í™è‰òqŠc²¥ÍiGY^;ò;®äaEv0ÌÐqಙ±Þ•“¢º¢ -Œ…¡øª^ÌJ÷d49[ŸºaArë]½÷ îŒvFMTQÒ¨8ÃvǾ¹=2IžÇ>V´l“¹;öãVy Èg½;®›¦Ó]áâŒ(—f„¤¬7#6vûæ7Ãã[M Å?oª} 2´ +€£ŒCf© `Ü ôsthC“ÿ‰BV.ÿ]àXA™+YýýDZ’mGÓ'̇ ˜ó£Li7ŒõÓ‚F©¾¥ðÿœè[Š½ÿ¨Ð¤§­ E¦¼¸.e‘ÂQuù?ÿ姛°ØwÝþp9–bË¿¥÷„I±)ÿp6»ôøø¸:ìºA(?cï𳫮Ǚ +ÇtZzy]:œþ­jZËM±—iœX§e§ÿ«Û÷µúï=arÝ?`KhŇaÀ &ˤk¢¯%óûuÇÆ&e/þO€¦±.µ +endstream endobj 4 0 obj<> endobj 5 0 obj<>/ProcSet[/PDF/Text]/ExtGState<>>> endobj 6 0 obj<>stream +hÞÌ[Û’äÆq}çWì‹#0Ž™.uá‡%)YT¥][K>`z03»M=Ãa8üþ^ç9Y…KO/I…eKÁ.¦ª²2Ož¼Ô¯þí]öæaøäÓ÷Ÿüê7îMöæýý'å¦r®x“ÊáÒ–›ÔöÏ‹I3óæýþ“”ôrñ~‹ÿ=ò!ùíp¬®2¿©’ôê¦0~S$õUš øC^•?ø«Oöu•Yù廦Ço©üÖÝã*ß”I½Ý^eÕÆ&Í0´W™Ì"¹Ý5úœI¶òn±É“n_ã¦KÆö°‘»…‘ë·».½ÜoxÅÈ8õî*ËäßÝ5~±xåñ*Ëå£Õ'»v1ˤ›«ÌÉ﮾}ÿ;Y×M¶É¼Á|.ë;ö ^Ë“»Vfhäý±}šr©“»g,-O°2—æae¶²r5Èœø¬ÇVF.“9z½h¾™ìøµLæ"Z™ÿI…éÒLÆå¤Éã˱ƒÜ‹y]Cû#„“͛ŚÊÜèššZÌ·H,=¶ +¿Ì=‘-·.Ï!þnçmrÛj|T&ÞõíUžb·!|ÑáËSU26ýS2É®ÖMxÁ•Ìñ¶Ÿu¨¦ÁVeÆÅÝÕéøˢšÞÿ3V‚ù@Ínwøº“A®nŒLÇR ú‡›õëÔÇñ܃îÝɈ.¶œG‘´ÇQÅÒv Ãh‹‘Éy +•ßl{¡Júf‡Uù¤[Ì¢HºÃðI‰Jã‹Ï­l‡3òÆQÕj×^Q7ó¢¶âÂçó*•Ïížfá“Ã(~^zä ÞΖšWNž>4?Œxˆ{ÜLzÛan2Âp›Xé3^)ñ©BÀšñbå©jaØVUϹIïÌ,‡¡6œý¯~S(žT"¹#\„ˈ'N.r—åÀ“Ég¢X7NF…b¢ÙX`ßR¥Ä´ ѼÃØ··'™”LÎë†è-ÅŽT^ýÍ™ñu>€½1ïÚÃÃly–OFÝaûK*í à!KîpEÝÙq¸’›¡UÅÜcÈðaÁA[ƹ©>ŠªÎoÒ,{ãd~EšzÂOõ;$æÚŽØ!5z‚Д‡þí»;H[6y§Áyg¢n:(âBôµ¥frûË„š ¡S3]%³ÄS™èCƒ©8Ž;7ÍœsÔUÞlªªZÃÊeT ø~Àë¸VX\|þû·ºQåÒ¶Ðñ|9Yu$¯«ò/ðÚ÷úÚI Q&]->7k³ÂB–.k¤3Mn~Ôå7óºÚq£c•ÉûGhå €.€‚]Ó~Óäjuk»ø·ºƒ·–W·õ 3ž'ªÂ6- S +0F(=8G;ŒqKkÕola»“§º7ÈÛ—ø†x‰¤~“|Ù( ¨e˜ Ööövнév'Uƒ‘Ô ÊøN J¼ïá;%õþ­fÖC=ÂÓYò.Â_³•äÌm…Ë?1¤‡çY ?f“¯šñQ—ÛÝ JÝLrßõ—¬ç®ë€O»AÅöÍ•`hÚö¡°zïÚXE›o¯õȲpˆŠ"ªðN™²÷ÇF©ãžK Ë3oj’<öy8ªo¯ûAA£D­ d6–üvÉy船L{§`ÕaÈÒÉ$=`.Ä;JEA§‡NöšTøˆß^UñHß mÇÝ Öâ“ëK¶{_ouêí +S*›™¹¹Í¡C+·9 öuôÐ7£ZË +s1@µ4)Ljƒ{ØÑ?5*õâÑè<ð góœ²z BÄ›ªè‘¾ö“€Ø1eø è‹ÅjE<µZÀ“\&¡…¦Ål )49ªkÁv5Om §r;”ávíuáÇ]§÷BX6y$§ ½k‡­FÈtÙä¢Ö=ù‹pÿa« Ñ ¿ãþŽqi´ìiƒ„ÓÄ°T9p}eW÷hTÊ×Þ‘S0^Åþ­ò8{¦˜XG¾D|áÉsÍ÷AOÇ0ƒ}Àd~žeQø /8‹ix‚§]ˆÐe›K°§?dZ n~8FF¨Ë¥‚áôñs#³´¥cØ·nß©„F,ûp#QÈ“Zh¶e= ÿXËöæiäéÖ ÛÓÇ+1© vóÙ§_jìYÂå…v<Û Áœ¨½)¿UKЈ+’ð< êú›öá ° Z3,?Ëè•v§AtÄX~‚ÈôEwš~ÐðØHT)æ&zñÎÝûlEë^ÂÑP¨ºÉ9×”Ý(¯ìëö ¡NVEßn¨²”QGP‹¬À7êË /.þû›«Ò˜êIÕ$AçÒɇl˜g‘M"ïá$”!¹)ŽÂÇ,Âáæ¾ÛöT%ÛÜñÂþ>‰ë½ ±¤‚=¯Œ lW.á_æõæþB†XÀy߃A9¥ÇDqGl9õÇn€[°þgÃ%Ô6yíæÝQj»Ú"ÍÂÞ@²@êƒòH ~N·ÜÞ)56OI€¿?1š'©„Ðltœ÷"Þk}BwChh½}œ÷QxÅá.z@Œ™{È\e,à+¹Òbe²úŽ Ó£Pâ†ð˜± ¸AËœa^2½vêú„(ÚÇ[|aš™Œ +[Q†ÇvGç!ß&¿æJƒáÛrËÌGsHy!üÉ­RmØ/· < +±Pª¯?ûL½uÆ$¥¦'<ܾ©ÁTf.`­¦rÛBH‡&Fâh»R–3Ú€ÀNpz¯Òùs³ \õ:’ºdØ`‘j·{ù18æ c1;¶×ÄYL™1Üڧ&f³ŽÝ3y“åbFmx Ù'—#Šû3áÏÑ½É ü Yìš'*#ySåq9¢¼¿t Gç(zhïäþݵtÜ‘¸¨qLû#FßÊÀ”¢Ód·Ê,”£p™&§5°ÈB¦QX·€rb‹^c‹,×›‰ +²pë¿Â­4ÜÂòõNîdᎩ*nýËÙK¹Ïâ[6]Å1HI|¨÷à€¢.\‘dŸª’EÕ!æ¿;%´Ú ó©û—A›ªtÅÚ”çÀÉÞo¯•y™äSuiÖ³"NîÄÌ2Ro­µî‰¾üØ>Óß#Ó-Ϭ±‚?ž¿'ÀðÍ•ä7^–dÏÀ}8=<ÀJÈñWû‡·¤Ô½°Žé A Üp)a|áa°5Ö! œÊ2>hÈhe“†*ƒk$W{3•–EMY2ƒ<{J¹•²´ Ž’fÉï»±¾Ý½@P• 9ayóHf*ÛEКMC ÁzH¤u&j~D¾mõ‘lòMòÇí â*“C7Æk\ȃô~x‰uªA¨nÃ:*~R³·>ÕLóEÙöÂ,èõJˆ¬e—hGl1³³$*•™œi”o’cW,Ý=¶ý„*E¥œvasBœc>GY|Å72²Aœ£¬»öNŸô* ¡¶]ß7"·F“¼•zaù°r +³`Œ©¡’† ZhÇB\é&À_@»W†,ð䫵GÛòyZFãú׫›Ì +¶e %ˆÔ™¹ûÍÈ• :ê_qÇ&ŸÁ¿Ò §«ª\«Õûú»†ô¯Ýý ½“S˜HÚµ6>¨ã,è%·]NR ÒÎY YKbÌØÇfÊw[:^Ìø—ã®I¡é[úùŠL[`~¤)CY2æ=+Ø$T¿çÌð¦K^>œ1윕fVàh÷á3× > +`ÿÐîe’ŽÂ'…ý§kežZ¥DÈ.)ìS-È+¬Pš*×Ú±,¿þâbsfÜ&­¼û[›…ÀŒŒ0Qäb˜GÇ…ê3fµ"ñ±»Tzþ?.-gð÷E¨,ÿÛq¢6à:ñ¹Ò¼¸Dø¢`=<¢6l™XœÜ¶-cýö+\6C,` ­6Ý},°ÐR/CÇõž–ä¡õ‹ð6„¦EÐг¸žCV>mðN1`-dnC LOêô?Û-“?]CÎøY.í"n"5,à ‘)…8‡)–e7[ %7ö +´°%™s5lQœòrYx³–èZ,–"¾p¹ › ?¦¯9~œ9ƒË!`€Ýç¨R9r@ø:ÇìüšŽMö½®æ4~@K`^!ÌAòl)±ôÊOmw¸³L¼8³h®œ@/ªokÆÄ“›öš÷*ÖÜBÝ6àÚúW ’¹é8ag*Ƙ°³Y̸9ëÖìA,gêŒaa÷Nóч—Kê´ y +cÐ1ŠˆÙ›Gù6¤¾ýôf )J²ý»€'Ú^çÑNï»a‡ÒÔ@©õ=-› +[w®ÌÞ‹I `3¢&"ÚBSݨ±SñšÈiHÅÜ—h#ScÞɦږŶšƒ> ¦Ðm›ah†Îq%‚«ÂqUHnÈoÆî†K5%‰»ø&èb'l1´}`‹)Í4ÙàÅʘÐá H´Ý®{½Þ-?ZÄ>†Ó(ï³¼i,‹¯Ù ®Æ±Å%fH1ë̾)d4lcˆœKgËÂËY€xaÁëOt›uê¥K{™W­ú­Æ„mˆû¢}êuB¹OIé”/j®ñŒg/ò$ÄYú«2ÔΗêSh‘úP1eæŠÞî‹Ãv'¨©ÀœFMâØŒ¾µÚœ ò¿˜z` r~™plT¯²=÷¢€çù1ëýG°43ö"–ê€etÉËÀPøAþ×V`–wK³ÞÿeÞV—} +€½æºW!Xá³)CÎKÛfœÓ0`•Ô#¨R‰Ž»¢ñ&4RB‡.lø¡ì±71ï jæ‹*xÞ„¶²“òxüíÕW{6Ý®|µ'\DŽâ¦{ÖUþ•1$Ÿ÷ÝÐÛ]½«|¤p“ÇÛh»®GLÄ3‘-kÓn…¦uPäíño©ìŠT)Öðk91Š¦Ðpî…)ˆ² ¯tóÂ,Vr[*6.Àck*ä?šÙQøÓ`ûúY\X­­^yµÔÐh\´èú£ºÃØØ´šì&–#þpÐÀ¥XVš†zßè=*¤ÊàÅ¡~ /ØœÖC"](¸þÉ¿ÉF¾Z,á°_ +9ŒZg÷¢VÃÒØ4}g\5(ÿ¿¤oP;€Äú6IùŒ›)¼zDôHYr³_ƒ›) +é;¨ÏQ¦ÓÉZ63ëôîÙE ®Ö†°)krA²…Clóýü"¹œ–S" +Ùl­,ðµòfÛ„2à„oi5qõkUtŽáS²Ù„[2FÒüðØÞ¶cìßuÏš|È3¾ÖŸ + #S7©cÁÚHG°[ »šþiáÇ.ãØMï2ùùÔ>uë8Lt¼È}T€cÓS¹:kyh¡Íå”y•áQÀàNÝî”îa¯֒À€lb©`æ«Ö¾z­dè \Õýä/vZÎ1²þÎC|ÊsÇlÑâ+©'!þu"Ù,Žïë—XeN÷2`8²P-’YwÒRêU/hÚá´¿Õ‚˜çË,ÑæTÜÚ¶ýöÔŽ¡A¼ä>Fé‰S‹e(´áxÄ £ñéE6ªo×­s‡ö}_!ôNû½@Á5þFã@Ñ—Õb§ôwÝ)y'xsvä“ã~óD¾d³ÌÍaùB¯W¹"ÃV-f”IÿÕ›záUyÁ¸”áÒŸerYŠ<Á˜jŠÉC²á–0Ÿ8;íØG–Yk,1)ÝžºÝS¸u K…Tò`Sµ! iþzA¬ËW)™Y!!¢åßgÙ`I“&³.ªÚlv§…‡C +SM™tè|,ç1=€î¥jù+õÖ!¹$—°¡Ú-sYH‹P‹) +=€ò‘\™ª²Yfy6}†ÔmZUùl_™föRþ,ä‹çc\,Jp#´ÝYãÛÀ1™Ë’ˆƒ†Ç!Ü/X2;?Å1çÎxR‚äPŒfw]—×V)‡Wy3öZ.&ã1ôVßTÚŽˆTãä˜È‚—<¬BnûòsY¸Q(â´(åÞѱs‡F©dÍ\n&«zPgÙ¦i²ŠI-üʲËS󢧲IF|ätn>¸`óL´Ûô\2ŽÆ¯s­j ìlºìÒuÌ¢„F*Ç8;p¼áٽࢠí^.›ü"ÀÖ('Æ™ŽÇÚèœÕ¾¥A]YÐ5‡i„T `‘“×^ +çÙ¤}Š•öu”µ,v\bß¡ã‘œ Êøœr_æ# +jÆa“÷YÄâ‚åK5y¯ž?2_ÒÃúâBŽíL>»0ÌÈ÷Ùв2”TÚ´,äöûS­]*ûZûžðÀúï7ÉWï”M2MJÿy9Åâyû‚.ñî¸ýž©$†ƒ»®Ü3°ÁǼ™²°4ëAÀ3í2‡ÆxÊKhŒùx6tª3|ûæöå#‰!XPq-c¥Å_ïÌ[ +Rì)?¶ÛGTà ØÄçØÍ;¥1Q[Õ=;mts9CºŠ<ÓxÇi_ˆ>ô9xqy$ìò¢ ä ¯4r¨wìfcƒé[ßqó=Pm•ï"c’Oì«G±íªôÅÌ܈—ç’×™ ãÛ+Jç–X´ÞÍdZºÐŽ¤© m¿G·¹F¼å¢•P£êØhN^O;jòé,ln—Ïf‚wÍìÌtðËcÇ#–Q…*çF<÷-¤쵊…ýkÎAro”äå‚0{ªlõ¹ØÀ2'FB'`,ú¯[ +Mb 7,¤ÿû!t™M½—Á®*L¸iWý^jôÚat¦ßQ8ZêÌÍDG-;FtÔæZø˜•’?•‹Þ•Zí† Ïâ×ÇÂÄÝT>.‰pV1Ì”É*—a«Ò¶2Ÿ:0½à¤:¨lh³*%ÔºA[ïæ¢r`Ùýа5I{©ž Tmdžø9 +mQFëæ¬ëLusWÄî íªšbë4²î%> cŒeS¶Dí 8iHc˜–C"‰]:ˆm˜ùL1‘ÕãeìøðÁhC3ˆvø, Î:Õ/ÞXd¤Iÿ¦-¹6µåÇ|±³15kÜG}1«c>ñ­¥—iwšG÷S&óZ{›mr× Çvlôn¡¾‰ç\Cq˜GyWYö, ¦* ÖV« +Ã?Š˜Šì'ÄÄ#>È£h>ۼ纽åÚgö†ë¹¢Ð9˜©èÉ£œýñùR{yˆjÖð,–Ä_ ë•gÉ#4¼¡'7¶ÿ³$v뱜ÿ©èG>×­š2¦rJkÙ!¤Y,Ë3Óü!ј—ÿˆÎÄU?¹tVQ×%»Œ½Tyåbê7gÎþ¬è¨Ï‚,m 'ÕÔ”’.¨ºàL> £Ã'Ãã¡8ŠTrïBS6*Ÿ±wÚóˆmèv6Þ/’2x¡dRfëµYì€V¡k-Œ–JÏ}ÙîC\´Ð°eg>;Àdìy‘Ü0U¨ >³a™!ÅfT 9+K—û M +VÏB…¼ ÑŸâN½7—y ÖÞxúU³csɆG$˜•ÏåJìÍ/3÷ÚÅ"ˆ˜> +DãvË…‚<4јΛ|Ø€`íܾÀyæl\[æ> kû¶¼kGàšSiø%MB!‰MB¬™kŸñ Ë_´·Å_È•²þrž ]Õdª>Í™0— ê^þ÷Æ‹*_M˜ÿñ„nãgÃëx” îè«é r‘ÇCH»µÉ4‡¨þ´Šp¹ÅïŠiLèÛÍŠêÍØ[é[(¨¯¿üû˜ý쬆Êüê§ì:{ÑÖ5“ü§Ð†NåùùysÜuÃöŠ4Y^EÚ¦ëÑ'ãxˆ¹¸º©\…³¤¿«'MƒQGó438Å€­ŸünwÚ³cAX–â÷ð€©°%_ Nṯ¯eóûM–¦…É´Mé×ï?ùW)Ý» +endstream endobj 7 0 obj<> endobj 8 0 obj<>/XObject<>/ProcSet[/PDF/Text/ImageC]/ExtGState<>>> endobj 9 0 obj<>stream +hÞœZÉrãF½ë+t™pF„QPð­7íðÒ¶¾´ú’ 7Ð(ZŽ‰ùŒùÞÉ—YÅÅ-M8&Ñ µdåòòeB_üóV]oÆ«×wW_|•_«ë»õ•OË<7×ýO3gܵ*ò´4>¿¾Û^e$M7ÕCµœš¾gs£UZ&‹z:Ôu‡Ÿ6uÉ×ßãr©Iî“ÙÇ»oé`eäd¥R–ö½{{• ³»_ñRËËÔ¹L…Wÿ¯²°.ÍH¾ð. ïTXfËÒ…W_^.£Ã\^VÞåŸïø!¹Ä:-’Ûýn×ÖÛº›ªá 7*R›|ÕlöC_&õÉ­}}?»á‹Í]¸4æz®Rå}!›-ûnÝ Û¦ÛÌæÚ*RIß-i¹6Ž–W›ªéð#Oódz¨&<z–Ñ"é÷, ­‡j[úá¿¡ÝP¯Ö>oTËåžÌÑÔ#Ës÷w:¾Q-é¿ë'1EžTÓt™ñ¡®Œ–4J¢Žõoûšå3ÊCÖ5ž +zšj1q‘tûí‚Wñ§)뺚H5c_Ý6Û¦­†öéæ$Ðz?ÐV´Úæ9­©Ÿênä+XW’F°u¢Ž³2Üö«ºÅ•,žð¾ û4ݲ݇¥¹ ÂÊÒŸx5¿­›/ª±^ÎÞÔ.A“5Lêe¹ÉuÒÖu _Í‹T‘®û-=“D:ùà²<‡6î‡ø´Ý·SóX M5…=óäëfµb×'¡óäûjøÔ?žNÿ—"Í-9‹N–tN5ÁØ6ÃƉ¶åWA'«§?⧧Ÿ"”ÍJz&¼ûáÍoßÉ€¡¹æãé¬U³bu‘ØìÐÜØlºfÝ,«nj¡DºF™4ÛÝÐ?ÖòóÒ¥0b¢S±Ö-ø,ŠÉ%èöêÅ(ÎíóQœ–eùÄp¡âªBÿ)†­³ªn…—síRE÷¸ ÉU5qdä3gA1>ô‡î~–F¼º«>±1 ¦T2õ›~{#Ábá#‡INÖ O"wãNMGJ¿ ×*6ÞùäÍë÷çáIrÎFô1R:m%dƾբųÉè|þ?GÌ®eÐpÚ“ m³y`ƒ:$EŽ!ËáMt.æ\ÀeÃ0‹ãÄ‚ú(‹8s@„HÄ ·?¼ÂPFÖê]‹«…Y†dœšnpz¾6p×q¿ÙÔã$°çèVÒ6Ay²çtèeœ\´žÎ”9óL#²à·¥ß„T“è „êvÕ05U %Ä÷ÛsàÎ3h¦éÖý° ²cž î6Øà[üÚ7'†.S&Ëj V7<Ô˜ÆXÇa{ÓÚâ,Š %ZB°Ðåss. ðŠ¬,)^rŸZc9Û~HîH)9ùÙÐï7ØNpÐØŒ]µOcŸ³Š-óXW `F°|»˜Í=é½éª˜  Ã+ÊZi%ñÐŒ´¢2º ãtZ3›Ã.ë`sÚD—0àC5,ú¡‘%Eó— +¨Ø³ÁKhæÓ>Ä +á-bìJjcSœÄÉ*XœjA—G®Ý#lÈS½ø Ý›Üòèƒt8Ò#8B„ጢó òaærzOæ#XS¢ó¯k +Žg²².,{˜e¬Ü’4È3 /oV4‘$‘i!Ua’O¾«Æ™¢Ä +Ÿ¦T¢¡Å™ÂÕa9˜£‘„,9ìÅñT€@@ŠlÞ=DTnÉË›™¢‡;z +! ¥€¸"%ß1ô€ŸÍ8ײår°¢-m®6SHÌØl‰8ÑîJpÒxP‚-=ŒF?:HO±Þ>ý1S`"@œÌÁQxªÂ=±3"êô–’ D@%V$ʲYhzØô,]-ã*`cÍÑh!ÚØ@Çã8Š’غ©q”¡Õ4#¿Ô:‡’B–Æ Ž±„[$j/>EN7⛶št¼XàRžÈnð¹Ä÷ÉWŒaª¶\bH'Ð&ëuÉT ´‡ <à/¦)x‹›¹•D1 *僆y9b›Û‘ëʾdCámðW-î–‘ºü¦Ç+lkÞ“LÃ<3î3!ÌáJëç\ÁåyW0Z`PËsH0É¢’XÍý–I½d÷.hæsÕcÅ$mV ¬bxΑ×ÌÚ²å1:oιÒZ$~Åñ$ÝĘüU»Ý ŽÑ“àPrD&S¼%ò«f^´8²Üú hm!;=U`óMÝsxÔ"É44ÐKšàa!2Ü„ô0±B)ª›Nð‚IŒ‡Ó7,—Jvý(‘‰{+á8ª8G;ã)÷í^¡ 6ô Ib=8=Ì »–¿Œ)´%$€9fåuÈ + Ç;Ü¢á <™Ÿõ4ÍX=R,‘ æä4B^2ˆòÁ:l©“P¯Ê(ï²ò3˜t"®'×TÌÎñŠE_Õ;#tZñ| u­$`Õ2`Pä žjv+böeDƒwwW¿]YhÇjNPTm§%UÜ\‚ÛkàÊÜõr{õÅ7[uý¶¿úIŠ÷À¯i¯"“¥á1ïsJo^R[,Z-Wu*Ånt»|¨A‰–RcX$W²ˆ$…À‘5ZuLç–£Ÿ Ó?ËP#5ª˜—+U«A)8‡Y2P’^r`ø”Y‘6q9Â1±ë\*rÉsà¼lR°ñ©ò¼`[.™Ïb)qŸ¼ºŸqUÇá^D<Ž.T‘Ø[*/§¡âĉèDI¤ +rѵü(ƒ6²âB¦ô\E†ŠúÎ2acôy¢1胰ûX)5¡¶™Ô[wýÏ7²ž2v»¯ãÁtRMbiË âŒUÔ#ù©eÚ¨$ÌÞ£dÂh3XòX×yÑ3i–±¬[_–ad›Â—ìváÑ0(“—Äg)®¼+àw‰Â²Ï}Ô’—[¸k. +bd˜|ΰ± +¤¤*ÇÓ…¶Ó‡$Mg(Ï£O!¢Ña27¨âfþX6fæü*Ÿ_€ +âåâlc^Œ60P•]Þäñd“ .OÂÔ(¿•ª4—ž·ªUÃà` +Ãl»ml ‰ÈåTu›¶alS0õPGþmOT +rsÉwì¡FÒb`¥ŒD^ÑOܸ)l(ï䈊ћöRÂlòi!8ýîÒ$·SäÕhù‰pÈ^Ìox^#™ýîöVv†WIA]cï8Ey},˜%T +ÃÂìö!ÏÛX {”»äÈCó{LL +x?WëgiÂæ{Ÿ,úiâîwDÖúsœh, +g=4èáI)ý=,AiSûAv—tò’V Hº8‘éøé' +Æ.”{Ÿ¼fgÉ@—Þ Þçè3î%×1tÍ•_É}vˆ•´ÀÐqØÏ2Ø>ÿþöl‹¯BM>Âd(§Öû.~Å)‹øE%Ó¢Ø8ê;­†æxËTaWbrRÇÚœlûÍ ÁŽ´”™¿Øeʪ¿îÈvEiòk¸qŒw°F!mæH´ŽôÚË|aË¢Œùâ~õì[ÉPœ%T¨ÖE¤6ÌÙñFùåDë(äÄ¿‚Öj!sªž48Ù…‘ÓM Ö±<ÙøX裸ËHW࢕ëÕ†Â5ŦœXÑÊãvä†ý ^âv %œ— +ã†OEЀ¸ßDÚ÷0yl³Ýoe¹“ø ú=¼) +ÆósVCuè„u˜³3WÕø ²¸p(wxJ4l_Eâ@£’‡[Xž›'4íÔTÄ\8&+‰Ô“ &! xd|0Œ0Â}G‰D}Ž@…:Fh¨Ï¾þd:Þ}Š\©è>áS¥FYlWDำp„|ò“Ö<Ê·æ1„¸b&ø¹`«DŸThcˆoŠ +iŒ×m*‡ùHTÔ%#„2¼|ÐÊ;!óñs{)º¹).Xl¤3™„ZËÅ%ò~F¨†pÇâ¼ú€ÊÏ@Ÿï×Ö¤›U*& ¤úÃ~ò^´$ +E™Nn2îGÑù ÀÌiü¯s°+Å•—¢½Ž½ Ùßq7šžtï|,ðÆXãóØEìÛ¾Ÿd¹âæ[Ëê崴‡èé)6ëF[€ÕB¼]ÛO©¼Sò)WޔϹ”Ðt<G\É|s$™Üëëeß­æÜ°V|ÍÙŸVHÓŒ¹ïø¸B.ßY,€ÿñëâçèo‰+MÚd”ûJFñD¿P¡ƒ‡¾Öš¤ô>|!¹GwÉæy$|¶ Þóè¬&ÃfäÞåtþ²™[÷ÌéL&Þβ„]Õq©Ö­BqM€V^Â=KÄõþgÌW#§‘64Íδ9ÉC€ä^ª÷©Žõø^¤ñ&“&Á?.‘Ê‘ò"Rëäž¹À;f þÇ QJÅÿ|ƒcÚ„˜.Tò¾®†‘gæJ€©1•k.<ëõºYrA!âÇP”É(Ck™h% Ä/M§ÏÔØö,þþ\®ÜH=§¤~fÈe/ˆð”£ñ‹·xóßós˜nF‚K&ðê‚à&‹†"bꇋö!ÚRÄ6ÞÓŸþÂàÄ+â_øÓõDLøý%:HÅ$]é,V}ó%)SQ53㯜_üÚjÓÝrѤ<è:MÉ ‘(¾”¥-m¯zžÎç­~âÍ„ ¯¤¿‰ÅVpD +™ÓßÒŸò½S£øó9†þÈw"·óxàM‡"žøþ»oå3Q‘¼é·»PÝs¢×@æ× aßÖÁ4ä_øF‡û‡”°n\Š#ÑÒÍLû„¤Œd`gó2/‘]¿­º}øÓ(@“&R‰ïy aÇ éÛý]GžF“¿*òËÌö›qä¦f‰†’’eê´¾V¢âØ0ÿ¯¹ à +endstream endobj 10 0 obj<> endobj 11 0 obj<>stream +hÞTP»nÃ0 ÜõStmt4¼äxèµ›]‘hW@M ´<øï+)N‚ <€GîH¹o-Ùò‹î0À`É0ÎnapÁÑ”«ÃÖeÔ“ò £¸[ç€SKƒƒºò;çÀ+ìNåÛkñò“ ²¥v}ùsŽD·xÿ‡R€š Bîß•ÿP‚̺Ù¯¡Ê}¹Y;ƒ³WYшPWØ\É<ÏnŠË ‹ëfQTÇFÄÝMªtÌ=^˜c¸|qŽÌ-áý)Þùä•Jü 0fdi` +endstream endobj 12 0 obj<>stream +hÞbd`ad`ddò ðò ðÑvL) 0q6q5µ‰ŠþæËùÝ÷«ægëyþ+‚Ýßy…@ÜHꀀ‘Ÿ™‘‘IH‹ïû¢ï³¾ÿmXñ»Ärj.+ˆr@tEñâ¼¼ââ¼¼ÅÅ+V,^¼BŽ ÀªÅ'c +endstream endobj 13 0 obj<> endobj 14 0 obj<>stream +hÞìÛO«+ÇÁ'àûÄlf˜Í+È:AÙ½Œ ÖÖÆzg6Yi“¥ !Ûƒ÷?€£p Z_o´t6ƒ áÞ…!Èp `4' ƒÁp¦¸‹vWÿÓ¿sԭ硸Ü#u—ZUÝ­î_U?>p6»ÝîEƒétª}ÆêîîîÅ æo-—Ëõz½ßïµ'À¥…K¯–˳ív«‰FéÄ<¿"Ü]Jõ.'ÏóÉdÒ~=¦•Fé¼y~n0×뵆¸„p¡Õy=–繆Ÿ³çù‘>À%ÌçóÎ+±,Ë4Àø\(϶ۭæ8£ý~ßç2l:j+€ñ¹\žïFà¼V«•™7«)ÏŸN§ó.7’ëõZ œK¸Bë™ç/—KÍ02My~x½ÏêÛív6›5ÝH. - p›Íæ ‡%ó<×hcrbž„[ŦH:ja€³X,µW\MWbY–i4€19=Ïl-¦…N—çyíµÖd2Ùï÷fVÜ‚³äù<àr²,«½ÖZ­Váݦ)úÛíVÓŒÆEóüÉd¢…N×”Øïv»ðîz½®}w¹\j:€Ñ8Kžn$k+Y,ZàDM×ZÓé´X Ïó¦‡%Ã[`Î’ç/—ËÚJÖëµ8QÓµV–e-À žç7Õ'ŒpŠÉdR{¹µßïã2ÛíÖ%À¸5¥ñËårÛj½^¯V«p‡Øôp÷f³Ñ¼' +]µ×Zóù¼²dÓ…Y¸rÓŒ#ДçŸh¹\j[€ÓÍçóÚË­õz]Y²ež†fKäù¡N pºý~ßtÅ•çù) 08çÍó'“I:U €ã:å¾i2–e`è.1?±Xì÷{m p¢étZ{¹µÙlj—_¯×µË‡z4&ÀÐ]"Ï7 àtÛí¶é‰È¦Uò<ïÖ®jÓ¤ƒv¹¿kn$Ã2³Ù¬=Òoz€yž7]_ív»–›fõ¡N 0\My~ÿ©õáÆ0,Üôd÷t:ÕȇZ¯×gv2Ô©a†ëô<¿°ÛíÜ9œKçSGujX€á:WžßRÕb±ÐÎýµÌ”8Q¨Yó Ôóüý~_[Õt:ÕÎý­V« åùËåRó Ôóü éÎQ;ô7™L.”燚ó<×ÂC$ϸ*ëõúÅ%…ú52À1Ïßívò|€-‹Ú ªét:?DX¾¶žÙl¦‘†èŒy~Ó½g¸ÔÎ}ì÷û¦ ›Íæ ªZæZ„·45Ààœ+Ïϲ¬é†qµZig€>š®©&“ɵ5MÑ_.—š`pNÌó·Ûíz½žÏç/š™ÐÓyø–Ñ<ϵ6À°4åùç2ŸÏ52@Ûíö¼$ò@OËå²ö‚j:]çb±¨­s6›ip€a¹hž*×Â}äy>™LÎ~MµÙlÌ»‡ËåùËåRóô´^¯›.«öûý)57 ¸Z–Käùáž1Ë2m Ðßl6«½² +¯ŸXójµjºfËó\Ë ÅyóüpWnOœBpkò<Ÿ7Øl6'V¾Ûíš*ßn·`(Öëõü«Õêî­,Ë­¢ö §‡‡Wîó,ûòåKí×ìÍë׿úégŸ|ª)àš½÷λ¿úé‡ïðæõk­WÎ5cuÿÕ«WÚ€ýâ‹_ýÇ´(ŸgÙÃÃ6«õáûx f¬Þ{çÝpÖ4¹¿¿y~(ï½ó®9¢pµ¾|ù²x &¹Zcd>ϲй¿ûècãª4ùÝG—#ý"PúÛ×_k¸6ÅAúÛ_ÿæ¯_|¡AÆ$Ž®†ÎýòåK @ª˜ñ›©>\¡?þþñ ýðýÞ¼~­MF#thù ì) €‘ùêÕ«ß}ôq,ŸgÙ¡å³O>­Íó¥úp!á ‹Çì¡3±Ã!_9Hÿò§? ~¯Ä›×¯Ë'äCWOGWîòðð aÆáó,kIãÏU>|ÿƒCSG Éï>ú8\á>tõßþú7•#4¼êü>»¿}ýu¹_]=ô`zúÕ¹£ñ4y~Œ•L…Ó˜çÿåOn:B¿ÏëÄ\ÔEóüPù—/_jägqézïwÃZùÓŸ4&‚Á‘ç•2-ÄG08òü±rB …øGž?VNÈ´ÁàÈóÇÊ €â#yþX9!ÐB|ƒ#Ï+'dZˆ`päùcå„ @ ñ Ž<¬œ®ÄÝÝÝ‹·¶Ûíõl•øèP¡ûŠ~ ª5xòü±rBnÙ~¿ß6Ëó¼iÅÍfs÷Öz½•t~Ðn·+–ϲ,ü¿vyþÑBOµôcKõé—Ê–,Viê&y>ÏNž?Vò|à–ŽVm`»Ùl¦ÓieÉÕjÕô»Ýn>ŸW–¯¤ƒòü£Å½Vm®Þ¿_ +áõårYY>ì é(€<Ÿg'Ï+y>pËÒD·=Ï_¯×åì7˜L&ÅŸËå2­·ÛÅf³YX>Ž„?+ѱ<ÿhíã2i®~P¿<¾ óÃë1ÃËÇ?C=•H_žÏ³“ç•<¸eEžß3wÝív1òÝï÷Å‹å¤w½^——o)ñd2)Gôqšwe@ž´¢éBoöYøÐ~ ‹EñVVŠFãàN¨­¼°<Ÿg'Ï+y>pËŠÜu³ÙôY8Næ¯ÌÇÎó¼˜ì]Éuc>Ÿ%yZ¬*Ž <Êóëõ:´I¹‰Ú»fµZõ©öÐ~‰ùüb±hªª<”#ÏçÙÉóÇJžܬ<Ïûççûý¾iòv°Z­Ò¨¿˜^ ù ›Í&”kóüíÏúja3ŠµÂw<±•ž1>*Òõ>ß½xD¢g~~h¿ÄyûéÈBÜ…ÊQmž\„O,Öê3¨‘<¬äùÀÍŠ¹kŸ…³,k™ÌŸF¸»Ý®x¥iÒxñî|>¯”óü<ÏÊŴÿBøX MƒãGo…eÊk§¤úƒÈóûËÑ/E{Îf³–,ïE•!ì9ÅB¹Gjóùòþ­¬>¨ò`4‘ç•<¸Yëõºižvj±X”cóT%nÏÿërà˜ç‡UŠ ç©ðzebzܲÖd29: +¾þ:Ñgû¡ýÒ™ÿ§OU”óü8·¿Ot®„Ö‘K'yþXÉó€›U$±“ÉdþÖb±¯4åÞEÌnª­˜Mgqǘ·©Â˜ÙÆ|>®RTUž¿Ùlâ¬ûJ°Óã"Ìß"ÆÚá£c:Ý4½¼Óõçù±æ? M××Ú/±ò¬!-F…Êq•¢+=Ç\Ò)÷cø7~ñ°zèô8ÐgØ‚'Ï+y>Àà„ÛÀí/¥ÚpǺMq·ê wµáF8¦ñþ:܇6ÝY× +ŸnœÃ-pyªa¹´„-íMV «Ç<$V¶Íì•¡i2êYv¶güŽa»ûY9l9ñ@†¢itøihš;§ß§*óºÓé÷é¼îøJí4ìp:Š?aåSSLƒðÒŠ¿¤ÇMí¾þäùc%ÏœKäù-3Øû$ÛMÉl6+f/—ŸyoÏáËSéÊâDè¦í,ϻ묭¼m§¤ã6Ö Ô)y~LMÓ¸eît1\~bŠ?ãÏPíÔciÐ9ÏóÊ*-gÝ4Žî“÷©¹Épóüø8C¹×í—ؼMóÂë•YG÷Hgžß§fx”ç—<`p.‘ç7MW.¢Î2ôߤÅbQ¹GÞívéb•H$|Pšü‡ÛÕÊ„›åtƒÓq‡Ú‡BýY–•+ ÿ·áµ#1ݽMcÍóÓOO;:ìw%éw—çÃ-H“ÕÎyÝ•U:#ô´Â[Îó[¾ì)¿AG4re•ÎæM+”çóìäùc%Ïœ³çùiî] ·›f£Ei˜ßãËQj´f wiòþìü¬°LSD¿ßïÓ1‚–»é[p;yþ釡PF)ýQ‹lí¯Iü=ç„xÂiú9+~ËÊ?7}R÷b­øÀc¿Œ7|‘£Oz#ÈóË× GôKûNÚ¶õHyšAçHØæ³ÿ.3Jòü±’ç ÎÙóüøPy ½ã fg>ÿX—Ž¶Ü`¦cåÁ‚bôùjñ~6*?þè|ûÚùü•§ Ú…ûñmIü¸PIøjóŸ…ÿWª-žQ,°Z­6›MŸO õ„Ãò±òPIh™þO´lÛAÝV ûIQIøOø³eú'êEË”¿`gåíûjî9±Ëb¢ê/wel“ðŸâ•ÙlVy<¤ÒéÀÐ¥á|ùÅp^JW©âÓì=ª|c%MQsí6ĪZ~²[¶¤Ó óü4œ?¢_j³÷BœcPþˆ£{¤i–BŸ-2yþXÉóçìy~e¢ûr¹\¯×•h¹gL³Ùö,zþKíy~Ëçîv»JUå(5­*|¯Î¦¨ m:ïºÒÅ}ýjµzQ'~ñðŸJÄÕ[¾þ~¿O·¶²z{ú*oª¡ÈˆúäùE/4mÃl6«]«Ož6¯©é +Óé´ç¨Gô¢KÜÚ¦é÷é~噫˜šVÆ銇¹Ây»rŠo…˯Ç3mz>ŒQäç™J=éZå +ËçÕÚÅXíqÏ 7Ïc¸•ñ‘Cû%^¥ ?¢|ISî‘Ú¹q­J…í(ÆjýÜÐIž?Vò|€Á9ož¿ÙlÒ4>Ïó–Yôi6{ô=f–;Ô¶RŸ‰Óéýƒ¾Kšç·'Ò¡©Ó¡“J^é‡í¬h5¨ÕVf˜§Ãy~ûÆ·lCgžß¹y ÓDò| "œNk³ÖxLO2ñÔWy+®R9éÅçÅ*§ô¦zÊç™ðVåW ¾[9۔ϫáƒ*_*~V: ÑÓ•çùÅóqéëñ‹§ƒ#‡öËci(§|E‘+ÑÞ#ñÝ´GâZá­Ê—*ÿúŸòÀ7Bž?Vò|€Á9ož_‰mãóÝqrZçÓâu1i¸«Í²¬6$i‘ƼEdn®ÍÒíé¹bq·~\óV¶¿3rO?«iª|Yÿ0¿%Òo™Tß™uz†ùµÛЙç´y-ƒM;ª<n\ñ#8›ÍÂÉöî­ðŸxŽmT§ˆp/ÖŠ¯Ôžâ©#Ô\|PüñMãÜbáðÑÅqøˆ¸mq 3¬Õ”ÇeÂGT¶íE×t-®<Ï/~’B[ÅoÄÙJ\¿<þòÇ«ø òÞRÙ¸pñ)a±¸måK¬´Gâ®UÔ¾~±Vù‚-½6€”<¬äùƒsÆÀàœ1ÏOoùã i|=Êšojsì–l¿e“:ç?—ãÓ¦Ûít{úßü¦Ðÿ‘öôs+Ï5Ôå†Íó<Í«ËADÚei|”~J¦)¤QI¡ÓĻҕVJ§>¦ÛYžLØžçW>=‹I¿`Ӟг›:²tÿé\Šp)†\ço…ÿô|¾,œLÂùªX+œâ:,Ba±bù°bÓð_1nß –×jú -çù•Ï +ßèˆÇÜ*ž1> +_omiÞÐq±GÚ¯Žè—(´dø òÞRÛ¶¡Úbœ·ügŸ)ÿö•?+8âÉGn™<¬äùƒsÆ<¿2ñ¯2¼’ú†?[ªª Ø$|P¸«mº“­ “›L§ÓôÖûzòü4I¨ÌµKç–§-YÞ€J§„Õk›1ÒKGj*i!¥_ތʷ¨M?ÒÌ¿¥¡ZöðÚ¾«l^vÈ]ª<ŸJžvâ£'Ó4– ‡’ç•2Ààœ+ÏÏó¼=×MgA·Ï +Ûn·iÜÅ7Mœ ]ûŒyËtýr¬}=y~g÷•g­7U7 ÿC¡a›fà÷œÜž.7£Rye(J·6~ÐAy~¨?Ǫږ4_QžœÅß¾þúó,+Ê—/_>ïÆÈó{ +={-|©+ÜBy>ç"Ï+y>Ààœ+ÏOço6›òýÓã²ív»\.{û“ɤi–~±…‹Å¢g°_¾óPžŸnXKž:¨O_¨´[8ÿé³ÿ¤#M›úú®AÓÖÞPéŠñ ‘°ña¯hùÖOÖMò|àó,‹qÊï>úøy7FžßÓõ'œò|ngoç8ò|€Á9Wž?›Í:gYW–™N¸bÜívëõº3Û¯<Pk»ÝfYÖ™íÇ)èéHDX·çf‡%z*¡²ÍóÓ »ÿ~“¦×Sý7£§øeÛ*Ïó>ƒ8¡§*#POÙMò|@ž?Dò|n‡<¬äùƒs–O.¤­7#´aå­PgZCøÄÊqZ*}«v¸!ýOÜMò|@ž?DNn‡½}¬äùƒS´ö£ìJ&\NÔkµÏ…NÓÑ°@S¤^oÉÌÓ:lj:Cûñm¤¼\.+ ¯V«ö +>.#Øï÷iø_ Òûx‚íÙÞPµV´mOÐMM‡aùQ`ÜäùC$áävØÛÇJž08'æùiÛ'¸®¬þ¬,pD¤ß”™é·Ì¥?"Ò?.Ì|ª<ÿ &jj™Îþ +Ö¹=#ýétZyt¢³¡ÚÒ‹'è¦,ËäùpãäùC$áävØÛÇJž08§äùéÔît†|­4¹ UU–Ùï÷ý·- H˦N§Ó>õL&“tKRi:}܆µ{²<ÿñí,ýö& +-Óþ]Z"ý"!ï¹íãaKGú4TgÍÅwì|ºäBÝÔ4N$χÛ!Ï" '·ÃÞ>Vò|€ÁY¯×wGÙï÷›Í¦òbmH› +‹UVlJÑw»Ýjµjš^ϲ¬2[»IøˆårÙ”Z/‹Ðý'Ò‡%ÃG78´aMÂê•Vêì¾´ýÓJZ¶*ÔÚ¡ÜÚ¡¹Âw ߥOË„eBýqõÉdj‹›tèf”{*lCØ ÂÎptC›jû@ew +Úûg隸‹†¯9/9ôa`¸äùC$áävØÛÇJžÀåìv»íÏš¢Ýž¶%'¦îçÝ0n“<ˆ$œÜ{ûXÉó€èþþþó,‹¥çbåòåË—Mkýíë¯›Ö +o5­Õ´J(a3ݼs•rVöÞ;ïž½þÐ ×SþúÅåø誶í òáûÄoñ—?ýy(›ýððàÔÄ¡äùc%Ï¢žAAe±ri™¬^žÓ^)-qSÓ*E°|èæ)ÊÍ–¦c³åxi:0[Žeå¢=Ø¿üö׿)9´®rÍ¥<.Y¤Ê—/_¾|®aåûûû¦Ušf\?:µåÍë×M«„·šÖjZ¥²m®ð€±’ç+Š<_ž¯(Š¢t^n÷º®å²üÀQ¥ô¼æt…ŒÕEóüÏ>ùTž¯(ò|EQEž/Ï8ÝEóü–Û1y¾¢ÈóEQyþAM«Èó€1¬<ÿáááÐÍSy~ÿãEž¯(Š¢Èó®Ö°òü#6OQäùýy¾¢(Š"ϸZò|E‘çËóEQy>Àõ{óúu¸iŠ¥çbåòÙ'Ÿ6­ÞjZëË—/+ o6›»»»ívÛ´Êq›7”"=PäùŠ¢(Š<ÿQžpõÖëõ‹Ÿm6 Â-{óúõß¾þúôê©­ÿáá¡i•ûûûÚUÂëgÙ$¥ùêիϳLQŠ2ô1kåŒå½wÞ•çwn›k €‹úß~øß&“¢ü×bqhÐÑBgÔ2딉dÀÉóàúÉóàúýßÿú?ÿó¿ÿ¢ü¯ÿüÏß}ôñAåÍë×Ú.m>Ÿ¿øÙÝÝ€+$Ï€ë'Ï€ë'ÏžÑ~ÿãrùÝ‹ÿ¯(áÿáÍ)y>ð\v»&“ob˜_”ðŠHRò|àYl6yæe6{£} Bž<½õú_µI~,«Õ½V€2y>ðIJìûö0¿(›M®­ ’çOi¹ü®O˜ÊdòMžÿ¤Å  ÏžLÿ0¿(óù· €´Ûí¶Ûí~¿/¿(Ïž@žÿ4›½9(Ì/ÊÝÝ?µ5k·Û¥oÕ&öåÓÐ^ž\ÚÑa~Q¶ÛkCèo¿ÿ15¡ìv?hJˬV÷óù·E ÿ¿»ûgKɲtàhEö¾ÝnÓ·jûöwåùÀEív?L§?:Ì%¬žç?iIh±ßÿ¸^ÿk¹ü®r¸ÍçßJõ Yöý‰'¢Í&׌Jž Ån÷ÃdòÍ)ZQ‹hLH¯,û>íGYx׈Øf“Ÿ~"ò¸G烰Ýþû,a~Q²ì{M +=3üJY.¿»ñv;ñ)¡ò,};!‘ç?¯Í&_,þ1ŸÊrùÝ~ÿ£6Ôzý¯žùØlöf·û!PK†Å4,7(üÐÜÝýóÐ ßásÄé¨O }aŸ ?yþ3Z.¿«Ü×O&߸µ‡ŠƒÂü<ÿ)¬þíÌ*ãÂp;V«û³¤Ðóù·7ۆ皜÷ˆ.'Üçn6›»_ +/îv; ”<ÿ¹dÙ÷Mw÷Óéß·Ûk"x¬öj ˱X8ˆ:W •kanǹÂü¢l6ù ¶áy'ç;\BžçY–Íf³­&“Éb±X¯×Z yþ³è„|sö¸qýÃüÚ@¬OzFíÌ-ØïæŽÎ#n6{£µ·íöß—H¡ÃÁuSÏ‘]hr~Q6›ÜŽ +pŠív[žrŸeYí¤µh·Û…ef³Y\Ë,}`äùO)Ïêœ-l$<öŽû<À²Ùäõ¬V÷Úœ»\ÝòtÌÈtNÎï[l_=ô‘à‹Å¢¸Ͳì Ãòq@3×o~šÊc‰òüv‹Å?N‰MÂÍþvûo͈ƒ¥˜Ü:ërù]çñåàb¬²ìûCg݇0¬µÛýðØc,àFŽövè“ƯV÷î.§¸ ],G¬»Z­ŠÕÛ§ôŒ<¿EŸD±OY,þ‘ç?iOF¬s"ëdòM‘4öÔçјP§#‹ñ {uØ·ûŒ‡©˜á—u>,3Ÿ;úf¼»ûg{#ô^ìì g!€£m·Ûâ&t³Ù±ú~¿w Ü&y~“õú_g óã-–}¯U«öèìÐ0¿Vé<²n!–äÖtÎ  ì÷?¶WöJÂo܈۰3‡ïêèX.¿³Ó!æùGO°w Ü&y~­ÎÉÇ•ùüÛ#RMžWžÿtw÷ÏÐwE1.Sk:ý{Ëžt£…;«Ð;ÚŸÑèÆ +ÇZŸz:™ õŒxbyg~åû×Ö~~ Å/;Àbž¿^¯XÝü|àfÉóSáƼ}^_œ!Ù9‹ò\•yÆa6{SéÄðʈs°#l6yûnJs-ÿè<¬SŒFç¼úp¸õ¬ªój¬cagœœ_è<ÅyPà8ÅMèl6;bÝpëzâô~€’çWäùO3ñBY.¿+–¯Í{oyV䘬×ÿj +…âÀcWä~b[õ9$ÃèF༹qg¬ÞÝï_3žwr~¡sœåˆ:X,Å}høOžçýW̲¬Xq2™hFàÖÈóËòü§>á|X¦²b–}ßgJÿègEŽIçÔVMTØï¼tÌjè<¦FKrk:‡®}%ü6õ›³OÎ/„–ï©·j·ÛÅ[ÑÉd²\.7›MK°–ϲl:ƵŸš¸5òü²åò»>a~íìúýþÇöYÊ'Æ2<™žÃ:fcڧž+ãêœp»ZÝßòî}CÍçßÆ$3ìÃáEûçh¥£³÷γÙÈNe—˜œ_è¼BȲïíƇZ¯×/êÌ©œáGËåR—sÐóƒOIžu†¡L&ß´çð›MÞ9Á²i’?×`»ýwÏG-ŒÈÚwøõú_ç;Y}Û~lÞÚŽšeßÿöÍ/ÄŽì<ðzôCD*a‡! Å&Æ,¤À;ì—ÆYðîãZ{`½YÖS/Æ »‚Ç ˜fÈ,fm‡‚dÿqÏNU´ØRÆÊÄÓ‰Ù†3šY:Es©ò¢XL¼Ñg§ÜËáγKiÆ|XzÞîKqÏHÖašë´Dg¤Ï èÁ"åÃF ì@ЧÒä|Žt =Ö ‚ +oÓÃá^¨Wƒü²ÒëÂKý ‚ ˆá0‚.ý_‘•-`YSúðÕqœ¬-zÞùü ˜ª¸²|IwREÜ=ÙF¢h¾TÎs隺¥H%aéYª=»dÒ—&õ£ÛûZ4øëûQÁKHË;£¬:9ŸoJ¢Ç:ADKA^ö ‚ ¢‡¸®ÛG<÷Þð wguunÍ4M~›Q%ÿ°, þäû~͵*g/ôÜç+ŠÜÜþVš.‡çé_èfQ—ùЛ$E9¸=ƒV­¿³òÅÝ4$ gåÊ| +EiK=~XåaÔêpX=Éù iü¥”ÀAQ'ð"¬"7~ãÉßþÜK¯fôg/ÿ!‚ :Cžïa²{á©øžoÛ6ûÆ4M×u‡ïD€KC=Oî¹Ï—¾•3-EóÜ—ºøҥ¤âÖá8;Š.Ô4×KO8o5Ð õgƒC±ølêÏÒ”ï(¸ 5Ï£5;>wà°íQ{›±žä|†t£ô) l‚ ˆrñ}õ1ƒÁÞÍK/ñù8ýëO?ÿM8à›G¯Ì?øÙWß~'õ€?µQל>}úÌ™3O=õ™«¶C]I]IèÆ“O>Ùê®ìÀÿžç±{IýçATâŽãÄ„ý°ƒb@¡Ï>_jÚ™,j®Ä¼Ab)¤‚K4]dAÕ§O)' < ·(ŽÉ¬}ï ÛÛÛë999¡¡Øj¨+©+ êÊâ ‡Ã.ù|×uSî ø#ëé_?|+ã8*ç÷ÙçK5»a\)%; g¸j€Ã÷£^5¾Hs,ù±ººGÍöGH‹9ÎNu—vÝ[ŽŽ©,¥äGj¡K‹ ‡w¥Û7ÚØ’u&ç7ÕwA]%Š"ö®-bš&ÓõüE;‰a1ó_Äç_Ü=f®þüÖ~¼<ž">ÿÚGÆææÑýK{÷6'íØ‚½¹¹ÉtÓññ1 ÈVC]Ù666¨+©+›¢c>ŸIï,Ý ÿ„°;õ<¯ñªŠ[U¶"öÖ竸Ü»4á–ÞýkFjc(“! gx»•ÓóêU#3â‡i®«Ÿì8;´ì4H#9Þx$®;\¤!°Šb|5ï­ ‚è*âÛhL×Ã[¶išü7–eÁÉðU¿Ä ‰ŠŠ¾Ÿ>·†q¥‘버Ì6zÈv«`ž´L‘¯kséÇJG*x—Ê¥‡3U6¡´QáöaªÔà íLbyƒÉùŠÓ¶º¸ AD@:KÍÊÀç™l¥¼ƒã>Ÿ |æç/íÝC|þædvq÷XL×'‚ ˆ¶Ð1ŸÏ2LÓ\Í€ÿ³±šMÕ•Œ%ç+¦è÷Óçã&°R¯%5l®{‹ê‚©Jº²º5í!¸¿ª4Vf +®¾ÛÕªž7–ŽÌe‡eÍm{¤®ô¡g)ŒU:èti@¡O¢f“óÒgJëÖ"‚ ˆÚàÆ^c“õ<ùëâqŠ~‰ï°¸Ïçß»ú(cäæÑ}Äç_Ü=ÞœÌÄt}êk‚ ¢-tÌçóç{*­!ü?cFêuñÿpzèó¥£R‘¢â“)¯²i2ÇC9ìðý¨žúÀHƒ¾nWwKZm¡}jRʽHGfî8£J¤@ fÕ6þ{‹t£V=.ÌU·O­DOÎW¬F· AÔ7© öø_µù|Qàßž>€ß >ÿÜèdþÿxíÎ õ5AÑ:æóyz€¶>‰8††aÖ{èóñ ùÒù¤2Ç4×)K¶þ®¯awúWT@†q¥žëG«¬xMv +T}#Åv8¼«É}2-A!ÝÀ_ëi|­¶Ð:$ç3¤‘bx¦ÓÈ'‚HÂïûÈ_uðù€wuŸùùËãG#ç·&ˆÒ?™?? ÃÕÂTZ½¬ä|†ã8YŸí›Ï—ŒrzáÝÞîuÈÏ츈f‡mj¨ €ÔÈB+ü3®­j€¾éàE ¢’?_|] +ÙJs2»¸{̾?{ý€úš ‚h óùšcÛ¶tw@VbCß|¾&úBV¨'²Ðƒ}YþEÌ Œö6c#þéïФÙÚ%î‰í +Q9jsËÐp›<âßÀjìº·à—¾Á¼¨ÓÍV‡tå¯9‘[šâ®s³ã§þð(¾Ѷ;‚ ˆTLÓdï¡A,ûYþ +œã³I¤>ÿòxÊüü…Ñ!üxóè>âó/íÝÛœÌø“=‚ ˆv@>¿‘¦F°,+õã½òùRwQ§ý“æZÖ ïR‚©T™Â µPVV¶Zš‹Ô¼©M%xZ¬þ“oÒ*nA%¶“•zHߤ)뢅ú8Îô;ÜHë<¿tgVý= 'u)øþ!­RY9‚ ˆ.Á-:àºnVZŒ(ŠÇaŸ2M³ÜšdùüÅãœüµ£ÛÓðýÉü!âóÏoMÄ®Ý9¡¾&‚ Zùüz€fxVƒ”T]ß+Ÿ+ôš#£h.u;ôú_O;ÃáûQmUÒMè)¢g*¯´V:oyð¼q#a&•W¬¥Oè8X—ªrØöHÿ Mxì‰ÝEýµ’nºÑ³1ñ0DýÉù üYÓÈ&‚ ý±,Kå¥uñ蟇Ðu]ñíð}¿”j¨øüçnDˆÒO¸<Öú¿”ƒƒƒõõõíííùœžS톺’º’ÐýýýÖueß|~žç9Ž³òø`0DQTõuyfB*|"'¹±?>Þ£qwT¿<÷ýHê©ô—Tš#Í®¿ëñ*i›¢‡Ã¬6žÝݔٓ†3©Íö¼qEW‡õPejÄZ²¸„ƒ}ËÚ(EãWt¨¹»›Úk€W¬Îmkê©gKRŠ>ADà•9öÒšõNšÜ–oÜeU#‡Ï¿¸{Œøü›G÷oOœßš¬íÌêÜë9>>¦Ùj¨+©+ êÊâôÇçAKà†Q©!‡`øµÇñ}?öOÎâqƒçy<íÁ4ÍX”¡ŸEsÏÛöøFÏ 4ib#ÕÆU¤Îv7FΠ…g‡™:¨¶#WÐMåÄJÓtõL)×VúIãbz®HR^ÃÜ—Åä&¦ÜFÕ°>”•ß"ùÌ.õ š^mCum¬0>¯)EŸ " x…÷YöÒªâóá6™¨V„>s2C|þ¥½{miü›7o2Ý4›ÍÚRgE¢( l[†™çya"Ÿ‚¡5DÁÇ>”QQæg‡»2uA`99G§ÔÐÀöö6ôãÆƆJW€„̶m>ÎáG|ï’Ê(Uo‡Ó¤?,Õ•úL®>ø|˜#†aœBKª˜æ0;àÒ0UÅIŸ/ž2Ó4aš‹¿/îóƒ`S4ð£†Y妹®a¯t×€æ ÆÌá#mkÛ£¦’f¥©’pXÖFývEÚé +4i8LçÙ]]–{n JÒlózrŒa­Æ[¯ y†»€›]öE×½¥[w‡w¥’5¯¶éîY輡@Ú׎O‚ ˆ¶†!“T¸ŒÍGŸ2ˆøüó[“µíññqÇ pEŽã – e¥kÆR7¡üÔ¡ÈÇ\EÑE÷¼+³XÊ7f,öˆçyÒr`̈©¢—êJXMÓDFi–âS¥¶mgÝ£ÊÇYª‹z´…ÖÍÊ>ø|X½¹Ì‡o\×eòÀ`01…^ +©ÿÉ >?ëƒ}~–™¬MF)È»Úú +iv±VJ?¦l/ÆRy¶¦¹îº·êläd˜)u”6x’æEëÓN7Tx{ÂðÓª1a"Hg1XÆa…YÊ™Ãx€6g|~L=ªÎÆGL}² ¡&ÒpFSA϶LpÍc‹ …­7ºÅG‚ ú’wÍ^Þ?øÁJ}þÉÉÉ|þË3Î^?@”¾´>bQYÀ pµTQ,õQE6ƒd9*>Ÿ— +(šR¯õà²EáÖ+V”ŠÏ·,KZ”ëºY>¿þ¶Â#Vbä(iÔsŒÒX­Ô?žÌp¦Ñ®yQ}ðù|‡Ir +ÃíêJQñùYw‘Ïç#Y¦ZüýºñthÛé¬ôó9ü¬¦®!yruuO¥ª ¦qJSôµÚ”¡ú®´†Ãáݶ,GM­H¾5¥ß«8Ùz“µiØÝ1ô—äŠÓG‡<¤ùÚî¹#‚è61—Êúúúk¯½†²··çlll°d˵#ÄçÿôŸßQ/*øœ§ÁÉT”bQ¯¿þº(óÇ¥+üõÙgŸ=}ú4’bÍ ÉÓO?½š—õÆo<ùä“<+8™<ÏÊÓ>ô¡qKÎä†ä•W^ɺÜp8äAÏóÄ?qS +ßdÝ \‘ÛN¸õ`Ž¢ë•,*õd^_b]+ +†Sì|îókn«¯}ík*I¹/¼ð?-k”ž9s&«Vb~òÇ>ö±X­’Mº¿¿+j0$cÌã7˜,**J½¨ÍÍMiQìœsçÎuÛçû¾Ï&r”ábgÖÓZù|n÷ù¸è{≷©UìL©åËJ)¯¨Vp¡’u-knœÅ} +Ú•o¿¸„Š„3w>Òýÿü™ŸÖ_«Ôq¥(úšõùÒœØWÿþûü ˜J§UjØ®ÎUô³Ï¼Ù „‡öYYÙ‚Ã4׋—CWTúõ¯íÒ½ÐÚŸ ¢aò¤PÅ(æçç;ßA +a)Ž›››óù£÷—ÉlŽøüW¶"õ¢RáÙ’± p**«¨3gÎdYúXQpEžkSܬ­­!µúÊW¾’šü,ú|äa óÇΡ\ª(•ü|^žŸ=ȃeYHQ| q'5?¿ž¶‚Í +ßøÆ7ð¢ž}öYƒH¥Ï=÷R+Q0Æj•lÒÔämÅ¡i½ª¨¨ñx¬R”J~þ+¯¼ÒmŸÏÆrßJ*Y;¹J§~ŸÓ\_4íóß~† ´/=ûtðù ó“ªôK¯UÎkRâá8;ÏÿùbÆUÑ®À§>þñ«_ë‰'ÞŠ]¨)ç#MÑOæi×P«Ø¸‚ ‚Û×Fj•:Úq|æOÞhÜç[ÖÞãÜšÖY«d~ûÅ*îs)7º‹‹îq` +ü…w ágŸy7¿o]þÝß{kY¥Ïùš×vߤkQƒOœØ¸:ÿ7?TYŽšõùxl1ù4ojm_çìõƒ,Ÿï]ݧžªÑsª¸ž<ëtnHðBø D|>^žüœz!ø¥çy,hUMî5è9K­Y'óä®> ìB¸óç]œÚq0á÷<àèû>Rf ‹[‰µU¥xÓIÛŸ§7§ÖF5ŒmÖP0ÚkP¦„ +¥?auƒ|¾¢ï6ëó¿ðÅ˸êI:ä¦ìJÍ¥º/©ôË­•çkHËÇ,ÏüÉ0®Tì +ôÝgŸy76`ªÜ;T˜ å/;J¡Î©éýêíŸö‚ßóx–Üâ}ÕÑyŸÏVïä¨F&~¹Q9i³çðù_þò—áµ”wŽ²>ÂÏažËmÛ£“““ØGøñàAú8põÔóÕkÅßú­©ÞŸþiØH­ MRÏçw¥ +(¦ô˪Õ÷‡{ð×4ùIûúÌ3ëçßÊj«o}k7G +ñK/Ý®´—íùRô«®W0*Ô«W[­²z0Šæxmÿê¯nÕ_+4”T>ýëÿ\s­¤ãêoÿöê|ðtðýBs0¦Š &Ÿ~úzk»tjÃí7þĉ+XT¥›qê¯?ð'TêÓ¼Áµ}¡¢¸Ù›A‘ +¼b§šØÜäöù—ÇSÄç_»sBUŽãàJVEŸoÛ6;MÔ¤‹e|>³¢¿å‰âYP3£\Ÿ¿ÒïSKø³|~ª æ†+}<íŸWÏìùV<|”ÂTâñˆ|íÏ£lb؋Dz΢R:ïóy Jú°`ë<,57{ŸŸoÖø~”CHÖƒÎuË"¦ŠMÌÒ/ˆT=5x@k8ÎÜlÍßçwñ(’J2¹6+IÎýzÀ}ô‚ní‰WضGMU .N “Ñ|Ó-ë0ÍuÏ—µöªokb³‰/#•"Í͆Y¯áÓÀ—£:¥7©†í)]ÞµõA=dYŸíÎÉ¥½{'ó‡·§Ÿ¿¶sDm[ܦ4ÞRŸÏÒ°³ö(šR®nD1Ë ÅŠYÊð{>jážPºÏ}²Ñö§ŠwþKè) ž‚~ä#_^T|>7áC™*£Ôó<¶×¾&ÛD±ýùlââÚ„; ø`†Fãµ¢¸Un&³ùÍ£û é¼Ïç#“ ¬sxŒ‡ªÔˆÏ¼¸a’««{ÍõÑ–žr§N¥×R·aˆ›‚Æô¼ñpxwñXb@ÅŠ›j?¤-’ùŒ|)ú5 h ʽì5ð®†)­•¶v—³»øü…ÉË–ˆrG.á¬K5(}i¤ÁÇ"¬“zúgm+†#]Þ5\E ‚ úÉR>s2cºþÂè~ô®îgùü³×ô¿÷ù|>wwwÇažMg †Yj…ŸSPwsCbYÖJ1¾O^KÅ”ÞÔbæ3×G©J9kG@¬+³®ëºß7Œ¿œ™ïQ4Ç ‰¢ÃG*rœÅ©îXYÙÒY–j›¢‡Nšš×R4 /Jc[0´ŸâtÎÒæ0ÅRBÐàpˆûk®± ¹—Màf¥ж—µMƒ×vãŽty×y0AôŠ¥|þµ;'ÜØÃF‡HŠþdöè_ “ùÛG÷Ù÷º±½½½¾¾þÔSOinòERefYJ4$80lŸ/5¥ISÄÿšª‚ `%dù|Ö•ÀÉÉIò¯®û}ÍM¾x¬¬|ï¦|#'µ>ëÅ$ü÷7ÝûR÷S}~Ö~ të»T79PlVW*îþP_ñ¤Ø¶ƒÀã)Ü…&kË/-î@‰M@ žŒèÚجYY.wÙsçüÖ¤H9}ðù !´„G‘9[.Mù|ék#ïÚ¸Þ±¬ ÍG—¢Ò‡sr¸©áð.®=³Ì´*îð3fʾ4aµŠ*¬sÔ†£aŠ>Lê–îwÀËõÛ3if»¶©Å­C*Ò .›ŠGºnk¾(áku#ïYmc‹ JÑ'‚hKùüÉlÎuýædviïâó¯ÝyäpÎ݈à{ï꾆Jssóõ×_o‘ÌÏrõû|&íc¶GÝ”&MÏg†ord„BW2s˜š Ü"™ÏŽ0Äœd>?æí91ÏŸêóù†‹ÜVM,vcc#µ+ë÷ùl &CHêeÚó |hÏÚLiƒdueœ½~@ùùËÞi,ö„/ïUW¦Ÿ¿ÐOžKmd+Þ «PúùÒò¡‹ë¯0œ­®îåˆ#äÛ>ЊœgÞ2øíÔŸ¢¯aˆA}„ã³Æ÷#}*£sK¶XØÕ7Uñ®®¶=Ò¿ u“熖Zð§¥èAp|߇Rx?µ,+öZ ¿´mÛó¼Š^®—òù‹÷k“›G÷ŸÏ¼ +ÿñòxªS“?âðððµ×^#ŸÏá†D´µ"0a(rkšfêXB€îºnÒØÇ|óYÕHíÊíííÝÝÝÔ¿¶Îçö:¿Tw+ú|èYöhv±»c¿Lõùb¿ÃØpg0,µ^‰Å²®ÜÛÛË:§,ŸŸUN†Pq)ŽÅ8T¢0€“Iø0ìùÜasê·œ#€Õ +²º²tbæ"EuÌçóÑžu u˜°\ìØdó·æz6èó¥B²æŒDÜFjžÎ'RDéC§@³Ã­‡ëÞZYÙR—]¼døl¹7åû‘mª“ùp§Q¤ãnV<"V³õ•Zèúã %6fBUjwKŸ\„âšYÅH†KK—ÓV,MZm¸“þw¡DLºs¤EÑg‚ ˆŠ€÷PÑðH3¢KÑ^Öç¯í1mrîF´t}ò`'œßš°/Œõì$GQCR»‰»Ç‚A©ÏgDQÄM+•:˜Û/â_<3¦µ“n0&îÔX¾ïóñPÊŠ'¥|ÏH,;ˆï…šºà0· ÉÖKýýåñ”?w +^¢o>_ôù Y]ÍO‡k—C“:"nŠ  à°¬²Ä8”V*‰¢¹çña£U…+E«ýö&ç+N™zê/­,S­ <µeÍT_á̲zAºšµEÛâq(¸ÍÞV&7øÿ$m ôATAEÉl|àS%æs.ëó7'3nN&³9×õ©œÀM‹wUÓMâA¨‡TšÅ4ÍT£ÅÅc2%8 .Å}>ày^RuÏ † %§Î è£ÜÁ¬ ›æ‹­ù†ñ—xrþ¢2ŸŸ´÷IßåóÓÚ¡„TY-ŽÛÜ>Ÿoëƒ&P¥üŠ±}(Å}/TŒÏÙІôpL…­N°$F‡ì)Ï£‚W!ŸßÍú|ß4q€Ò\¸Ö)_é•~Æ•ÚÔSÍággÙ½15ZóÒÑ$E¿íÉù \çÖ“¢/µ»5ç9÷ +ÆêJ?uÓ²HWi¨O[ZO«”x­6 T7pîFÄäÉÚÎÑÍ£ûˆÏ‡‚l¹´wº¾ +DÙ¥¢:y&¶˜·¼XÆçÃP¬ÔçÇٲ†}«©Èç/ÞŸŸL×_¨ù|‘ xDYè‹]jDQÄï]Ü„¢>JÅr·¿"lgJêvBÉü|ñ4¾ðo?)´Á|~#4îó=oÜø«÷px·KRE¤¥}TµçT$ g0œl{$Íiì’‘êÇF/®%ëÉl/ŽÔ¯šæzu#J–ƤŠ'„¥Ì©R4µô*­‹#k"Ò5 +”‚ôŸJÑ'¢‡0o–TRà|®ô“Tqrøü‹»ÇLžœ½~?">Ÿ°¶sÄ~<¿5¡®¯.7bŠ> žçÓ§ê>Ÿ›U×u“c)‡]a™Øbi±a¿ì(í0Õù|Ñá‹n?ÙÅ|„ð|û,]ÏC?ȨPôù¢ô}*ü^b÷¨>JáŽø®Üí«RlÇA û A dÿêyôOo/ΟZ\,´DÏo„Æ}~Íñ×Õò¨q¯ÒöœØJ•¾m4tãP%ß [cz¶ÁMÕ!MÑ7ÍõfX‹ÂaRÅZ ”îqhé.¡–²Ô² ψe—Aé^Œ–¦^㱞æÒõ°u<<ÑÆ;"‚(Ϧö?>„Rר¤xç]“ÞÉõ +YîÔÓþù5 Qúâ•©8J¡pöŠ­´E|>û ´ 2 àº4ȳ·dÓñýbO?dþfèû˺VšNœY¹©¹‹ñù ™C³¬J[@úú_ƒ‚¨š*”¾i®·ÂÓÁÔóÆЖR ]i'žUÞ®p˜t5¨(I®‹‹Ð–ÚÝVãûÞ)±õPe`À9®{KºXµÚØhpwÍ®W t¤)úé#¢WðW×ÜoÊ%¾Ãæðù'ó‡ÜÏßž>¸´wñù×îœLfsþã愸UÁ»’õfR| ®(á›äþnH<ÏK;P‚hQbéôE|>ÿ¬ã81¥?r½\J «íTçóB"tê& Tñ.›Xiðq©Aö©û| â†ÆŠ…mÛ΢±‘–:Èaâðñ–§Èí{ùÊe&[ZOë'¼;`p&ÿÊ.þÄ»Ð'wðtÕ硆zêàóƒ`Ú`~/ž[unsm”«ô]÷ÙE}€¾hÊw)9_eA¨(ÂhÛ£NÚݶÏ&ènÅUfYVð7 gЃ*¿í›ÂOo|ƒ@PŠ>A§í>¸vçäüÖäâî1|óè>âó×vŽàœ³×Øì#DEˆ’w+CüeVnsì489&Þ‹øü˜§…Y} |ß•Þ7*õù<‡<µÁSÅ»èâLÓ„Xßá^]Zlbæ<¿(ä±`Dª_ÊpBÉ™RÄsŠS Ú‡54¯yj ­Ïˆ+Cê(bå/¼}àôÃÇ>ÿÝ"—#Ÿß[Ÿ¿½®V—~&¡•&6×>&÷ú“–ß7¤[Ñ$êRr>_¤Þµ\».Í¿íLT±ÀxF[²Lã«G*ÝRøÓÜuoUwi<¼Ïú–6©4ç¡ÒV%‚Њ0 UW¾ï—˜«œÏçÇ@|þÙëpÂÅÝcöãù­ €Já³IŸ% }¾iš©þ¤ˆÏ_¤yZ˲báƒÞR©Ï‡^àIæÛg‰wX‹#M8_Êç/;^1XR²ò±ká° Rê+â9¡@¾a!õ¢©¶>#­¬Æ‰þÁÞ`ÇÊÊõ"—ëªÏ_)@ õÔÄçK³|+J?ƒ·`üºËBwœee h«–&7ö©….]v/9Ÿ!ì†q¥ÄIÚqAkœ¥‚¡¶=‚©!ͩ•JõꞪ †ªv·wCADx6æ²öFÔA¥¤q–âó/Œ¥?™ÍoOœ½~à]Ýßœh´ëàà`}}}{{{>ïÚ–íÁ``Û¶˜® ýëº.>ÞàS«(žç!% ‡CvZî'0¼á㢨1 nDºêpW¦ÎYF‘“Ù/S–$¹Âð.Nþ ~ã8Ž(«aøÁoTƒX¬zWÂÉ0¤ÅÑWd£ ýðk!àu^ªý³&T[Œ^Á0¹:±*eVòÀ ²=ÇöW>ÿöKEêÜUŸ¯y=5ñù ™Ôª"O^jíªÛÐ ¾‰MmW˜®‡›…F†šŽV'ˆöèY|<—î|ðÄãVg•K#_¶=*åBž7®çBDñù…oæ*å¨Tw×ÞPÅ…ÃpÖHV@=àwG>Ÿ ˆ^!戦ʱTƒ7´eeÍ•âó/§ˆÏ¿vçDÏ^ØØØXÌññ1ÉVC]I]It¯+ù^¶ÔÝ"¿ä pÿ½÷žÏ?|ËûŸEêL>¿-TäóñHøRúà6²í¯ÿD‘¦û~TÖµ¤á°Vï戢¹TÞoL•«Ð*¤A0•n¦(xtc¾ñ ž¼õ_´Æ 2zÞ˜¦'A½BLdeɇ®ë²ÔP–2mÛ¶˜Ì ß—’œ¿(Éçßž>@|þÚΑž]póæM¦›f3úOµÝPWv†íímèÇ êJêJÑ®gn^¸¶jþfÈ|þïœú_ó%·¼!Wì@Ï_–(š×):ðð%¼m$¦ø¨.1g´:9Ÿ Ž´1 ¦RKwT±/‰(ô¸4j–ûèÌCGš*_Åþ¯F6Ôܪ©÷Ø=AKE‘mÛ§–Ç4Í ˜²)ÅçÞÕý,ŸÒ¶ŽIvêJêJ¢{]麮eY™Éù‹ÅÎËÎ{Éù‹ÿj¾T°ÂäóÛBE>!³[%&õe½‹Çpx—–¢uàIªe)ân'çs¤æZ;wá*ÁÒt-e9Ûu©»ñ¹Ïúr/‡GߪØß×°hÄþu«ŽA´ß÷Å×RÃ0à½53M1eùü £C$Eÿöôõ5AQ.ƒÏÿÊç¿â|³`iäóÛBu>_*¸Êrì•j:‚h(šã±*økÚw>9Ÿ!M3.’i,]…|?¢ñ¬-ƒÁ¾4(¬rÀdÇMñ)©aûà«P¹Á |6uéíæycÛÁßPÈ " CÏóÇWTÃ0bÙøðKx]õ}¿ŠK—åó/§ˆÏ‡¿R/AåbÿÇè=Ÿÿó_ ¾[°4òù2 àF kÄ_Vçóµ$õù~„ Ú½N´Ïã#¼à<êIr>cuu¿Ù|û†pÛ ¬„4’5'™,½¬Æïvf5Þ8%®Ò¸[÷Â%A„”åóoO >ÿÂèšš ‚(Ãøerþïœúá÷ý( +•Ö1Ÿ·³ú˜VßS÷±»¨ÔçK5WÁsiö2¥ÅÀ4׫ÛêbÛ#<Ö·Æô¼ñ²«´Ìn›ÞÎ]iYêf‡ã씵ÑLs\÷Vé°¢ÐAQeù|À»ºŸåóáOÔÔAD¢(bIÚžç…a(þéÔ©ŸŸ:µøð'ÞýwŸ¿÷ôóGýãéú/ÿïý§,AÇ|~7¨ßç/döluu¯Háø‹?½ûÝ@šBŸ{œKSa ÎÐ66¦a\Y*Î(Íù‡eŠÆp‹pœß·HqmkEm‚ B¤DŸatˆ¤èßž> Ö&‚ –b0†qJÀu]þ×uúò^ŽÄgÍêöÿð¿½Ey®E>_Cñù¸ì*’ýÓr½Ahü•Z› ‚PÇ÷ýSi0¥‹˜ÌçÇÿøVž2ù| iÄçGѼ + XÖFßR‹‰Þ"õƦ¹¾¬7îar>_”ð`E3 hÛ#¼ÏÓèm#A0uœ˜V0T˜Æ§¸ .Û™o‡v+r !ˆµ¬ezÞ ùŠ%mqÝ[åê÷~&ç3¤f‰ÀïáãÒ\eZ…ˆî! „Á˜Ï½nH7ÎІ;‚ ¢: +úüÉlî]ÝÿêÛï\Ü=†Ï^?Ȳ+pµ6A¡H©2ÿ /á™rîFô«GYOœÕäyâÏצ|~Lñ—ôe3úà¥^j†Ã»ÔãD—f•Ã_Õ}Wo“ó9R!ŸLöýHªi":Œ4’‡mr”,W„¥ö'‚ ª£ Ï¿<žŠº~mçIÑ¿=}À>5™Íù÷ 2ŸÏÇãñññ1 ƒ¶ÓÛ®Œ¢h8AЙ; +Ãpmmmk ûnÙuÝ•ÇÀ7ð‘Š* ; VßÃ÷ýê®E³2 tnRæhå?ðgÊ—Ö'NŽ+’Ïצ|þB¦Îgg©Òl{„¿ø/[ A´iV¹úÈ—zé'ç3¤ .äƒ`꺷¤1ÄR¬&AhŽÊΔe£Ò• 8‡Ÿ ‚¨Ž‚>ÿöô¨ë¯Ý9AìÊ¥½{ì#bJƒloo¯?æää¤íýÈåÆp8Ì}²hHÇQ¹®iš5H•^ueŽ~ ü7\HªÌ謓ù²@«Ô ÿH¾Å„ñ£ýJ8}úô/~ñ‹ÔàfùUØ톡2ìÕ‰¢Z@Û"–e‰ ã” (Ú*«ÂâÌÎA* Åg%ôlòöÿèÏ^@ž2üøëËyÔ(ù|mW¹F|¾ôm]]ú~„eW:¯"‰ÞbYÅsÂ¥©þ=‰ˆ­®îáišëp,¥ñsì• ˆ«‡Ê¤€'µb*2&µÀä<—ÇÓÉlŽ–ó[8ÿÒÞ=1¥¿A677™nê@^wé>ß0 i9Aˆž­AŸß¥®TÇ÷ý¤o/Ýç*ùÿ¢z-âó766>ùÉOB!®ë&ÿE\Ȳ,ø†ý& CøQ1è Ül–ɱm›×Aä”2©!3ŸÏà +©ÐèÊ"³’ ï$_Z{[Åç¿~9ÌqQòùÕ1Ì õ¦|þâQÌz÷‡*^Å$PÑééÿ–µ!-Dê±ûã¢óéúÒó“ ¢EÁTÅÀÃiÒ¢Td>M(‚ ¢Šûü £CæOàøñìõıÀ 7î‹)ý Þûáááöööîînú±tŸø¾—㺮&>¿K]©3Û±äüE5>?U­‹ÄÔkŸ]ÉRôSãìB±‘É2öU‚R X`Âó<î¡Y˜ZäF=Y‚øÙ$±HA²aù„ÂSKˆ)}‡èÁÁÌʽ½½¥Ú߶mÇq`xÃ7I™ÿOþ¶ŠÌ‡ãÆFžÕ€|~uœ*FS>_ªáõÎÁ­¾ëÞ YYÙ¢BtÛåi…ál8¼ëûÌ2JÎçHã#9Ó\§-BD·Qñð–µOE™/-‡ ‚ ŠSÜçÇòí×vŽÇróèþâý)ýÔ¥P…ÏO͉ÉÉ}~ogn2/½ +Ÿ/Í~‡¡R–Ï L–Ã*–z*#‡‡HØ-gèy2æ¥68 CÑTÃËNd±±hNgÖ±Øä|ô?¯"óÿûÚF¾ +ϯŽ–ú|xWysG¬¾JN`òŠ‰Þƒ\:‰ß÷#¥M8` Êú¸¢Ì‡ÕŒëAD ÷ù±|ûkwNÍriïÞBHé?¿5¡.(…r}>ó†a …A žL>¿NÂ0dmîy^ìOåú|Þ¹xö;Óàüäâ>Ÿ._Í®EQÁ‹ò¨„eYxilG@ªW´Á<ëAʼn\|ÝÖÞé¬ R¥îç^zUÅçÿõ•wòÕ|~u¬‰>WýèQ÷fLHÆ>nYø§VW÷ôê*‚¨jØ+=«¼‡ÉùŒ(šã–ÊÌ'™Obm‘ÎetÔ<ª Èíýa|àô¯«È|8®Žþ%_Èç·…:}¾J‚}LŽÁ[?û¬ç¥'So=¡DM;\þûŠŠ4ô…ãì´ÎäÍçsšM¥ó½ï}ïàà€¢¬+ŠÓd>AQ'¥øüó[fQÖvŽàdz×Ór2(:ÿÍ íG+r}~EìÇq² +aÂͲ,nÀ’R%îè8†aÀ™mqŒ‚÷N¹>Nzu1¸€\Ú󼤤…3³F,œ i¸T’í Àe~†©ù½1x| +ó"r!ß÷EÕÉ€–WÙéÐì¨f½‰$çøŸQôù{?#Ÿßqêôù/·•#åÕóÆRi0Þ¥Þ$úƒb‚ëRLÏÞ¶gŽ¥ Ûñ˜cë¸zõêÑÑM%¢*azÑÌÃ7*!’ùADÍ”âó/íÝcåìõG‘ýµ#Ä´0Ï? )×çÃ÷,íÙ0ŒÔ‚ àÉÉY>Ÿ ÏTLÓ¤\ý|ð†M5´¥û|îÕ³²Ö™†eZ;µ´(Š² -¢ãx +zR°û¾Ï. +’Ž"$Þ$ÂkˆìIQAÑóËÅZUq"óÐIìBÉðY,z¢ÿ¨fõL­ÿÓÏ“=5V°Q +*±E˜20_HæAÚRŠÏ¿ytŸ»øqs2CdËÅÝc8¾Š!¢ ¥û|®×Rõ&OfÃ0Õ—Âï™q…¯pòð=àž¤mYu\X¨…5~ò¯¥û|îÕSÓàaxˆÁ…ÔÒøhßÃil$À7¢|Nfl¨Ä‚J¬4(J1¤èó˲¸*åˆ ’o"óé)–ÀûÚÚø%\Ž§¾ã{„8à›ä>Æç^zUÅçÿý›Û¹«A>¿-ÔìóäûÛÅAä`8¼KÉù%²ºº'Ý+亷ÂvCÄûpœ•†d>A¡-¥ø|àÜè«o¿s~kߟÌ"²… |ÑùOfM¿ÒÞòo:‹‹+Z?q·‡YwÀå†ã8«2¸.C|>ONfG/Þ­LȧúRn,“ZRÌÖ.˜ ­ÔîƸÎÔP¥=XÓemàÝ}$ ܨ#>ñžk…“—ã%@·.Ò|>H©+ ÷Ò©Á¹àIìlcHê˜Ìîz¹Ï­àHcjƒ‹ñ,Öh©sñùð'îç=Ïã¿gÝJ íÆ?’ükãðý>l£GÖþ‚â3ð¼øÒÚÁ^ŽGÌ7îX(Èç·ƒú}þãáq^íËòƒÁ>õ#ÑOT4%ç«cÛ£TÁíLŽ‘ JÙ.D2Ÿ ‚hŠ²|> jy¦÷³v&ÿñæÑÿgßÜ£âªÎþŸ?»Þµº^úÇûG»Ö»Þù½ï]ËÚMâ-ÈÜu !$$“û ¹z‰bÔÞMÆK¶VÆKÒX'*jm©£F£fLˆ¤Da A,r ad~ÏœÍl7ç²çÀœ3ÃÀ÷³ž•3‡3ûìËs2Ÿýœ+©ì‚3%‘ÃcÒ&jý†!Ê ëH|~$fSõÞ˜Ë7æ }©æTx!q²ê*#Ôt y—ðÎ7[°¢´ŽÜçÓ@k¼:‡Ybš*ìWýÙâêt¾¹#ÉNÜZÓ+ô‰•F˜iêAùüÄӠŧ«Ðwf$ÞÆœ×ëåÝÅvÄ«–_‚d‹-åð]!êñ© =Þ….Ïd¿äæRrì˾6,àóÓ…”øüØ$±Á꣨ŒfB¡+%¯Ø³NII3“Ô±nwm   Oˆ‹¢„ÏEXnR…>_äxÓ%‰r9ÙÝÅ®hìdåúÝá¾”]’N2Ÿâ¨qý°>Ÿ×Nkªè¹ …B‘x>?ɦŌŒtòùrÈ{›+t³lôù4Ðý6Õëãû24UØ+Ÿïr¹Ø„±ßGà³H2ÏÍ4õðôùfM²¾õ;q»bxŸà`»ò«>–9gQäæò豄j5áóÓ…úüØTIÈê‡B=D0š))iZ,­;·»–þ‹8Á`v¤)ùü‹]½åRVÛ>®½µµµá£§ÓÌç6¶L\nø|¾Êxð_¹ÏçžÍãñˆ‡¹\.z‘NÂ~5ô¥|/€I­2¬F¶q(«ªªêêêÂá°þÝô’ùˬ™ÂâÃAÝw&pa.÷ù‘X= ½x·¯¼JÜðllÂðêë@  ˜WP‹C©×ì4‹Ì®e¸Õ盵“š!ÖØkZeÑç»Ýnýæˆ(ÃéZƒƒÝ@IæªÔw>ë ÉUS¿Èž·³SrsÙ±ÿr"m†ÏORîócf(V¿¤¤ #€DéÓ²¢ðz/Ð1ô_Zh°÷‡ðû[ ó¤#ù|ÂwºÅL¹Ð[ÃáÚ«‰OßaõùVJsÍÖø|Âív3 Ë_ ƒ|〽bæK Kmé#œpû4’U*úwÓ«>_èlÙ‚ëó­¬h³ƒõ>Ÿ›qìhbhž0<ý ;RÄårº}q(‡ Ù³upyNŸ¨—]A³a1,Ú`ÞŸÔ3bXÙ˜3;'GÜ)àçO•Û—¯J±ÙlzÐ|з_äÁ¯Ð»»¼Uâó7nUi3|~º0L|~lÚ Âê»\UŠÆ‰Þ|{|¾æ’’&ú—Öú|<žzÈ|i‡s>¿¬¶]b]:®¤üÚªªªš+6¥“Ï¿0¼‡|>/³ú?×ëõ²W¸”Ô?Ó[lGÀPìÛhõÙP==\~:ù|j­•›dŸÏ7Mö +M öŠ_h±ÙG+ŠBçä…úá,^K]]cuu5 å|þ˜AÂ/p°—®ˆo +6 æ‹k° Ù3+îñx$OFØŽ8”q;“²Ÿcf(óL¹ñÉm¥èˆò”ïX"m†ÏO†•ÏMž»\Uq Œ%0ÜÈ̬†Ì^8çóÏ|Ý-/Ãáò;;;£®ébeäLIµÓ‡|¾¢(ܲW˜’ÍÌÌäÇH|>?I  wEÃD®5ÃýCi](µnøGÜÑK•ÏÄü3¯`çÏ_ˆŠ8îGƒAŸÏG«qû|›@Êdú|>9E».og Ùçeâ>ŸA+Ëï÷S¯jܾ¸r&ËW¥¾WhˆÛíV^vO(è’ÜV¦¯oU^žH›áóÓ…aèóô_bõÝîZŒ0ÜP”pFƧùÒç|~[OX"^JÏ)è|qÈç¬À>###¢ÊXv€ÏçãÄõù"Š¢ˆõâÅV žO•Ïçͬ )Á,«ø‡ƒJ&tQáêKLJàó%×(ŸŸüê,~ðD3‡‡‰Ï …Btul¼¬oX$ÃÇ7DgëYôTáÙc_ TDNxi|~º0l}>ÃÐêgfV+Jc C‚Á.È|púº]¢’ îðz½Ù*ÌMZœóùDé9Eâ^ºÃ}˜ÏváœÏ÷ûý\rû*ÖÕúR¶Héo @îܬÙðÞÖˆtý¶û|>j4 xuºfˆõgãÛìY ^篟º|î%âë,ú|~uVßØÒ¬…È`|>ßÕûpÈ>Ÿš!¿3ÚÒ™ÎÁg”!*ÔU’Jɱï¬}‘Z¿-ë >˜S°8ÿÿþÇ5äøàĉ$4’¾õ»ÝµÙÙçé_`˜C7k‰Ì÷xêÑE†5*cHÎãDdZ÷§fµ¢±S¢_Î|ÝùlÎù|EQØ‹‡Ðfffj–›~I²#YU¿!ðùC#îVˆs>?SÐ4¸\ÂkŠêõgãY|¦ÃÊg‰o™ý­¬??Â/Šæ­dŸ—.™«xúÉ×ón¡Ïû0Ÿoq£gxú|±ÜZË'ÿ;î°ä†Rx ½rï5‘ÎP"Í€ÏOÒÂç ½ðxê!óÀ!¬ø|+ßÇáó5ýé„Y­ië‘è—òúÌg»pÎçn·›‰GC¹jè ¹54±ôbâžvÔÂÂl¯ÄQŸÏŽµA¯ŽõgãžÙåriäDuã’­6ñˆDž¢²î±ycX{ Ÿ.¡³‰Çè¯(î݇®…¯}«¹1ñ†v—-éâß?og©ä†2v~säõÌ[ŸŸ.ÀçÀ ôJßë½€n€ÄÏw¨?ª”–èßi<~nŽú|^KÌ…B⻆¾TttZ:{d†~àŸb¨CA\¸˜Õ „f8œðùïª7Þ†gëÞ½^/~Š~æ›D†ù<îSVT]z0äMbM½]¢B­åeù’þ1ƒAó¨K$±“¸N©ÏëgŸÏÇUÿð|"FÜà0“ùDÑ‘JÉ eåüÒÈ'Þ[ŸŸ.ÀçÀ!*+ÿ]RÒÄ"êA‡€-Àç;ÔŸyž²Úv‰¹ØÕ‹)m Žú|EQ$ÒÌ—jv4˜éPÞ±fäÎù|BtÚfÕéš³Ñaâ_éñx<ú¶ñ½Ãw­3(ŸÏ>—/‰‡7›½Öe¾×ëMp!ë‘‹qjö0ÜA£&‰{(¾óÝÿœºp)ýð½ü·äV²»¼u磕ý½!Á{ +|~ºPýÙgœ81ähooG@Ò€Ïw¨?íòùÝá¾ÃçÛ~qê_Ç›.ѯ'›»$†Çëõf«X‘äfó×%¢wÈt³·hqéÕhFF†Çã1¬-VàþÓívëßåÃa¨‹-Ì£0œNü-3møµ™R^ÛfffîJD„m‹@ HwIæ§úPþ„½(?Ov#ÙøûÞþ»äØt§XûÄѱóó%·t÷I¤1ðù€íÀç;ÔŸvùü†Ž+\­Ð¯»zs/ ]¨Œš|[àeØÃÓÐJ…B|2ÈÏJú].WjL36§.õ-ïça¾w¦ß}àL(XÏo…ž‘ÜJJŽ}É~(«M¨î>°ø|‡úÓ.ŸßÖ接¦­‡^9x¶UâaºÃ}tÌ™¯»égßé–†Ž+I»öp8ÜÒÒÒÙÙ‰e•îÐP677ž¡ …BlÙú|¾9”ï¾û.»ÀAÕƒ´[•¢?×ÃþÚ'ŽZ‘ù'›»i3|>`;ðùõ§]>?"üŠÆ¨É)¯ï¨æüŸoc¿ÒÁI»öººº*•îîn¬¬´f¥×ëåë å-·ÜboRÃdUúý~š´4²ìé þ¤‰žï|÷?ùmBîóÅhë 'Òføütáþ}÷,ÎrTöú’|¾Cýi£:ã¿ôœB¿Ö´õHô øì׃g[“ví555L7¡D?Ý…C©(JFFÆÈ«`¯®®~óÍ7‘œGÆPjV%Ÿ´ìÑþ˜‰!cçç[ôù¼>?ñÛGÊ}>uõ ÝŽyG™!ù/Ðh `qþÿýkÈñÁ‰X¡4àóêO}þ™¯»¹ié÷QHT 30 Wø+»z“sííííuuuXVéÎèÊ@ 0òJôi(,X@×åõz1±ÓšÖÖVZ•MMMü~»!‚Á ø«ž…ûaw„¢#•»ËOY)ÎgO„%Bj}>õ -ç1րχÏ€t>ß¡þ´Ñç‹¿¦­‡^)=§H$L[O˜Žá¿žlîÂ<À +,¤}V³‘‘¡( +Æw$!ç³Û¼½äØìŽp×s/[)Îç·›DH¡Ïû>?.ðùFÀç;ÔŸ6úüˆ ðËë;è×ãM—$B† ü²Úvöëáóm˜çXAQÊ`Á`pÄ\Q(¢+¢1¸# ±Ÿ†Øï÷KdõUÙ³ù ¢ìØ3}~âL¡Ï÷z½ìs].u–€ÑçÓÏù|ƒŠ .  iÀç;ÔŸöúüŠÆN&Xžm¥_/võJ„LYm;s²¹‹¿ÒîÃT€ƒ¦8Ÿß‚ Y¸ï‘þ;ȇ§J߯”Ü>v—‡ÄûH‚¤Ðç»\.&óñdŠDŸÿχ€á |¾Cýi¯Ï¯iëá¾¥­'L¯øN·Hœ @‡ñ_éÏ1Õ`d )΃c¤ì.?Åîw=sÚŠÌçÏy%H +}>ûP¿ß? +§G(òx<™™™Ôô¿‘¸'Àç@ŸïPÚëó»Ã}\³4t\¡WÊë;$Z† üƒg[Ù¯t0¦:ŒB¡¦8ßãñHd>Ão ÷Énwªã;Ålã8ARîóGáHü~?Ÿø|Iˆþ¹Äþ•°Äöl;|¾C>Ÿ(«m5Ë™¯»%Z¦¢±“Ž¡Ù¯϶bªÀÀív‹ÅùŠ¢èý­ˆßïg÷‚]‡ë ´Kno~úÕÅ®ÞãM—ìz¤+…>ŸÕQ57B¡ïpÇS©âõzãþa‚>ÿÅ^ ¿B ,>8ñCk}‹@ #/ðí04D]o ðùùüîp_CÇ^3I?H´ ø5m=üLõQ-F¶Ýæ÷ûEA‡€Ä¡‰T#nÑïÈ# ú|>ZSôoJ.Ÿ +ÛH¼›xFFFÿ_žð¸Ç$w’c-Á`»í)(U>Ÿ’ž7âaRÊÃIÐç‹Ž@ ò=èÐGß"ÄÈ‹Ñö} +`ðùõg4Bé9E"g.võòcè_LõAáõz³U‚Áàæ¯>k†Äãñð?ñûýCn¿¢(™™™­7Êצ€fñÒ˜²á°âÇ̦¡äÃÊl\hÂð?¬šs‚P(DÍàÏa‰óŠ•Ç]f¸Ýn‰»Î ú[ævÜŠn.K9¾¤WÔpŸO=¯¨È‹óé–ÔŸžr]•Ý#¹eøÊöM¿ú|‚åÀá°|’Ÿ ƒÝÀ…ÏG àóŸH#àóêÏ$øüãM—$ræds;Œ‰}0(˜Ù³8ŸÍæ¯.Wü;u(2qC€‰GŸÏǬ5,33“ @ ®Ô9ÌW‹ãÈ…¤•mv°&ÍZ©ëÍyÊkŒ­Ü&hÊÎ.qÈ1ô®ÖïPôA No6|Ôó†çaõÞt™løè_·Û’[^ à[ôƒ¼[ú'Û…€½gá¾É-cìüË••—ímjj}>ßÖdÛ£•RFÀÃ&üBW=Ø¿…ÏG àóŸ£–dúü‹]½9sø|[’¯½µµµººº®®.§û8Úî󉸥þ>ŸÏ.ŸÏÄ£ø ++ëµXó?’†Ò:LjV®>?nQ7¯ÁN<™ÐPVUU%2”š¢tjLI ·Û-‡gffêM¸uŸ¯Ÿ´‘Aî86` ßpéÑ[ú]9öxBÒ¬f(5;€²þ<áq ì.o•Ü2¾ó]꼑ãóÙƒ!ò‡ìʷÄA%+ 6úüŽýÑfŒ¿zÆøçŒÿIÎøŸª‘™3þš™ã¯9~ìÌñã¢1nü¬h\§Æõ³ÆÝ0{ܳÇޤƄÙc'RÌ;iÎØÉs®¥Èšsmöœk§ÌÆÔ¹×PL›{ÍtŠyј¡FN42gª1k~4fÏÏœ£ÆÜhü”bÞÍ?‹›Õ¸E 7Å-?¡¸U±ÈÃ…Ñø1‹E±Èb1[£‘¯‹%ѸÚ, +îqËÀ¸™Ç æˆ%óÆÜ1g`̳ÆÌ‘30f1Ý ò£ñ“hLSÆ”‘=0²„˜¬‹Ic¢úc1‹›DÞM?e±hB,T#W (&RdÞªÆsO>æÐ2ÏɺvF,¦ŒiÙј‹)Ñ›‹,Š)ј‹I±˜¨ÆŠ©ã(nŠÅ±¸AëYLw],ÆGc¼ã(¦‹kcqM,2cñS5~‹ÇâêéÑBñ#5®šq ö+{ëêœh†añ!Õ°l™ÑœÃÒε±ä3VHAãfõg!<]KJ7Ì{c,nÏQ,MMRÓOVY±”•=·?k©‰ëÛÜÕŸ¾bLŸÇ4©Œe³Ù&9MŸÖÌ2Û­²ÌfœÓX*Ò—Qš²š…ÔD4Ø\do:Òd¤¸IÉƼd˜$©IŸÌ”>G¦©Üþ4õm¦¢pÇâ–XÜL1©?æÇb^\37s(&÷ÇìXÌŠÅÌXäPdQ\+É]†é‹g0yÓç1ÃT¦Ïf† í:]BëÏi&iM’Ùâæ·«&fÂçÀp#™>Ÿðn‘ø™îp_2¯½ºººJ¥³³3ÝÇÑ ŸoX~,ÂJI÷KÌêÍëÖÏ9’†Ò"\jÑ Ÿ·zVStH2Ip(Å–¸ÝnÃfñêô“\¾”E¡‰*®ÍaüäfS7 Š HÐÊòÔ_©ÙÕ%íé ýPj¶ZL‹ó‰2¾ÿCÙþoÑ%óªÛÛœBŸ?¨$ø|}þ5[æM{sÏÌ¿ì™ó×Ýó+vßZ±sáßv.~kgAåŽÂ··{Ž¯9V¼þïÆw¼[ßÝæ}·hû{E»ßÛzÛû[ï<±åî6ßóÁæû>Üüó7ýêäÆß|´ñÀGúxÃ#Ÿl8øÉúÇO­{âÔÚ'ƒkŸútí3Ÿ®=tzÍ‘Ó«Ÿ;½ú…3«ÊªV=»ê•³+_=»òõ³ž?æùKõŠŠs+Þ:·¢òÜòwÎ-?þ÷Â÷j +OÔ,ûðü²Î/ûøü²Sç—~úùÒÓŸ/­ú¢àìÕµKÎÕ.©©]r¾vÉuKjëòëBùõ¡ü†úÅê7Ö/þ²>¯©>ïŸõyÍ ÑøWC^Ë?Q|ýEÊŠ…mþ[Ž ¹r/5F£«1·[Ë_F£çËÜ+ÑXÐÛÔa5¾Q£/·j"b_Þi¼5ráÖ>Š,èkXÐW¯FhA_Ý‚¾Z5¾XÐ÷ù‚¾ó¹}5¹}Ïí;§Fuî7Ÿå~sVªÜoNÇâÓÜo‚¹ßœÊ ’þ87üQ,N.  Æ‰…½ï/ì}Owö_ØûŽÇõ¾½¨·R·õþmQo…]Ôû—E½o.ºòfÞ•?ç]y#ïÊëj¼–w¥<ïÊ«Ñèy9¯çh,y=/åõ”åõ¼˜×óBÞåçcñÜâËGÔøãâˇ_>¤Æ³‹/?³øòÓj<•ÙŸ¹4ÝOæwÿ!¿û 5~Ÿßý»üîÇ—Dã±%]Æâ·KºYÒõ𒮇–t=¸¤Ë·ä‹K.=Ðüû‚öýÊþ‚ÖK[,ý—oéW¾e;eÿô-kò-k|pÙ…—ýã¡Âú‡ +CÖ>\øÅÃË?xùù‡—·|ph™}ríK¥kËJ×¾PºîùÒuò¯;â_ÿGÿúCO­ö© Ï<½áé§7øŸÞPúô†?<½á‰g6üþ™?»ñ±g7<´é·‡6=rhÓÇ6?xx³ïðæ‡7?ðÇÍ¿ùãæ_ÙüË#[~qdËÏl¹ï¹­ûžÛzÏŸŠJþTt×óE{Ÿ/ºãù¢ÛŸ/ºí…m{^ضëÅm;_ܶýEoq™×[æ-*+ÞZV¼ù¥âM/o|©xC xÝÑâµG·¯>º}ÕÑí+îXñòŽå/ï(|eçÒWv¼²sÉ«;¿º3ïÕ‹^Ý™[¾kAù.÷k»nym÷ͯïžÿúï™óúžY¯ï™ùÆžœ7öLÿóžiÞ3åÍÛXPb™þæžœ¿DÓˬ¿F3̼Šh’¹¹b—»b¥š‹f›¼·¢‘_¹cI厥•;–Un_þööoo_ùvñªcÅ«¯}‡RPñ5 m>¾mËñmEïnÛönQñ{Ñt´ã½¢ïíyoëž÷·ÞþþÖ;NlÙ{bË]'6³ìt/%¨6ßÿá&ÊQ¿8MS¿þhãmØÿÑJV¾7W3[ˆe¶Ëlߦµ¯(­©9­õ‹(›µ«ÙŒ¥².5ƒQîb)«O’…bYÈZ"êã‰È,iÒÑÉÜð‡æé¨?#©éh°éµþŒMJ¯y‰'%5/]æyéO&y闞ΗšòYjú6;ýv`ve§ýÆ JÙ¿ôk£%¤©eõj¦ª‹fªå_¨iŠâï¬8§Æg¿]qö·+ª]qZࣞSz>yÔóÑAŠ•>¶òƒÇVžxlÕ{GãÝÇW½£ÆÛ¿[Uù»UoýnuÅï£ñ—'V¿ùÄš??±æu5^ûÃÚWÕxùɵ”¸OFWYéºþÜUÍ]ÑôõÔ€ôõ”š¾¢ì™o3X4‰Úô¨Ä:ÔŸÄöÿ±?ýú¥²þ<ö³#[îWSÙ½ÑT¶•RÙݱlv§šÐn{¾ˆ²Ùn]BÛf”ÓÖGÓÚv1­y^îÏlË„Ì–¯f6Š…±ävëkÑüvókÑä6/–ßf«ùbÒC«àó`¸‘dŸ_^ß!Q45m=ɼö††¦›zz’ú¹N`¯Ïg¢^_Ü+Â}2·úCöKŠ¢PK4…ÊLõX¬ÏIC9¨×›v{}>\C1Ρ©"œH2©««£q¬®®ÂPŠ2V>sè]3!oq)ñÃ4åîq}>ƒ?Û’‘‘‘àL`Ý®ïsj¿fÔh‰%³>_3”VŠóy*»§¯¿$¹YL(èº'wS¤5ho›S^Ÿo‹¹qx"yŒÅbö€Ï‡Ï‡Ï‡Ï‡Ï‡Ï‡Ï‡Ï‡Ï‡Ï€QK’}~M[DÑ”×w$ùò;;;G†¶×çsÙ ÍNÂá?ØX/J ËPÑHþÑ0”ûÇÌZÛëóÅQ6; MÍÁ &“!%ŸÀq-‰µâ¿mq)y×Å]4½ã®2+ð½ yƒC¡3ÿVR„-„Ãaq(­ç³Rϸ³*‹Ž(’›Å÷Øüùÿ‹ô(ö¶9…>TŸŸŸŸŸŸŸŸŸŸ`È$Ùçw‡û$ŠÆwº#24ìõù¼’VâEy ?7`z©(Šßï§ÓruIÇ»ÝnI#飙÷£?IÐsŽ`¨Yé÷;ìõùt¯½7; MÍ´1ühMY^ÃÏ£²²eS©"Ÿ|[Áâ6?^óŠÅ¥·ëâú|³쪡ã 7&Ĩ1ìl©*ê¶RœÏ·HˆïýàkÉbwy«ë¿>ŒTØÏ…>?ú4D `ø½Îg©ÐÙø ¥…ÊÓ>|>|>|>|>|>|>|>|>|>|>`dC_ékc‰ +}?¥/’èN’}>qø|›DÔ\ìêÅ  {}~DÐõ†g…¿™Ï§uÇT°!n·[#]éWf†322,jÞÑ ÷·Ô‡úwm÷ù¢®7<‰(üÍ>šŸD ·™NäX¹"Þf3­mxùŒ!,%®"5{^ úüÁ®Ûß!ôïR;™É§nIá½ÏJq>ï1c~0vþç’ÛļÞYû"ç|¶·sú|6“iÖi&îC$îRZoá¿ðùðùðùðùðùðùðùðùðùðù€4…Õ1z½^ú2hXvÈ‹KõtÃê3’ïóO6wIDÍñ¦K”!`»ÏçºÒ°ZR|×ÐçÓÚäK/33³$† ìxW®1aòãÂ=›ÏÈbÙîóy»áÇiÞ5<Ÿ-4èl&Ð|†Ä}ÃÊñ©• r´²”èöÁ‹ç5·‹>Ÿoʈ~°«FßÃâ}ÎÆþÐív§ö~g¥8_<Æã).<ð‰ä6qUvO ø¦HkÐö¦ŽBŸÏ&‰f^‰3œ¦"Ÿ~loÃçÃçÃçÃçÃçÃçÃçÃçÃçÃçF ¼ìÐLžV—‰E¡ëÙ$ßç·õ„%¢¦ôœ’üNèS”ÞÊÊá}æ"…ûZ•ñ`µ÷rŸ/Vàë?N¬Þ7ôù\0ê%0­;¾rù¤:º$»Ã} W†P;ã^ /Æ6Î|8¨KãÎ>LŸX¯AS½ox66ÜúàˆP¶mø¬ÇJŽÒOª¡!_J@€.™–~Ù¢Ïç.öê`W~ÐE+ˆÆp§;ÉX)Ρy"¹G”kÉø†ÈQG¾J$ÍçÓ Òœ·/i¤Jƒ•­[+î‚ñáàS‘ïÜÙ8£àóáóáóáóáóáóáóáóáóáó£ +½ÐȱºL¢ôQ œ|ŸO<Û*Ñ5m=ádö@8T22ZÇŒþAí ›¸J±‚×:Ÿ(í5‹KTý†>_s* |¯ý 3Evé)=»z}§[$Snøµ“Z+¿^Âmø®($­#÷ùi¯o —Òú³Në—cvZ³c×°Ö—’¡Øä]G7)Ã=:@|jLô¨ƒZ5†—/®VºÁÉ÷’ƒ•â|ºSkÿwÜ„ïÿðjúµ¦­G²F +´çו}üNÜ•2’æóùÿO¸0l·kpõ÷6ú-<öÿ.Ã'Dìmø|ø|ø|ø|ø|ø|ø|ø|ø|ø|Àˆ‡1Šf^£VDáOßI¹3aEq¶#N_’ãó/võ>ßVVÛÎ\}Ec§Dלùº;™=.2ŸÅ¿M†É ŸÏš¦XóºÜçZzEQ˜Ûd~X¿¢í]¡¥ç”´ù,žm•_ŽÜ7:áóyi®¦n\ÿºÄç›e: › q/y¸ù|ºïè éy×YA£Fµjä—χ&îXÛˆ_Eó¢•â|êÆy;ïgóÿd}sy}‡Ôçeq¥ äû|þTª|>k‰8p|kF“½nãüχχχχχχχχχÏŒxå÷!z¹AÇð\.—¾Ÿ]E‰~r|þáómÌÀT4vÒ¯òò˲Úö¤]~8L#™ÏÂðB¸ ¢Q^,÷ùš:|Ž¦nßÐç‹V“þC_·¯?›˜±éÏý~ÿRnJ|¾ÙRr»Ýâ=H³:¬û|½Ôª1k6û+³A7|¬ÀÆ[‰x]’mqG#:W}Á&ÿñ¦Kò§i¶>þñðù4 +4‹hEðµC¯” »hbÔ¶0iÈØô¦ ‡>>>>ß:ðùðùðùðùðùðùÀ ï¼ü붙—qáJÓ!¹‘.$ÇçózËÒs +{E¢k|§[Ø1¬ŒÿàÙÖîpŸC û&J/™¯è C^Ùkñ`ÏèÔ}ÄHòú|EQØߊÅÌt~:fP–ÒÒÎçK&|\6(Efv°ÞçëÕ}ÄHòžMLÚ\ì{<C·oh5%;¼…ܱ'¸Ekq)‰î]ì1£š™XºC62‘U3¨ `;¢·w»ÝúVIŠó©7®ÊžÍ'ÿÉæ.ÉÒ¸û•O~xJܶ—¤ùüá¿d6Ùø:Òï71ó¯y¨Ä–†Ï‡Ï‡Ï‡Ï‡Ï‡Ï‡Ï‡Ï‡Ï‡ÏŒlÄâI³c¸zÊ0‘Ÿ„Ïç‹{žÑ@r|¾XßÖ¦WÊjÛ%Ò†Žöds—­ +‡Ã---_]}ùüK‹õëÂ^ŸÏ— ׉úW }~D•“ôŠXÉ,ZJzËÆGcØPvvû=¶1”.!>%U>Ÿ [_Lé_‰˜ÒÓyÌÔ.½.ÎøجÊ}B›ïˆBÞúyøÓ †O¦èu¨†¼jRèó©I|\Ì ú}Ãâ|·Û]xà^r/_­÷=úWþsCÇÛ¯eú|q&‹;núQfÓÒÆø|ø|ø|ø|ø|ø|ø|ø|ø|ø|À(Á°$R/q 5$òEr$‘ŸßîãæÌ×Ýô +ý+‘6¬ðòðù6+†sÈÔÕÕUUU}öþûJA’‘1ÌM~›ËÕenòùúj|}ž™Ïçús½§¥SÙ¥ôÙPÝÝ݆oºtðlë07ù¾Ó-4óåO£¤ÊçGtÕø†ûò¦#}>¥eQÿjž“š4iÒÐ|>oϲÜã'ç¡õ¥Ä¯7AŸ?äU“BŸ/Ú`~Õ\ÿÊ‹óéÈüÂåâÖ­|î|ºV󗽤ÐçƒAútÉl… ËífÛFl¶Ó»6îÃÂçÃçÃçÃçÃçÃçÃçÃçÃçÃçF¼"TRx,\ìŒÂ2<=Éñùœoë K¤ÍÁ³­tÌÉæ.þŠMª©©aج®;pÈçG +|½ÞXðù"@ÀãñpÑ缇ñC)'…>_#ð5zŸaý£™Ûç{¯<¥¿ôÒK¥*o¼ñFe ®²+upÿÉíº¸Ù$WkŽ·¾” {Ï.Ÿ?ØU“*ŸÏ»]Ó|¶È‹ó#÷vÅ'¹ôQt¤~ÿ‰²ŸËë;]_ÉÿA+Ó†­'˜EE±wvÁçÃçÃçÃçÃçÃçÃçÃçÃçÃçFV¾ý‰ßǃÁ älðù‘$ú|.çy]eé9E¢nÚz»zù¯ WloR{{{]]]ccãGç|¾Ïçã«IüY¿âD¿Ä\«Ù´ý阑4”q‘[kç|>ßN¥i þ¬o›x¶P(Ä&ƒYY¯f6²¡ljj’ŸÖn¼yµ¿•U ñ¢Ö—_âƒ`‰øüDV ß±±|:.4¸¼Ïé¾·"Þ… ˼ù ôã`EÍYÉMaÿß.hžó²´ðùìÈðh!|>|>|>|>|>|>|>|>|>|>`4`åÛ×)q¿ÃçG’èóõr¾¢±S¢nN6wÑ1϶²_7]Âü—àœÏkòÅZ}ýªM³|’Jéä̺ 7¨†ï:çó#BM¾¦V_2¬\z›9v³ÏÂl᧢.’oæòV‰byPK‰þŠõ†æÒñù‰¬šäßΨø&ø[âë†ðm ñA­3åù¥ïWJn +÷má?w‡ûœ¸¨4ªÏ‡Ï‡Ï‡Ï‡Ï‡Ï‡Ï‡Ï‡Ï‡Ï‡Ï‡Ï¤V¾ýq#ÿ†È-%|~ÒÌ*—ó‘†_eµítLy}Géæ9ó_‚s>?ÓGÜ^z½^ÃU)š(·Û-iÿÍ©À ÆZãÒ5}ë„Ï矋}Í õgã•üfíá—#),·xE¢aÎÈÈ0[ ➯Og­,%z‹F¿'âó‡¼jøí,™Ž—·Vó„ß+1Cœ6ü¹-Šæ²«%w„ÝåMOžúJ¼;8Á0÷ù4ÃùûÜèä4vÔ ùŽ¡½-™·~¿ŸÞÕÏy}þU3®»eÞø­ó®ß:÷†­so*š3±hΤms²¶ÍÎöΞâ=Ý;k†wVŽw֬♳‹gÎÝž3_[väܺ#gÁŽœ…;)fäíš±x׌%»¦ìž¾t÷ôe»§bÏ4Ïž©«ÔX½gêÚÛ¦¬»mÊúÛ¦l¸}ÊÆÛ§lº={óÙ[îÈÞzGÖ6Š;³¼wfß™µýά{³vîÍÚµ7k÷Þ¬=wM¦¸í®É·ß5ùŽ»&Ýy÷¤½wOºëîIwGc"EÉÝïQc_ÉÄ{K&ÞW2ñþ’ ?cqÏ„Ÿ«ñ‹{nú¥¿Ú_«ñ›hÜøŽßÆþXˆ…/ˆ¼/Å{c±O{nŒF‰wRÜ¥Æ^5îŒÅjÜ®Æmjì»ÕØ‹7EcÇM>ŠíjÇÂ+ĶX©±U-Ñ8°yBlRc£b±^uj¬Æ~Š5j¬¦˜UB¬TËj,W£Pe±XÚP¨±$ùj,ž¼X,ŠÆoÔøuÞ¤_åMúeÞdŠ_äMþùâÉ?‹Åý‹³îËϺ7?kŸ÷äg•,ɺ[·^ô;´Ì7.ŸF±aù´õ+¢±nÅ´µ+¦¯Y1}µ'«ÔX©†gåô+g,_9£Pe«f,휂U9KVåä¯ÊY¬FÞªœE«r®îÜÕ9 (Öäܺ&ǽ&ç–53o¦X;s¾óÔ˜»vÖœu³f¯›5K™ëf嬧˜M1cýìéfOÛ0{ªS6ÌÎÞ0;kã“7Ι¤ÆÄs&lœ{Óƹ7nœ{æþ¸>ó®Û4oüæyã6ϫƵ[æ]³%úïX5Æm¦—ëb&Eso,Š¦Š ”p¶EÎd5çDÃÛŸy¦ª1Í;‹¥ –…rŠgÎ,žÉrÑœh:Šf¤y±¤DqóŽhjrDzӂ9¹j‚¢XD±«?SåïšÎ’ËWjÊšN)‹by⚶rÏÔ•BúZË`ýIì¶hS#[HeÙEwd© Í{gˆ9Í0­‰™MLn,³í˜ÙÄ´&æ4–Íx*ÛK\ÑLeœ…,'¢½‘<iÒËEšt´Ý(y¦#ž‘Ô¤t`ËÀŒ¤IJ&%!/í—&šæ¥•ó’&5jSSüì´x@vÒ$¨_Å”>Gݟߟ¦î¥)1SQÜ¥ÆÞ‚¬;Õ¸£ ëvŠ¥Ù·-ÍÞ‹ÝjìZš½séŠK§lW£xÙo,¶©QT8•bkáÔ-jl.œº‰bùT–¸ús×rž» ÒË`!ƒ±$¶l@›Á’˜>-ZmœÊx6»eí·ÙL“ÐxN›©Ëi<­M‹¥5}f›Ël<¹EóÛ&ãüF‘™?> ô}Sþ][<@þ½8èÝÂ($™>_/ç}§[$§;Üwæën§ 2GŽú| ÓT>ú|þbFF½ÎÍ3ý@¿r_dh¤Å5+VDë{Þ ŸÏå¼™ 7<›¸Ç*¶™~æoy<I;­_µÏ.–ÞéZ*cÐÏ|[ÊìCy“èo³Ï ï¢D|þW ¿ áC‡†8¨£ø^ ý ö¿!b¡{Kï[o˜»¦Ir;øÍ¡jÍÓ[NdŸwïC‚Ù/Cn‰~àÄhÖÑ@Ó1öÎ"¶¦ 7vÅ]3ýÚ·Ñç#ˆ‡|:”åз1òbø_ O¸K1ô–ô ×L³hðx¿¦­‡ ö +7ü†AÇ·õ„Å_1ÿÍpÔ狳hª‘#&>_\bÉñQ£®RÍ$˜s>?"d`C±lx6c7,Ø–çGãóÙÇq (ÁìÙ¾ +âbø@">È«†?7¡Ùksîíé_qìâ¶_Óíü¡­«²{ŠŽ(’ÛÁËÇÿÅ÷é¾àÐu%Ùçk6ȬcoŸ?,ÛÝØÚ7ÜFtö°»ûÀç#ðù€Ï¤5\~ŸåßCåUdâwöQ.“éó»Ã}LÈпì±ü^åõ¡€³¢±óß G}>Á©Þ‚šù|6» E®ËåJš‘0±¦ß[‰8ïó¹ú3ÌÀfÍ +q Í$¥t¹Ì Òç3|>Ÿ¦žãv»%Ë$®Ï§)Mg ‡a³ôùC[5lyÎç…BÔb'ˆ7V³®ÓtÚÅ®ÞÃÁOŸ=üè÷~ðä^PrìËP¨>Þt©¡ãŠs•dŸ¸Afe ‰æ§oðúÚbàë°hÚ'ó>Uàóø|@ÀçÒ±T˜Õnñ·ÄÊ@IÕ½X,jïÃãéH2}>ÑÖ>ÙÜÅ«+»Ã}‡sðl+SÑØÉ~=|¾ ó?íP¥²²²$†ÏçKZ ñ†º1Éõض@­õûý|2¸&ßÞOÔø瑱jxwÒD«Y›ãªiãÝóŠì{rï™PÐ%¹Ü´19W‘|ŸÏaIÉDö'Íöœa°ÿ-¸Ýî$·Ð Ÿÿ¾{é ‚EÙ /8´~Ñ·1òbø™ [ÄgÃÙ÷Pú®§)hÔ—_*ŠDçâüHÒ}¾^~o»z:® >Êf,ãI6.Á(ÝÔô¥ï)i†ã[Lg(rxŒë¿B…Ú%7‚9+{’s£Ð糇;4~H|~òÿ«à„Ï|Øsßfè·ÖòÃF!)÷ùÇ›.I4ÎÉ殈ZÕ±«ƒ€få¦Üâ‚ÔÂwv|)Uš@`L<Œ18SR¹7û;ß•=¨Ur¬e̘Ëɹú|ö ‰¾ÁiØÅjÒ|>'0Tôf–^0d¾¦gRåó/võJLÎáóm# q¹\))èÖÀi&¤° ¡PHó|œÓYzÔå™ì;ÿ²ä.°p_‡ËÕœœkI¡ÏOm±âóYý›äÂçÀH" +ù|>úv™­âõzÍjÛDŸŸ™™©y´|4“rŸOøN·HdNw¸Ï¡Ïmmm­®®®«« ‡Ã˜ iÍèJæGX‰> eUUV¥xq~ò‹ºEè–*—ù.—‹MÑ`0èñxèNÝ?c[ƒÊÿ¡h—ÜÆοì]ûa2×Ô¨òùÌÒûý~ñE}ðÉ–ü Dø|ЗtúJßXC¡zCd8øüòú‰Ì©iëqès««««T:;;1ÒšQ;”g„•ècUZ‡eïÔ>köÿÙ7ûà6ª{ïëOÊ 3âþhfîTÓçÎô™¹£ççÂ-5}á5¡KH€„„n)ÜR¨!ô¦´æ¥o’JHÀ"“@J‚ LE0o /Â/ØØoLŒ¯C­ŒËŠ…õü¼':9ìJÇ+k­]IßÏ|ÇcÉ«ÝÕžõ9»Ÿýp8ì›gŸ}–-L£ {Ge6\:é”iIÿO¡¢«O¯Ì×ñ‚ÏÇãÔ² R‚Á Sÿõt]$>saXohÚ½ +ø|@Ä >¿óHZ"sZŽÏÓv™9Ìd29PÍÔmSêºNÿÂj é¬jÇžžüWÎ +µ;µ¾‹³3Dû]ŒÅ‹³¦æglÃYúw2’þå†1ÿÉ}¹ÝÊ#Wþù#Yqð)^ `JŸOôí{n8× ´ Út±'ðù€ˆ|~:+«ÏlêNÌߦS©´am€¦DSÑu]UÕH$"YÀï÷Ës0eËsSMŸbÏ t}ÒçË-¹S6?ëôE“¡³ïͽ®Ì·vÑçÓ1¡ÃeÇäÓbt0¹{/Ÿx<Λ2p{O—Š¢ð?Ñ/ŽçG£Qö4cÝ|> âŸO4÷ê¥321…–€Ê ºåbJßN%9w³´kay,ö™Ï÷^ã¾QIçÒ)ÓÑÕgæFb•ùâ.ú|>+ŠÂ\=;¢·WUÕï÷MÓœÝ:µ”üimÔq™ÏˆXç›Ì·ÏÿäËáø‘5œKJâx:l¤ÓœO)]_O·ýÓ„ôé=žO(S’3é3ÒŸÏ'F>Mö:6“FŒhcý R¾ìûÌÈ¡/û†Œ|>Þ7<þ1åÆ?ÿøpj&_¤>þWªw4Õ{„r´7q´W?Ú›<Ú36ÑóåDÏøDOj¢çhú£‰ôGéôG“鎥»§&»³“Ý_MvOgºs™®šJöð|um5v ê$“ÅÒ=“´½LHst¶¤º§g͸4_Ζ1IJ£Ï–„4GldT–¯(ÿbù¨p¾°—ÃÒŒHó?ö2,Íç³eÈFÍ–ÏÇ‚{%ÀÜ {ÛFGqü¾¸ºðˆÏo>*Q:ûOàÌ€ +`*W ÉR>pHà+ù€°¡Éï5<.éùoÚ®ûOÌíôWì»»èó™½b«ÏÏíó7^G"ëc:¨¹­šÝ©CMçfDß®à’ÖG eú|ñã‚< Þ?O=Ž-‚ Hí·K€¹aG#”„ƒ“Ö«úxºëóG&¦$V§¥?‰3æ›x<ÎÝ;s¹V‘+ÛCQ¾¼X†m¶{v·Kzþ³–O„ξ7÷v¨b_ßEŸo ÁŽ›Uq³§-Õ·ƒ§AÌÀqÏ¡3DòÀhVàó>AÏTðùót<Ýõù„Ú1*;éì4N~˜?"‘Ȭ2ß$ü øECN£L_2ÓÒŸlJ±¿Ê»ýo~gê·Ûö?ÛÙ921U™#àºÏ/HØè‡MK²÷C!gs°‰Šâs„J~ß9gø|ÏGAàóU„Éç7”uw}ÏÊûü‘‰©æ^Â\MëÁq‰ØéKfpòÀ<‡Mös“ù&)Ø›ôAMÓ¸À?Ö÷ÅaIŸÓö‘…k>g¿ÓèP™ƒà¢ÏgV21µëãAIŸ¿~ÃÃMÿü€ýÎëùç}>kõëjší‰©xžµ‚SCv0dS**ùeùqö‚Ïÿ÷+ÎùÞƒ×Ô@δæ¯39ËFþCÈ÷çjÊÙùü€òЉ4äseãÕ?4ò£!–ùÉÆйWQÎÛ¸ê|–¦U4­º°iÕEMW-Ü4“E›®ºxÓJŠòðL.yxåâGV^úÈÊ¥F.Û¼âòÍ+–ÍäÊ囯\±ùÊ•[®¼jËòУ˯~tù5.ûÙcË~þز뚗]ß¼ìÍWÜÐ|ÅÍWü*ry8rù-_¶æñËnÛºô×Û–®Û¶ôömKŸXrÇKî~òÒ?<¹øÏ-‹ïyê’û¶_¢nWØ®<´CiÚñÓGž¹øÑg.Žì\´mç–gnßµpçs=½pOô‚Öèßs~ÛÞóc{Ïko=÷­ÖŸ¼S[êß6Oÿì5v ê+ÏÙ+dO>»ó‰Zò\>»fòö³Bv²œ{"Ïäót>;òÙ~î[¦åé{n¨üü,}>;VŠ¢ˆoÒU BûFW8¼±ÔÒ%vAØ,¢2—Oš¦ÑOŒXž’&K:èóÿÏ/6¼ôk/çœòò×nó#!?¶ä'/ϹFÎrþ+ÇsÁ+·]øÊZ–‹(mk¶­]4“[)·ÝúÓ¶[#—´­YüêšK,yuÍÒ¬¹ìk.ÿÇš+bk–ÅnY»åÊØ-+b7¯ŒÝ|Õk7¯zíæ«_[};Õÿ¹oõµ¯Ïäº×Ã׿¾¡ò«ßøÕ¯Þ¸iõ7ÝüæMkÞ¼éÖ7o¼í­×½õËÛßþåoß¹¡ñîz熻ÿyÃÿù‹{öÿ×½ïþ×}ï^¯¾{ýƒï]¿ñýëþàç›?¸ö±øµxíþì©Žÿ|ºóšg»®ÙÝ}ÍóÝW¿ðQ襞U¯ö®Ú×{Õ¯|§Å{ý+>üäÊîO—|`ÙeƒÚ埼ì‹Áˇ–ŽZ2ùù¥_ /Î _RSß1_ÿó5v ê$Ÿ2rh&Ó,Ÿ-žÉ ‘ƒB´|Œò©‘OŒô³\:“>#éÒ“ÏG—~EéÒe¤ÓH‡Ä|0“,ËûFÞËç]!ûüsÉLÞ9‘©·¼eäM!oi7òº}Kgòš‘Ø×ó#¯iòŠ‘—¼4“c/]6“¿yÑÈ Bþ–O«‘ç…ì½,CÙcd·¨‘çŒìò¬‘3™¤<#äi#;.ŸÉv!Oi1ò¤'Œl3²UÌ“‰i>‘ôcF5²EÈf#y˜eÙñl2Ò´l‚²QÈCFþjäA!¹ßˆ:“£<ŒÜgä/È\òZø"ø|€SÐ-!ÝBì—‹>dbJ¬Õ¤wZú“½CËì?<Á~oîÕÑvP>4h²Q sªŠ¢Ì*ói=º®›>HC ÈlµÔoóùVƒ½’Þþw{?nkû½øÀ·2¸èó骆m—öA|“·Î¬‡zΰ§´Î +\8™¦XJÉχχχÏGàóáóáóáóáóÕ Ä~™¸èó µc”›¶¡½äº¾`è¯}É ™ÌdËÜz6›M¥R8 ª4e-5åáÇє•$‰PÿOÃe1EÌ«Äå2ßô,ÀÔ”ÔcóÞ»óHº¹S“ôöϼ¬5}p€ËÿŠ +}>këózǤô­‡º|èJ)°g:áp¸±8âã†9ŸŸŸŸÀçÃçÃçÃçÃçGÓ4º e7¤ûöq×ç·gƦ©;‘ûzž5-ýÉtvZ4Ben}`` Ë Nç@5ƒ¦DS‚y‚VŸ "‘ˆ¼)©Ç>1Ùê_ŸHºzÊkí‡øï}ÉLž¬»>¿º®«ªª( + Óô‹ƒ•ù­ÓW +tÍààqžó…|>|>|>|>ŸŸŸŸŸ¨%âñ8ľ}ÜõùÖzû¦î„Dò¤³ÓͽºSE›}}}L7¡¸ÚASÖ ===hJï`§2¿ Ì·6å®c¬ën~/þn׋’~þ/Ïõ· ¥ØïjÇh%¿¯7}þ¼ŸŸŸŸŸÀçÃçÃç#ðùï ûlF¹ã3Ö«w}>ÁÎþÃ9¡b¿`ú’™öá£bI9Œ á4¨vД5C"‘ ¦Æ¡p›2Ÿ³Ó”jÇ(ëºÛ_^ÛôÏ$ýü‡ï÷:øܶ$êÐçG"‘ÆR Cäàq†Ï‡Ï‡Ï‡ÏGàóáóáóáóáó  r±_çVßuŸ¢h³WÏ}½bßšÖƒãƒãÇøË‘‰)œÞà8eÊ|b¿}×;$|ã¾Ïµ¾Qñn%¿uú|W€Ï‡Ï‡Ï‡ÏGàóáóáóáóáóÀ&ž#ÅfÕ‹ë>¿óHš«›d&›ÎNKT«É7•ôp +]×mÊü`0hs|^Uã¾Ñ…kR’N~ÏîvêØùK*ùÝ=âói7f-›¯êKø|ø|ø|ø|>>>>>ìFM¦>ß]Ÿ/ +üÁñcôNKRb{F&¦xI?Óû¬P÷N{8¶ÿ]׃Á M™O Û\í»½¬Ó^rçxã¾QI¯uõóbþÖƒã>b®û|j2¿ßoçøÓ’Õ{fÂçÃçÃçÃç#ðùðùðùðùðù0+Lã¼M†Ïw×ççŸÌdé¥Xœi ýU,陘Âé "4ä‰3Ñlsöe> ¦š¦•°C;ý¿¹ûÁ³–ž¾hRÒ½?ÔúÁ´ñŒ`püuõ.ÎϹíómN‹€ÏÏÁçÃçÃçÃç#ðùðùðùðùðù€ÚE¢ñ@8ŽÇãu~ˆ¼àóÓÙéÁñcLæ#SáÓÒŸ¤eÔŽãžíÃGqž#‰Pgnïì¸w ÅGr™_ÚÐy ’kñN[çó^r縤{_ÿä»GÏEŸO '^ŸÐ¥K£§JèB¨¡h?<Îðùðùðùðù|>|>|>|>|>0 ñíãŸo¥©;!q>´@ÛPŠý>8~ ‘HÄ*äƒÁ ñKŸ-8bÚ”ù4àÒRt`}!¹î ŸoóI§LK:vÊ© ¾*]Í:‰‹>ŸÏŒP+{¬O*0/>>>>χχχχÏ4þð¦Ïo=(«áìKfh™Áñc#ShA@CݸÕäÓ;6K©iÜ´érƒÁ ®ë¦ÓØ*DFb¹_ð[«}¾O_4)éØoÚ®û|ô]&]<’.ú|¶Q:˜Þ®}ŸOgêóáóáóáóKn>>>>>Š_ÞôùGÒíÓ6”BÃ@îë +Z4ùVñnEÓ4^>7™Oã/_@Q”ÛاÄnÿ_>ßzŸ¯ûÚ-IIÇ~Öò ŸvÉ+³Â›fµ3™ÂYè)&EUUv}åHe¾é8ÃçÃçÃçÃç#ðùðùðùðùðù€º‚nBÃá°µ(¿$¼éóÓÙi‰öiêN á ÷u í—OÓ >·/óiåk _ +¹ûåŒÏ·þÔG%½:å¤S¦ƒßz'—Ñ=r0+¼iö`%zð£¦g»§–nÎåÇ>>>>χχχχÏÔš¦Aã;ˆ7}>ÑÜ«KÌO2“-‰D¢§§g`` ›Ízê»4e=7eWWš²$TU¥ž¼¤ÒnÞóÛF«Ì§wÄØú5åÏ·Åù[ÏZ>!éÒWnóùr‘ëB¹‘˜‹GÒEŸOXtŽƒ ++vX4'fPØñù´!É)í Ïÿ÷+ÎùÞƒ×Ô@δæ¯39ËFþCÈ÷çjÊÙùü€òЉ4äseãÕ?4ò£!–ùÉÆйWQÎÛ¸ê|–¦U4­º°iÕEMW-Ü4“E›®ºxÓJŠòðL.yxåâGV^úÈÊ¥F.Û¼âòÍ+–ÍäÊ囯\±ùÊ•[®¼jËòУ˯~tù5.ûÙcË~þز뚗]ß¼ìÍWÜÐ|ÅÍWü*ry8rù-_¶æñËnÛºô×Û–®Û¶ôömKŸXrÇKî~òÒ?<¹øÏ-‹ïyê’û¶_¢nWØ®<´CiÚñÓGž¹øÑg.Žì\´mç–gnßµpçs=½pOô‚Öèßs~ÛÞóc{Ïko=÷­ÖŸ¼S[êß6O]G¨úÊóFö +Ù“Ïî|¢–<—Ï®™¼ý¬,çžÈ3ù<ÏŽ|¶Ÿû–)Oia9o&OyBȶãy“gk>çɧù|s3ò¨-ùl¶ä‘|6²IH“‘…ò‘¿žÈyÀ’û…¨F6äsŸ%¹àDÖ¹WÈ=Fþ|<í<ÊçBþ`ä÷–Ü=“×Yî2r§;X.<žF!¿3ò[!·ù%ëX.šÉùõEûXn³d­[¬rËL^s³‘Õù„‘Ò²yE|> |¬ß‘ãé5Ÿß>,+æì<’.===]©T +gBUƒ¦DS›Äb±‚Ä‹ +…¬+áÛ’eXSþô§O>ÿ͵­ I—~ú¢Iÿɺþx nëósùý‚Ó 8X¢/ñùš¦ÑgŽÐKëã$}>‚ ¨÷ÏS¿c‹ R{Áý`n˜|¾¢(åáH±Y O¯ùüÁñcù³ëÀ˜›dæ0“Éà?«ªASÖ ÔŽ===hÊX,fÕ˜å@k ‡Ã¾R å ®G”ùÅÆÖ” <äó­?uA»¤?oÜ7êóåBgGro‡\?æ.ú|:°t0y•‚üÒ¥¤éŽÀöÍ‘KºîbßÂ:­ƒþD_ŸÞ× Ø´ëFáó>AÏTÖúü2©üM±7§×|>¡vŒó?ô'G6‘J¥  k4emÍfë¹)u]F£¼>™~:¥ôK-˧M[]+ƒv/ ‹í!kÊo|Åç[ú¢$>Éã>_.ºZÉÄÜ=þîúü\)W8´d…÷?¸T0QŠ¢ÐvM¥ðùŸ ‚Àçªøüy:žôù»ŒIÐàø1ü;jMÓTUeõÏŽP´rfDí ãñxÁµE";2_$´tÓÊ Ý’Îü» ™ÀiZn·ûwîú|qÖƒ×|>o÷P¨Òs(ØUŠé>AàóAø|@A7• ŽRÌZÔ ^öùGÒÔ6”¿ zÑu=KÊæm +sÉú©‡g¥þöQE²QîuíÎÈèÓÖ5î+:ÙŠþäóåÂ竹^ÕõqÑ竪*¶;R*VŠ@gd›µ1Сp¼>¨^¼ì󓙬Äç7÷êh>@õR° ŸëÜ2Ÿ5ÏÁäª 5JËØÙ½‘‰©]Æz¥û» »%=ùÊ c'2ý‡è‡ô{ûðQw[ÄEŸÏŠó©É¢Ñ¨NÂbgfå…Ž‰u»ðùê¯ùüd&ÛÔP;Fû’zÙÜ«KDP:;T)&ß®(Šªª¦:ä9‰D$5ÿÅ q¶ä{×±|þç’nüêköÞ|ÛÓü¥»-â¢Ïg¥¹ÂÛµïóËœ-27Ø%Šõ|>€ºÅk>¿}ø¨X~ß6”’ˆ Î#iþÁd&KAƒª…H$Bo(rª${n&Ÿ=Jp\Õª£’Þ›'Ñôo-oìöȬ+×}¾³Tì0«Ïƒž¢%A¥ ­[ÿŸ nñšÏïKf¸çIf²âKkZŽ›>Ūú ~Ðuzò¹™|¿ß?ªvdbÊŽÌß²7–|æßøËý‡'Ü=’.ú|æÕ]ÑæÞ$ÓÉYlR|>‹ÅÂápƒ¢(š¦9¾¯ùütvÚT~/qAjÇ(ûTK’½³ëÀÎ@@ƒB(òûý¾9ACŒãeùŒý‡'ìøü—žòÝö?ñ—Ôÿ»{<]ôù‘HÄ;±ëÈe~>PÓPHãÑ< Ð`Î4Ðý{Á¿Òõ+Õ³Bï;kõ½æós9O?%:hdb*÷uw”Ìdq‚j›h4ª(Šo®X,æünˆäzÕ\F—÷ÛdbJ4<âKkZú“ìS¦ª~; t¤Óiœ“U šMYÛP‡¯ªªX³77Eqv†× 2zn§Ÿùü‘¿/´Sœÿôs¯· ¥ØïjǨŽ³‹>¿Ø¤¼bØ1ðö·kgmlI:…\9¦=„ÏÔl––”èx„b +=‰ð‹7Õr‹‹Å¸ÕwêžÚƒ>ŸhêN0ÉÓ6”_L:;³TõÛ¡¯¯™CW;hÊš¡§§§š’n½©kUËÖŒñxÜô0wÎPo§¢;Ò’4¾”lxq~‹ïÝ®íøü×^ý˜—ñ·÷BÃÁçϺ¤G.àóµG±À© Y LŠ)tEQŠÉ|†®ëÜí8R­áMŸßzpœIž¦î„ø²`ú’Z&™ÉšÞ™•±±±¡¡!œÕš²fH$Ô”ÃÃÃÕûâñ8/¤Ÿ›Ò§;÷p8\~5>ƒ† ›*€6:G]lçGWÿoÿÉwN[wß«‡ìøü—^îá¿LLy¡í\ôù‘H¤±œÒ;6}>?2ðù0Oˆ£°È|M¬%Rì¾Øï÷Óû@@òÙh4ê`µ†7}~_2Ã=O2“_Zà ;MUýPaâñ8ëÆKõùº®G"‘P($~¼Lh(¡uÚÙº¦i¦Y4ДðµßçZ|ÓÖù|ë)û>ŸUæ¯ß½÷sñ¹­pÑçW:+ò𫎆âˆç†ê yŸ¨=h,¶^85#”O1…ÎއÒÏêº>—úÉ"xÓ秳Ó\ûtI‹/­á.¨m(å5;¨"‘ˆx'Nꬳ¨èæ]UUV#í ´B›&?g<#w›~·ÿÙRZ®Å¹î &ómúügZ»G&¦ÔŽQÖÉ{¤ëÄç‹_³$èÜpdb`ùÀçjêŸÅÙy¡PÈ#½.ÈÍæógõ5ïó‰]Ƙö™˜¢—-ýI‰Jf²9KU?N3@ňD"¢ù¤{ðY—ïÙ‚¶[ÒÔ­p8,~< ÆãñÒ¾y[ƒXœOùæw[¹¡{mkBÒi¿Öþ…±N|~.?°$EÑ4Í#ûŸ¨ah ¦ñ&ÀkSèlV;êóƒãǸ–o>*QCûO°Åø;ôYœf€Ê`’ùòΙnÒYWï ~¿? +•¤[­»1—:ÀCÑ\‹O]ù}.óóy±qßh±›þt$®y®=ãói7è2€ÏÚô»ªªº&‹ø9À£äG<ó|>€ +SL¡³RIºy—|–‹£h4ZþžxÙç‹ŒLLI|~s¯ÎcÚŸ^¦³Ó8ÍÀTâN]t±%u]…BΚü`0H[,Õôjšfz Ùm»ú–oøO¾Ëäó¿}F\Òc¯Ü0VÊ‚ÊáºÏ§vä¿àSÕiwÍ6çHy@%Ï€*BÓ´˜£¸2™‘ß›‡ÃaºæõoôíèMúS±{vÚÛ@ À>^R)f1ªÅçjǨDñJ~¨¼ UæS¯ÎºwG €†9¢¸ƒs/Ànñ…ξÜRœ¿~ášÏ%Ýõé‹&ÝxK;,•ß:ïvÎP(äàFÙD€9>Íqø|¨"Lò¤|bn” J ¿·–ßÓ;Á`ÐYý^E>¿õà¸Dµ ¥ðߨ0¼šZRâN£ ïºË„¶ +…ʶt]W…Fœ2 ³ãÛ~a•ù>ß曶ë’îúœ ¿òfkºëóÅs‰ÚE|ÈB;&Îì¨:ýî8ðùPEԆϧoA÷æüæ½ &ÍbZxîå”EŽ§÷}~_2#DMÝ üw*L4õ듳 Ö‡¼®ÓаÃêóO]Ð*é«oÚ®—÷ aqÑçG"¶]EQŠM¤sŒ=ñ§ŸuþŸ¨a¨·wk +9À_„®Öhè^ž¾ÝÈso/ñùÖæU‘Ï'ÔŽQ‰&™˜Â?À#°ør†§`0‡zzë8±Øg…Šóן¾è=IG½pMÊíQWò\óù¬ü>ÈßÃùx¸C+o”Bg£G¦ÀçjêÛi à#õº°ú¨yølt¿ßO×?tgªiÿ+ýN×Hô>+oóøŒuºxw>—÷ùôÓÙÕåóÛ†RMD-im‰D¢§§g`` ›ÍâߧªAS¢)½F<ƒsÓøÔ«ªj<ˆ¦% úü•I:êoŸq̳ßÈEŸÏŽËöˆ.fÜ:] ðK#9Þ˜\Ÿ¨=èÊÁÚë:ÛÛx ºÚá&D^É@åæßËJß]ãÍG…Fuùü‘‰)‰&jêN”´¶žžž.ƒT*åýïДhÊj!Ú´£Zž&ú`uUâÅbŸ56¾Xp¯èó÷HER/×|¾ý ƒlÔvpÈæWDv@}>ÌÅzc”è VÑ4]ðƒA›×<ü’Éû5óJuù|¢©;!Qú#SöW588ÈÌa&“Á?QUƒ¦¬¨{zzª·)y§jßä;åHiøSU•:óJ–óÅZ_eþ7¿ó˜¤‹^¹aÌËòµ}>{lÓ@€ÖL;Àæ•Ð‰ËÃfÐOï8%ø|@íÁæb[qvj6€wàþ$ÚüÝ–²„B!º*òùmC)‰,¢¿–´¶T*\ )kƒl6[½MIÃJ±›ñb„ÃaG©¦i4–‰“*vûÿƒÿ÷gÑ矵üo’.úôE“ñ¸w[ÐEŸÏÎ;b˜owê‘ Ûn àç!{Çtþ°K…J>'’Ÿ¨=ødsu^{€†+”9|Šnc]Üsºe…B´\ªÏZ¨É ¼#;Pu>dbJ"‹šºøwT]×™hµ u¹q'Ôv4-ø!^on*Χ¬Ü𾤋>ó’ÉÁñcžmD}>‹ý~¿ÜÛðrzûÕ rØ3 UPâ¬ßú<ˆ]¨Ä½ñ<>P{Pÿ/>—gPŸŒ#€Z¥Ÿ_ùÛvN±2Œ`0(¹e®sŸO4u'$¾¨/‰"m@E¡›?–º[Ÿõ¹­-ÒRp£Ô™W¾8ÿ¤S8}Q”"éœç<‘ªb¸èó5Mã§G±æSU•-#–Ó—‰u6»* Ÿ¦%Ù‹GJôáó5 õÆâÈ +…œêí<7ó%UŽñw÷¹˜ð)výV‡>?™É6u'ÔŽQæêÛ†RSÔzpÿ€òá–^®ßi1kA]1‚Á`ù÷æÑh´à¨A7þòêng‰<ôKKÒ›-î¢ÏÏ Ã1+ÈTU5–‡þ$§Šós…|>›`½$`»ç‘Kø|@ C×Ô-Ãä æáwÁ¡PÈæGøm{0¬ü³ûe.Òé%íÝ¡Óþ‹ïË¿¬³‡ÎË>¿}ø(³@ͽ:½™˜’˜"µc”0™ÉRð(S/]l±’d¾ýJŽ8R°jmêÉç÷Æ?¥ÍD@×'ýþ¹Ï_ÛªÙ÷ùÔ¥{³ÑÝõùÖ–-Hù“;DXi¸N:‘ +H°%áó8Ýu–t«+ë¤ò + ‹ím,ãû¦ºK­CŸßy$ÍEóóͽºD±2~ú)¾›˜´j±a"Ú—ùjX¶]Vï`©vQDr-¾™:±­;nmá2ÿÔ›ìË|ÊÈÄ”7ÛÝuŸÏW,Å7=¸q¼¹Ãá°õIS÷t‚±º}]×ù¥-ï…–‚Ï€€Ý~òHMÓ +.ÆnK¹¡_\™Ì(WètÃ.Ù½:ôùéì4AGÒôÎþÃYÔzpŸhéO2´ëÀ½Lf²³ú"kU?HˆÇãâ0á÷û‹•CÛ—ùÔµÚyj¬išjàÊ#æ¢dôÜ Áã2Ÿ2co7œõ°èóWnxß¾ÏgÏ[½‰w|~%¡Ë :ñL¢¾àîà“2Ï€Ú@×uEQ¼_0Éäi}>‰À´ŸõéóyA>¯ílîÕ%ʨ/™±Võ@1¨Cæ½.Šüyë¬XÈš MÐÚh[ö?RQÞçZ|ñ?.PÎ….¸M×'é½è“/‹2Ÿb_æ{¼7vÑç³R|:j ºå¤›b¹É…B.Ö@Úñù9¡:ÎdÚëÓçLL‰®>'~I (wþ¬ªßD6›M¥Rø¯©vДhÊ2‰F£¦é]ÅÆ>‘ùš¦ªEñJcˆäZ|ú–oN[Ǽ½ª¾§ë“÷Š2ÿ» O—äóÓÙiÏž~.úüªˆ½|> &¡kºx`RéR¤Ø$A€Z….‡"‘H8nhll¤ë"M>ß7vç>k%]ȱ%Å˹úôùDSw‚é ¶¡×—Ìd%ÊHíMg§Eço]áÀÀ@—A:êýêM‰¦,Q­óð4vÈ‹¨Å#­‡w¼V™ïÖÄ13‰x®ÅGQÎqu‰tݱîSqþÂ5ûìËüæ^Ý˧Ÿ‹>ŸÍ.ôûýè쟨=ÄÙÙv.'@… ìÎ]þp»Z’KžºõùmC)f„šºì^~_0GÒ¢ógUý"}}}Ì¢®»ÚASÖ ===®4%ï ‹Ý8S_Í°ÎJ$)¶!êÕYÿoš2æ…gÍ'HÄs;ý¹_äº3¸·ohØ¡õ šd>em«fßç·õòéç¢Ï§!žm—NEwý 4x¹¥àóµG8.8¯GÀ#pw éöY²$¿´ãJ¿n}~_2Ã¥P2“¥wÄò{kZŽç„ª~öRdlll```hh'dµƒ¦¬‰5åððpå7M¬¦iÅþd-™›ƒÌ'Lë¡ÞCŸ‘Ñs»¹_ü ü'ߍ½ßÿ ¦%• #&™ê‚Möe>edbÊ˧Ÿ‹>Ÿ 3‡tV;ç 6gÄtršˆF£Þ)…ÏÔÅæÊojvãI7§Š¢4pÁB¿ðBww÷P¼qƒ¡P¨`9œ©(4dPŸ>ŸàRhÿá z)–ß[£vŒæ„ª~öJ¾̧Åh葯¯Šº\/ FèUs->}Ë7§­ãÞ>ý$Öúºµ8ÿÛgeáš}×né—ôÃk[ M¯ŠævÑç+Ë,FÁ€9@\æ³Çü ÜC”èÃçjq ‹¾pdPÛHª(M>Ÿ¹× +{ú î³dIú +¦oçÈ>T—Ï'Çq™Oì?P“ð>™Pœ€ÚF×uQwÓpÃï|M~F¼uÚ º~›õöœ¾c$¡¯ÀÊõÙtÕù|ÉLVâ‘š{uZ¦óHš~oêNÐÂøOÌ +u¶öý*uÈ´|Í|wU}‹ú`p«®OF6·Kd>åÇ×i’~ø–û&«å»»èóãñx¬œšcÈÎsÓåGÁ#À®¿T /N6lÒŠ}mŸ¨U¨{gw…ÑhG5õbá=¿7ïUéMnþ@·j÷ù9¡ü¾`àð%Çih°)ó©ç¬%™Ÿ›Þd–ÞïPÓ’Zß ÿ令>óµ[’’Nxõº¯ªå»»èóÝ‚]™Dze|¾¦iÖ§f6? ŸÕÝr™/Þ–ôù¹¯ósù_«Ð—eeawÓ+V¬X´h‘d%Ùlvtt4•JÉ·E Ðb´p%Wõü'£•Ôy$íÊ^aUXVå‘UE£Ñ‚unWE#‚8ÕKN(ª½Ã·Rè—\F§_äÅù>ß‹’xmkÂ4ÆzùXµµµÕ›Ï/øe ¾‡ôùtÙÆÿÑèZm0´¿ò2}þ³;wÒ§ayçíw橇Á±E©½ÔÉE2 2¨ªZÐÛóù9CÚ°?)ŠRÛÇZÿf¥«««££C²’.ƒt:]l™T*Å–¬äª^éøDb“žüè°+{…UaUX•VÅ$¤ÕO\Ÿ¯dZsÍö;Ö½0›Ì_ÿ|@Ò/¹s\Óæå ҟ쬊þjU[·n­7ŸÏ®ìÔçƒAñ´/>§’®Áø ûS]ÊôùâÇy@½žz[AÚK\$*ݲCÓ=©ÄççòÓÌï‘ìÔšvuu HVÒÓÓÃt‡¤Êqtt”-SùUýåƒ/$BÉ­½Âª°*¬ÊÅU½õÖ[gžy¦ØÑIV¥ë:Œv'v% ;{Õ××7ëôÔªb/uÎ*óC¡/½í¨¤û½ôÆ´g¿ uUÍÍÍõæóÙ/>Ó„a=üjÊ‘)ôïÆ+óí;|ø|ÏGAàóÕ/A7½/÷ùÅ>åeâñxC›¡»ï†â:ÍÍÍkÖ¬‘¬$‘H I–Éf³ƒƒƒ´˜D›ÌÓªv“¥}½]Ù+¬ +«ÂªÜZÕž={N9åîfý~¿ÉCŠ«ÒuÕÛVF­«¢-.X°@RÀìñÃNË‹ïëúd`Á½r™ nU”îk·$%Ýïêu_Ü«±±±9ìÕ|¯jïÞ½®û|:QEaC³„‚W5s@Ó4¶BU°â¦#@ÿŸ}³’¢¼÷ýþ­JÝηêƪS™:§NYÇœh+˜_`xµ£øÆ‹´ ¢Øˆb≎c£¶r_0Û®q±MÜ@<‡ã\B¼$\“,îÞÅ°Í!ìÉ:=›v˜0÷7ýì>ôÎKOÏìÌÎtÏ÷S¿¢všž~yúy~Ïô§ÍŽ§lýžÿmVö ’ðù|>@ àó~§q|>?£J6µ Ûš÷uÈþφ\„RÛá¼ßŠÅbÝÝÝ.žø\J\J'ªª:Íg(ÊzuË w•^E1ï¦h¡óM¨\é:­hq¾®ÚÔô‘Kî]Ó{î¹>ÊŠÏ°%QRW¬”ÏO”賟š¦qÃωvÄûv¥vÊx”½Á +úü '|ù¢_ F|yÆå—L¿ü²é—_>íò¯M›ø©¯š2aÒ” áð„©á˦O¾lÆäË®™té¬I—^7éÒ믾töÕâ W‹7^%Þt•(]%~ó*ñæ«.¹ùÊKn‰9vÜÊãŠKn·ÇÅUˆÌöoµ€ Û7íã¼ÉŽ탟}uæDèt®µÏ‹Înæ¤Ké4§Ä´ðetîS™F˜l·ÆÕS&P³\9eÂS3MDñõ©©¹¾:m"µÅÄé—O°›±h\ê9Doq‰·¸Ø[|Å[üëôË7¼ùZ•ÒšÿÇTV\^øW/1Ý-¾Rz\ì9¼ôÉ¢}»èqh +ÇDgL;——™±Ÿ_ã1u8¾žßÈWŒŽ+1…"“²âêÑ1itLæÎDxtL9”è2éÎÓx8²bnÌpÄÌáÈäÒk1Ë×:â:v6æ1{8D6Ñ°¸‘ÇH&¿id’F¦!7çLI·äLOÎjôÄtq=Ÿ+³çPgÜz…c¶uœàœ-iœ‘¶â ˜™GæG{Š¯Ï™%3¥}­³fIê]|Šdó#u{63ÒøºøÊKàóUB–evoH÷¡Îåî>Ÿ×›ùèLáóó2”:ëâ”6ˆåýVGGG»{ý*¨p)q)9|:àÀ.ź®;=¼;…6•%ó Õç×û#é]R:fúíµÝEe¾ª~LñßvɽsÖ|ðA—Fe }>u-ï]±²>?wÔä…Ö©ÔîêÊç_zÿìðß +FÌØñè7ùÈ‚_¬^¦¯ZýŽòøÛ+ŸÞ|¿Úºâ•Ÿ,×Z–ýT[º­ùÞ÷__òÁ¦{>|uñîWýöå»?Þx÷7È^ZØùï ®¿ëÐú»¿¸àÈ‹ó½0ÿ¸:ÿ„:¿WÿWu^ßóó>{~žõÅÜøssûŸ›û·g‡c w&ì8Y¹ ÍÒ¾h¿t~aþ‘t¯_@GHÇIG»oƒüûòï^¾ûÿ¼²èׯ,Š¾ºhçk‹µéž_¾¾äç?^ònó’·›ïݬ-}ëeo´,ûñ›Ë^ýÉò oÝ·þ­û¨5žÝ¼â›ïjËkö5Ñco¯|tëƒÔ\Ê6åþwW-×W-yï¡Eï=´ðç«yÜÅâ«dâaŠù£cžsߎ;sâ;n‰ÛFÇ­#1§â‘[râf;¾IñËLH£bÍM#q#Åö57äÄ쑸>^7:®Ýþè[ÿ³J™mÊxuþ)Œ_‹©Ùñ(ibº{ìÈÄŒÑ1st\S(¶?:Ë×:âº|q}&ØE?ײ»ë6vðŽ4ªƒ±Ž7Ò oÎêœï?2‡ú­£;;6ëí¬ó;‡ÃÜ_d‚ç8ZðóÕ F†›sÊï­¾ÛŽEöØd±ø½‡î±cÉHÜ«¯¢Xª¯Z64œ—¿»ê>;VŒÄýÛV=°mÕÊ‘xp›BAÃÕH<ôŽ²:>lÇ#ï<¸fk&µã[[W~ëí•ß¶SÅ¿Ùñ·W>nÇo¯Œü,Of"“dÖmyà»#ñÔæ¾·ùþ§íøþæû)ýÐŽg6¯xæ§+~ôÓÏÚñ\ëŠç[W¨v¼ÐºâÅ·V¬ÏÄ}ÿþÖ}/½uß;6¾ußË?YþŠ¯¾¹üµ7—ozsÅë-Ëší œOٯŎ7[–ýäeo½A)qi«¶t³[´¥?k¾÷m;¶6ß»-™ä©ÿxÉ{?Î$Ò_¼¾ä};Ú^_²}Å=;6ÝCi–fÿØ´ø?_[LY÷¿^[L³ eàÿýê¢]v6¦øÍ+‹>²c=ËP¢Þ»ñîÿ›‰LÞþÃÙØ Ó¼³oÃÂý¶¿”I韼´°ãß3ÓÐÿ³g"Š?Ùó¥}óÅ4+õÐÄôÂü£/d¦š›øôôßê|š&(bö •™žì‰©²óQI‘pÄÀpd&Ê¿9‚²ßžL)¬áÈœÂgö¹PüõùyÿmŸ`¯}¦ì”ÿl·µCÝ&Ô8ÔDŸÚÍEM×a·$5é7,¤F¦§–ßc_>KÒµ£ëH×”.ñ;Í÷nÉÌ’K©Ÿ¼þæ2êH/ÙS$õCêŸÔ©WS·§A£†Æ—ôÜ]ðù€*¡iZÞ{CŸÏ+Ðüå±é°##TdƒÁðùDs§å¢•N žÉýJOO3‡ÉdƒÈ×àR†îînºŽå]Ê,-éž'ùÄá…B–>ë‰@gUHZéátkS&ÞËÿkÜøÍïŠÊüpxK:£ O-^û.‰÷†e+ûRÖ„ú|>Sw¢¿³ŠÆêÉ…Þ CRKwæ…;’þà?i¨ñ½o>>>>>>>>>>àwxaýk_îâóùí$Ý]6rÓÆçï>~ÒE+ííÌû­D" p)ƒA*•*ûR:ý<ÍîzÐKA2ßT¡i"ë‰@½Ëü˜‘qøLæSlsW1Œ^AXï.óiË:•YûD´õ7ï¹$^å™ÄßOù¨ûÕÐçó¿a*m–fù¢/P ЯI’Â6´¾®ë.o¸” +ÿé5Æ7àóáóáóáóáóáóáóáóáóáóÀYÛÆ5N^Ÿoš&¿£¤;h´[0|þ‰Á3.Z©¹Ó Øp»î.Ei +EÑ»Ì/´©,™_Ô”Ö˜C7ùÖ¦óoº4£÷GcY§Ä~²hq~4z„òmÏÀéôþˆKÖõcϯö#!UUiûÔó³–S÷¦³·×h˜Ð þ"ý¡¤â +ø|ø|ø|ø|ø|ø|ø|ø|ø|ø|@0pÖ}I’¤Úð{d^uæ40%½ßH|íó·êÿþþÚz0Î>n<sÑJC©³#Êù”Ó\䤮ëìe./ˆ¢X¨29«¼¿ÞßóÚ#s™¯-È´|$òѨu’–(¶•ùŠòaW<É]}QŸOá£þSCŸÏºeI5ê%Áæú܉žýpªÞ~]f,û…χχχχχχχχχÏ˲²t½{Õe:…èhª½G_û|âIúØvxÀÅ)íÿlˆ}k(u¶gàt<™Â q ìª(J“gdY.$ó ÃðÌOZéí"—ùʬ¹™‡·8W”çþ´¨ÌÅ–ôȃTú|°_/Õ{˃•7侓ŸŸŸŸŸŸŸŸŸŸŸ¨9š¦ñW¹ A7°†aÔÉÓ‘°7Ð]=°× \ŠNËÆ×>Ÿä· ¼j4o°uø·Ô}}¨Ø A 4+Š¢w™ï®U)óä\×/yÅŒôV™|kÓyáYæ”óšÖÎW|ò‘Ö¢2_ÖF/­LÉÓ»Ïßy,á£~RCŸÏvM¿^ +=EûજËáóáóáóáóáóáóáóáóáóáóáóu‚®ëtÓš%pè¾UQ”ú1ù¦iºhüB%£•µú¾öù;%˜2R÷õ¥íÂ{­ÄÖI;ªúyÅ> Àhš&‚÷4ë¥Þ>Rò¬Æ3ÖJ²Kb2ßxú‚Ðÿ|ÌiæuýSGû´•ùì+îMsƒ½<åjèó öþH–o¯ ü÷ ÚKĆÕ?ÐE¼Q‘XðùðùðùðùðùðùðùðùðùðùàG Ã(I19Ëõ+øHÂ×>ÿÄà™,k´íP¿‹Yê8Më4wZYû€ ÂiM²kíÙI·6iK' +ç¯ãZ^[X™=Ãøð/2ŸóSÚ,Éçûë5¨qðù–eE Ô»(Šš¦E])ãYRÙ¿:œT¤’>>>>>>>>>>|݉;o«%Ibeo¹*‰Ö¤åªªÒ:ÕN¾öùÄÆ1§œßÛ;èb–vKÐ:»ŸÌªØ˲JzJÅ@É|›ï|©å%I·¬Sü?pªþB!Ë;øW(mz—ùÍ–¿šk|¾sãïÕé…,Ëðùðùðùðùðùðùðùðùðùðùðù€šcFØFÓ4_¡5ÙWj"pø µ$IÞ«ì,ËâV¿RúÝï>籄SÎÇ“©¢rÉYÕÏ*öƒ{(òn))µR‚ X#(ʇN-‰|äü_Mk÷"ó%Iç_éŠ'K*ÎgP}Dà}>ƒ½#±aÄ~D¼A_{#ÀçÃçÃçÃçÃçÃçÃçÃçÃçÃç¿Aö~o8öÛɱÀŠóEQ,㻼â´"O"üîór¾+ž¤%Í–‹_Š'SiG‰éûŸö%>3N —T*ÕׇKðKÉ^VòòTÓ4ç PEQK÷¾ ÞÂœ¼ ¬×õOG7Q{Q“O!Š-¬žß0zé¶Ã%ùüß™'ü5*ÇÁçóòƒ1â½z¡X' ÿ!ø|ø|ø|ø|ø|ø|ø|ø|ø|ø|(Ãçó +ùñ÷ùt;Ïv]Þý8ÿzE”ß}>±ñ@Œ¹£¶ÃiGÅ~ÞØÛ;Hëp+µÁøK{{ûÐБ¯éîîn·Á¥ ê¥Ôu)zú×} <§y! +Õä­ñ!S/¬ÅÃèÍZîEæÓw™Ì—åì#ê1þÐþ‰¿Få8øüzCQ” +>ð|>|>|>|>|>|>|>|>|>|> ᯊ3¸œ÷øÎ8ÝÀVä¥õ²žíºì÷Ö+xäðù\à«ûúècÏÀi¿ÔÜiÑ:û?:gø÷w ®Ûïtuu1 ŒKéw:::r/¥3c»ˆV˲$Iò.óiâ ¯4Z {—ùì)€ª~Ì–\þYI2Ÿ=-õרl@Ÿ_àóáóáóáóáóáóáóáóáóáó HI˜îèº>ÎÏAy»¶, >ßɉÁ3Ü õ œ¦%îE¤ñdj(u–üõ¡¿`@ùþþþîîîcÇŽ¡)üN,£KyüøqöÑ4MQ³$|Þ/RbÌZÓA\ +’)+R>ÿ©að(ó)týÓtæu°^AXÏ–\9÷—^4þ÷ÚºYþøÈ_—ÒÀçðùðùðùðùðùðùðùðùðùðù€¤R>¿&› yI’Êøº¦i|ŸOl;ÔÏkÃ.ºioï ­Óz0Î>Òw1 ¨C(Å ‚àE—$óiMÃ0 +픿í<£ûäcÛ=Ê|Mkg_žpËc×µ}ztÃÞøœµn öÍöoÕÐçSߦž©SÓ¦iR …B¾~µ>>>>>>>>>>ЀÐoØ79t“ö†$I.õ™Õ†°Zâ}¨a\pUäv>>?‹®xÒE71í¿·w}l=Ç€ ÞPÅ£„/IæS¢+”9³¶C™¶®(i¥wI™H˜E×µ¬S’¤—*óey_¨Ìº1ÝÚ”>U”ô’Mq—»cû_ýÛëjèóé7‰Ëë'NèwNM^-¬ uåó/šñÕK˜¸bö˯/¿næÒY×/™%Ý3sÎâ™w.š¹àîwËÓïY8mÙ]ÓV,˜ºrÁTeþ”Õó¦<2/üè¼ð·çNþ·¹“¿sòwN~òŽÉkîŽÉOÝ>ù{·O¢xúöIß¿-?¸mÒ3qõ3,n½úGŽx¶ÒAÛ¤}Ñ~鞺}ÛöAÒÑ>6wò·æ…×Ì Ó)Љ¬š?…ΈÎëþSï»kêò»¦-]8mÉÂé‹åé‹äéòÝÓïº{ÆüE3æ-šA­qû¢™·.δÌÍ÷̤&ºqÉ57,¹æú%×\{ï¬kî5séµ3–^;uÙµSf±œÅu“½Å¤œ¸:'®Ê×_™W8ã¾ë¿‘/¾î!¾–‰ÙYñÕûfoúek•{™Ërc…טPJL,%./öÅÊ_+™‹þuo‘·_}#«ûåtÎ|}xT'Ïn£†µÑbª#¦9bº#f,=3³ƒ†ö¬k–fÆ8Ŭ‘¸Ö×%O;®™=7äÄ#qÓ=,2É„Å7G‚2ÌÍ‹gÞ2sFe¡[eâ6;n‰;ì¸s$æÚ1/3xP6›÷ŒvÜeÇÂáȤ;Yž~·‹±ØŽ{2A&–dbÚ½vP¶\zWfv X~.2¹ô¾SWØA©õ;VÚñ …uyP~h^&VÛñ°ØYz=Ñð Ôým{ÞyÌÊçß±ƒæ 6 ±ˆØó›’جô];ì¹éÜôÄf¨ ÏPÃÓS5¦¤²'²¼Aè3#GûÃá>‹Ü6<ç²³ûž#èÜY#¬³Û„µOd¤Å¨õ¾c·ç·íùñÑ‘)òaûº(ŽYr…=KÒå¦>°xáð,I}‰O‘l~¤ŽM]ýºÌ´8‹Æ×·M†ÏT ~^ö½á8CwâN¿¤iZQ9o†³pTQ”ŠI }>¡îës1Nñdj(u¶õ`|ãXW<‰@ýëç)õÊ”™Þô‚KÚ4M3Kæ»Ôðמ„™Þ.f;Åž"Ø0zeöe~$ò_(~i•µé¼ôVöû¿þá¬Kjìê«ÐÔTjèóY7öRfÀ~ øå×N^êÊç#ˆÕª4ØѶ¼ðño}@ýá;ŸŸ¹%Ï*@ ‡Ã‘ÑÐj´×äó5+RœŸ®Ïo;<à"ööbÔPŸð¤Ä¼º‹át¾¯äNIÛqy .ˆµÎd>Åïݺ®*ëK•ùô_(œ¿Îxú‚ÌŽŽfJÂ/ +»½ý4g퀇óú¥†>Ÿí”Àãñõ”mšfÔ†þ(o ðù|>@ àó~‡n ™ýör/\?¨ªêQF9‘$©R2?\Ÿßw“NÍVN€ A‰Ñ‹W/Iæ»lGÓ´,™_Á[y²dþv1,x´Î{÷„õÑè‘‘†íuþ×°Ìß%¥3¡ÓsÖº=*½(œôP`^¿Àç×ôÓ®ÐÈ…ÏG àóŸhL4M£ûb­¦ö=‰…BM~ÅXÕçê¾>ïO¦0¨C,ËRm\¼ºw™ïîç)ÿ;W–뼸Ü!óµ¥™o×õOóµá)IÒ½Ë|Ãèåß ‡·œ«Ø_:1³»÷Bì© ¤×´Å\òêç>¶Ü‚뺠†>Ÿý ðòƒ„½ÜTŸ¶Ñuÿ.¢?r­þ}þSk×Ѫ“¯¼Šá¥_¹¸Ú»CT$èJñ«FW°qN|ÛÖwª4¢ÑÕ§cœ}íuEקuœ_Aú"0¥Ö[ò'(À_Ð=#+ݬ‡ƒ¡ÛUö|A’¤°ºsgïT©d4À>¿í°[éÞÞA üˆ®ëe¾»Ÿ§¬ë\YQ”º>í|2Ÿ"ù(kEÓŒ‹bKy2?ÑÅ;Ø=yËÌÌîh§´ë̳ô/<ã’T—l¢ýú»kÕÐçÓÔïe"¦_¬óÓÜÈÑM- ØÐ0gW„}Ìú 4FŸ?ÐQ9}Q /Vð¨ÿ~Ð@N9ÿÛ={Š®Oë ÌØw`J€FÀ4MfÅ‹¢(J­nÛëŠûü®xÒE=5wZ/øŽ¬Šú²e~z´Ï¯í‹ZÅ) ósëó£Ñ#‚°¾l™OXÝ¿¥]諾Ìv—>4Ü2’”ž¾ô¤KR½rî`?)J }>ïØî]‘ÿtaº;x°B 竈ªªæ6 |>¨P¸ÁwÀç7˜R ðp5]¡PCOåöù„º¯ÏÅ>Å“)Œ|DeþpŠPUI’œò°I˜…d¾¦µ>=š| +Ql±¬Syv·K6ù*_LSÄÊÍ–KFýâ…gê¼!‹RCŸOЯ¶kµ€;â2?À¿[˜ÏϽ(Yï#Àçƒj… Ð||~#€)‚®ëMeQïe™U&Ø>¿íð€‹}ú¯?õvtttww§Rûþ&‹áRþR:_ªªˆÌ÷ '¢Ee¾e’åÞe>­\pw{äa™¿gT3¾ülÌ%®i‹ ‚ïGem}¾ógL(¢Ù9:u~nû\œŸ†Ï5 + 3øøüFS*ç­®(ŠtKÈ—ÐáAà«Ñ ²iš ÞnÁöù]ñ¤‹€Ú`ü¥Ý&‘H`ùšŽŽ\Ê:GÓ4–“Ýe{¡KIßò(ó³¼_HZéí¢‹Ì7͸(¶x—ùYUýyv·?â¬Ìgüñ÷.étÎÚIòý¨¬­ÏO{{…~º8QÀ烅 Ð||~#€) ¿Á0 ¾œÝŠ¢è\Y×ufõ³–7&Áöù„º¯ÏÅAíÝŸ1NÉd=Á×ôôô0sˆKYo˜¦IIÆù ÕÝ”vwwÓuìèèp^Jï2?¨ï[iZ{!!o½‚°Þ£É§5iýòŽÁýu§‹Âɬ¶Ï{)뜚û|v ì§K.¡P(À•ù ø|PC p:ƒï€Ïo0¥@€áR:ëŽ/·,˹Ü0ŒÀVr–ÛtAòùñdªgà4ûÛÝAí>ƒ‰D—²®ˆF£y=¼{ªI¥RÎKI©[Å—ù†Ñ[HæGÛ~-œ¿Î£ÌÅË:å}¿C©³”?)(£¦‹=ìÊüïÞÞÁB—Ò/¶æ>ä¢4;óW éïÀ›||>¨!P¸ÁwÀç7˜R ÀH’ÄnÀÅùi»Ÿ-§ûÁ¬¯pmšf#7]ð|~ÏÀiæ—vKÐÇ®xÒÅA5wZ>TMÓòJxZX’r§|žUØ߀2?ñ™GòÊü¬¢}÷å¥îw÷ñ“,On;ÔbðŒK"åÑz0î󦮟߰À烅 Ð||~#€) 9=k9¿7Ï­Ã7M“ý—ÚØ?Ò‚çó¹ƒR÷õ±%îe¥¬ôt(u¶gà4ûP6ykòiaîCUw4MóhòA(uã¾#ù(Þ¢ëŸ:Ú§™¯ª—±Sž9Y•¾Ÿ¿íP¿¯Û>¿æ(Š’õkÄ0 Z’õÀΩÚÊ/ÎgŒ@>ø(\€Îà;àóL©` +ù|˲ØrºCÌýV( +’Ç.àù|giÏÀiZân¢ööÒ:ÄØ#€¡ÔY (ʆgcfÚ)ÔñTÞ‡…d~ÖkY Jþ’$ÑÁäý_¿ã]æ ÂúhôÈè–9¥ªG"Ñ.»ØÿÙ3‘º?åAßòuÃÂçûø|Pí~…‹Î€Îà àóL©`¸AÊG.²ºÐS€†"x>?="ç)vKÐÇ®xÒE@5wZ´ÿH+c@P6š¦ ‚ ŠbV=­G,Ë¢ïŽQæÓBú¯àe¶‘ö*óE±Å4ãÎïÒGZÈþW–w¸ì¥õ`œ¥DJ§î)Ô~ +ŸïàóAµû.::ƒ/€Ïo0¥@€áR:× 15$Bî·àóÓõù¼ ã[â^\O¦š;-ö7} +€šF¹‡/ +åv˲r7Â(ðÕdYR©êÇe¾,ïȪÀ7Œ^AXï\¡Ð^(%:ß`rÅ)ëÙ¨ß{ |¾/€ÏÕîWP¸è è ¾>¿À” +Æ0ŒBåš’$±ÿÒuݹܲ,ܶ§êóÕ¤ñd*í0üycoïàÎc ö·º¯ +'”TUU-¯ÞÞ#”EiòŒ‹Ìw®&ËrÞÕꎄ™>-º–,ïð(óUõ㜖UÕ/þó“Y¶ß O˜”)…º?å±ûøI¿wuø|¿ÐñÉ'¿Ý³§ìèïï¯öB>ø(\€Îà;àóL©lB¡¿ ‡Ã\=q½C+8ÅŽ,ËÁóØeHŸO8]}z´áÏÖƒñƒgøGZ +48ÌáK’ä¬uW«sK«ëº3…ŽÊ‹ÌWÅm}HK·6eâ÷nì]ækZ»ûwåI·[›ÎKïÉÿæÂPê,øm‡ö6äEæSPõ{·‡Ï•òÁ@átߟß`J€`ã¼ wÚi˲¸¢?E‰D"¢(ò5«ZtZÿÕço;ÔÏ]=[â^b:”:»ñ@ŒýMßÅ€¥JJ†”!)é”.*¾Sþ +•G +C–Ì÷Mbé­Â°ÏßY0 —-ó-ë”(¶8Wxò–™î»s +üƒgx.uÊŸðù R@>ø(\€Îà;àóL©x4MãêÞi§UU-¤†DQlðF ªÏw*©¡ÔYZÒvxÀEFÑú»ŸÌú +ð ©Tª¯¯/‘H )ʆ¿²äRošf÷¨ëº³ø¿(´2}%廬 ó)i.'™/ë£Ñ#Î/Fo(ôÚ¹Î_§¯úò¹ÝÍߘÍKƒOüÊúÁ³g=çS‚ À¨„Ï•òÁ@átߟß`J€FÀ²,UU%IRŹœ>æÚ¡p8Lë7x‹ÕçÇ“)§«§%]ñ¤‹ŒÚv¨?÷+À/tww·Û á•InY¾ ´RD4­ì¾hƒ.ozöjFÞ­™¦éw™o¾ð…è+«-ëTîZÞe¾aôæ\Ó-|ñK«Œ§/6ù´ß˜Qè¸xœpÃ) +—´ù@ó¹Ò}J°•ðù R8åÃ¥_¹xîíw ê?èJñ«¶lɽèÆŒÓçO¾ò*ŒŽº1ú|4 /‚Æ |>42¦i*Š¶‘e¹Pg£TŸŸvT™î>~’>¥Ü +MÕ}}ίl;Ô¾á#ººº˜9D‰¾˲¢Ñ¨Ç§–”C¡Kªª’çc„òpÑò¾àrN뙟´ÒÛEfק/Î_×Ôô£P赬µÆ"ó IÒÙ +ÒDÙÚtް̧ý&ݺKƒ+7[MMé%›â.i³eÛ ¶2ý›»ŽŽßJø|P)œ>áÇ€2jp²D1ÂQ†ÏG 9>%À>¿+žT÷õm<‹'SlɶCý.nŠÖßÛ;È?òoú§¿¿¿»»ûرchŠh4ªªª,Ë¢(òÊöz80˲ò¾'UÊQE7Nç +…ü(ó­Mç‰_ZÅÍüè““ÌOgžžÄŸ¼ãVuÁÕÃ&Ÿbì.óÓö£ÏžÓŸûüÙ/\ðw—„IñÉÎnZŸVλX,F£òøñãþ>ðù "ÀçC_ŸŸ@rê™ûü\ö6äâ¦Ú8køO žA÷õiš4Š?%úU‚öNG(B©&? +E£Ñ^³™O!M”¹™W”ù*c—ùöGΙ| +úè MK75¥¯œ;è’0<ß_ÓnUàóA¥€Ï‡2¾>>ä Ô3 åóãÉ”‹žÚx –¶ëÁøîã'Ñ7@ýcšfQ+.IR­¯l“O(ŠbϧG9ö'o™Éͼ(¶ðU*#ó‰]Ò𾶠+飺÷c¤Ù ©)½r³å’0'Üpªv=«ZÀçƒJñÛ={^TÕ‰5«vÊ–`œÔ;[·¢72Ô‚=l'_y•S㤎=ZôÊÒ:HÈHÎ@h(ŸO4wº*ÔäáÔAh8+Š¢ëz­”¸iš²,—gò[–ÏØfŽ]_õe§™·¬Sìÿ+&󉘑ÙÝ.)ó‡g ##ó¿pÁß]RedW­¼I>€2ȪwEƒPÿ8_@xQUÑ  @ÝÂýs¥²8*¥=Äçïít‘T;%0Ä@m1 CUUMÓ<®/IR(¢ñKcY×uÓ4k{üÌä—é,‚Y–Ï9ª§· +ÆÓç¯ãrž›ùJÊür‘åŒÏŸýpÂ%UÎY;@ëOÀçPÐGøøü ‚„  nϯR{6ˆÏ?1xÆER5wZb`œ1MSÓ4EQh :S“ê·Û+:‹¬S( Q Ãh„+nY§B¡×¸œ×´v¶¼d¾e¥!ãó×´Å\RåEá$­¼ËŸ@@à;àóƒ +2€º>¿JíÙ >ŸØxÀÍSÅ“)Œ2Pm,Ë¢¡GƒN—Ju_œ‹išŠ¢¸œHQ軾{x1Âá-\Î+ʇ™EI«d>Aס©)ýÅ Ýž{FvõÑ:¡ Þ#ÂçPÐGøøü ‚„  n1M3ZY–¥ž‘HDÓ4þ¿¬––;Ë_i¹eYÜž èówK¸¨ª½½ƒe ÚH’䮸iÊuu~º®¥ Ÿ™|JA–„¹œ‡·d>'-ù¦ï—!ó5­×öW +šššÒ³vK’ô¿´Ž¢ðÒÀçPÐGøøü ‚„ ÀwhšÆ‘{É=ý/³ú´¦a Þn èó{N»¨ªÖƒqŒ&Pmr58%%EQ(ÕRÒu]–å±ä3h#ŸY¨ª$í/Š-MM?¢-ë”w™ +½æ”ù¼ž_U?®à±ÉrÆç¯is{‰é‹ž¡uêþqS9ÀçPÐGøøü ‚„ À_X–ÅäýëEÑú\é£>¿Ñ|>¡îës±UC©³SÀ;ÑhT×õˆûÃDŽa’$ɲÌÞòÅiVJã³lãñ±ÏÕÌÿ¨ÏÉÈütZžûS/2Xþ·É©px ÿ¯Hä£ +XÊ0ZÂßvIkÚbMMiQ ìX†Ï T ððùA €¿PU•Ý€kšæñ+¦i²¯D"‘FnºÆôùm‡\„Õþφ0¦üE,ëèèèîîN¥RUÝå ¦îeY¦!“+·iI–Η²«$IM‚Íýù…óR† +…øwé0ÖoßøáKeÈ|VÞÏBÖ;‹öÇΙhtóóoº¤ÇÙ'ššÒ^nýÇmTVø|ÊúߟTø ®›J*¶geŸbP ½Ñ˜>¿+žtVÛõcLù‹ŽŽŽv›D"Q½½8]Ÿ ~oLÊ¢¬ßéÒÇmÐKM>¿”mmmÎÇ%”¨ö.•ñî3c”ùâ—VO_îTÇr»Ÿ¤Œwbð ûO¦\r#Å/:×O$…d¾³Ì»Y[Ë mŠ% Qi¼Ð1ÐñÐKJ;õ9‚$I^Ú§ h³´ýR§¯¯oÉ’%Y‚Ö¹iâ—VUFæSü^)û@6ˆeù|u_ŸKb|èñ¿<þîpæl=wßx*•*4*ëyPÀçP*ÐGøøü ‚„ À_(ŠÂnÀ#‘ˆÇ¯˜¦É¾ +5ôLÇ}¾ eT,³Æ»â}SYUÓ¹¨žpjšÍãïþši¨çö˜ôñ»?Þ⢭Ú°íœ<Óz0N#…1 ÃãQÑšQW¼ËO^s>öM9*ï zqݯ ÇÎàQÂ{iy§ s1Ï>uò%Aç¨ë:°MÕ„¶O°Œ#¤ šõ‚€êë{ÌùNÌ'Ý^1™¿§ü‡¼8Ÿ‚½¸ä\’‘]}Ñ>ãw?¼1Ÿ@@à;àóƒ +2¡ë:÷r^ŸeYÜ°ø³¸Ï/¯bÙ‹,­ì¦¼\_Z'÷‹n¸ƒ›¨/\ð.æJÝ×Ç6Õz0ΖÐ×]ŽÊ‹ Î{Tå‰e/ºÛ㦼•ÇÿÎàeSÎÁ +…ø“øüE€e>š¦it²üu¤êA]Žv4–Æt>h ­•÷P .HZéíbÆ·ïýÞSÌИ^’Ì·‡Ã‘ŠË|¢¹ÓbÉmãXÖ’¼ñÝ–£NáO¦‚7^àó(è#||~PABà;¸­*jè†ÝYÚu¹.¸øüq¶Á7UvIöç>ÿ?¸‰š¾t -yâW†‹¼:1x&íðù ž³~u}nª‚Á²¬¼þÙù‰÷÷>ñtø ʨ´Gºjcß|sŠpþº¢>_×?ÍݤñáÑïüS¥d~Úñ¤’ç·pɇo:|¸÷ïY‚|>e}€ï€Ï*HÈüˆa%Õ£Bæ§>ߣþõ5]ñ¤³üžÂÅ_1ÍO¦¯°€‰F£”ÁdY.úd§þ5~ HZé­Â°u§?#­Ô©†ÿeYQ™‰|”³|›•ùÎRüÝÇOÒ’¡ÔY÷âüWßèu>ܤõƒ:¬àó(è#||~PABàS,ËŠD"E+TC¡÷¢ñ`ÓP>ŸP÷õ9Ëï7ˆ¹(¬žÓ´Ns§Å>n;ÔjE >AIU’$MÓ ñ‹°K:'Þ;UË:e½é„];¡¨Ì—$½àf+'óÓŽâ|ʇÌÌï>~Ò%®i‹uV#dBø|ÊúߟTø˲4MË_ápXQ˜|'æóÛ8ËïwK¸X,Z™Öi„ªTP‡ÔVàó´@)Â0 \OÕω÷]’e„õQÿ ¥hq¾(¶Ðú·|HK \ No newline at end of file diff --git a/third_party/rust/zlib-rs/src/deflate/test-data/read_buf_window_uninitialized.txt b/third_party/rust/zlib-rs/src/deflate/test-data/read_buf_window_uninitialized.txt new file mode 100644 index 0000000000000000000000000000000000000000..52a0150b60a6f4466657926d80177f1157c9e977 GIT binary patch literal 10119 zcmeHN%}T^D5FW+f#e?8Q5O0DaD1zW^eE<)IJ$g{s_kRgznoc{JB$HO!ZC4X;Gnq`1 z$^3jtTR#BcU=1g*f(JNRVGGMsQv;kk2LIk6L4N?%WmUmfWt8u*ZxfVyuEz;QmuIWqn9?X+q9qNyq{H}hplvp)Oij7sc`*;yTOy=}rIjnJ?7!l6Z&fS-$ zubmEuaaD->?)8yjJv)k}Tk^A|8sbee;_bNZzG`ErlQ5@NDpcoiEz$;)?;7sOAY7cL zoxQU0AOytX|0*;(U%-v9fhN(!W?1K);fIme%0VXzcTV+20%9+;im9$-^VTfMVOGZh zz`8|#OVH@swHdT3TaRHTx(<&`06AS;1+tQ1##JMzrlKKWC%(54YM7g0_^6j7X{jL7 zE7LoVGz@d#7~sf}&954DrEdj77(?hxG~=Whx!f5a+HiN4Nk-B-hrBqASZh&J2YE%D zbnJ(=o+RR2Y&DkJRb`%Gff93vGAWeNq4kjjfLYIu8%09wf6Fd0-Y0pd6V`YIl7U2^));>j(+3mkiLb;1AN&iH+EFBdGoÌÌÌàÌ̹̘ÌÔÌEÌsÌ—ÌÌ4̢̙̑Ì6ÌÌØÌæÌ\ÌÌÌ5̪̲̕ÌmÌÌ–Ìç̺̜ÌÙ̧ÌÌíÌíÌ–ÌÌëÌmÌìÌÎ̵ÌGÌïÌOÌÛÌ ÌÃÌòÌÎÌôÌ„Ì;Ì”ÌýÌ’ÌÓÌÀÌ×Ì,ÌÑÌ¢ÌáÌAÌ9Ì»ÌæÌ‚ÌÂÌsÌý̼ÌÝÌÌ­ÌeÌòÌÝÌUÌuÌí̱ÌËÌwÌùÌ•ÌDÌß̋̽Ìt̞̣̹ÌöÌôÌOÌîÌíÌ…ÌpÌGÌìÌ°ÌÀÌ(ÌÌÌ̤Ì{Ì“ÌßÌïÌÕÌÌøÌÌMÌ#ÌÌí̵ÌdÌ·ÌIÌßÌhÌ_ÌpÌJÌÇÌ¢ÌÎÌÌoÌÌêÌÁÌ;Ì<̘ÌZÌÈÌÑÌoÌWÌ„Ì¿Ì}ÌáÌÌÌ:Ìá̧̻̕ÌeÌFÌtÌ(ÌEÌoÌàÌpÌÌ¢Ì(Ì;ÌþÌëÌóÌ!̹̹ÌÉÌÌœÌîÌÖÌ4ÌÈÌ3ÌëÌ‹ÌBÌŽÌÆÌuÌPÌ6Ì“ÌþÌ&̦̳̕ÌÁÌðÌ»ÌÌÌTÌÀ̧ÌbÌÌÒÌÕÌëÌ{ÌÆÌ¡ÌÊÌNÌ9ÌÇÌÌBÌÑ \ No newline at end of file diff --git a/third_party/rust/zlib-rs/src/deflate/trees_tbl.rs b/third_party/rust/zlib-rs/src/deflate/trees_tbl.rs new file mode 100644 index 000000000000..07abb66b9643 --- /dev/null +++ b/third_party/rust/zlib-rs/src/deflate/trees_tbl.rs @@ -0,0 +1,140 @@ +#![forbid(unsafe_code)] + +use crate::deflate::{ + Value, DIST_CODE_LEN, D_CODES, LENGTH_CODES, L_CODES, STD_MAX_MATCH, STD_MIN_MATCH, +}; + +const fn h(freq: u16, code: u16) -> Value { + Value::new(freq, code) +} + +#[rustfmt::skip] +pub const STATIC_LTREE: [Value; L_CODES + 2] = [ + h( 12,8), h(140,8), h( 76,8), h(204,8), h( 44,8), + h(172,8), h(108,8), h(236,8), h( 28,8), h(156,8), + h( 92,8), h(220,8), h( 60,8), h(188,8), h(124,8), + h(252,8), h( 2,8), h(130,8), h( 66,8), h(194,8), + h( 34,8), h(162,8), h( 98,8), h(226,8), h( 18,8), + h(146,8), h( 82,8), h(210,8), h( 50,8), h(178,8), + h(114,8), h(242,8), h( 10,8), h(138,8), h( 74,8), + h(202,8), h( 42,8), h(170,8), h(106,8), h(234,8), + h( 26,8), h(154,8), h( 90,8), h(218,8), h( 58,8), + h(186,8), h(122,8), h(250,8), h( 6,8), h(134,8), + h( 70,8), h(198,8), h( 38,8), h(166,8), h(102,8), + h(230,8), h( 22,8), h(150,8), h( 86,8), h(214,8), + h( 54,8), h(182,8), h(118,8), h(246,8), h( 14,8), + h(142,8), h( 78,8), h(206,8), h( 46,8), h(174,8), + h(110,8), h(238,8), h( 30,8), h(158,8), h( 94,8), + h(222,8), h( 62,8), h(190,8), h(126,8), h(254,8), + h( 1,8), h(129,8), h( 65,8), h(193,8), h( 33,8), + h(161,8), h( 97,8), h(225,8), h( 17,8), h(145,8), + h( 81,8), h(209,8), h( 49,8), h(177,8), h(113,8), + h(241,8), h( 9,8), h(137,8), h( 73,8), h(201,8), + h( 41,8), h(169,8), h(105,8), h(233,8), h( 25,8), + h(153,8), h( 89,8), h(217,8), h( 57,8), h(185,8), + h(121,8), h(249,8), h( 5,8), h(133,8), h( 69,8), + h(197,8), h( 37,8), h(165,8), h(101,8), h(229,8), + h( 21,8), h(149,8), h( 85,8), h(213,8), h( 53,8), + h(181,8), h(117,8), h(245,8), h( 13,8), h(141,8), + h( 77,8), h(205,8), h( 45,8), h(173,8), h(109,8), + h(237,8), h( 29,8), h(157,8), h( 93,8), h(221,8), + h( 61,8), h(189,8), h(125,8), h(253,8), h( 19,9), + h(275,9), h(147,9), h(403,9), h( 83,9), h(339,9), + h(211,9), h(467,9), h( 51,9), h(307,9), h(179,9), + h(435,9), h(115,9), h(371,9), h(243,9), h(499,9), + h( 11,9), h(267,9), h(139,9), h(395,9), h( 75,9), + h(331,9), h(203,9), h(459,9), h( 43,9), h(299,9), + h(171,9), h(427,9), h(107,9), h(363,9), h(235,9), + h(491,9), h( 27,9), h(283,9), h(155,9), h(411,9), + h( 91,9), h(347,9), h(219,9), h(475,9), h( 59,9), + h(315,9), h(187,9), h(443,9), h(123,9), h(379,9), + h(251,9), h(507,9), h( 7,9), h(263,9), h(135,9), + h(391,9), h( 71,9), h(327,9), h(199,9), h(455,9), + h( 39,9), h(295,9), h(167,9), h(423,9), h(103,9), + h(359,9), h(231,9), h(487,9), h( 23,9), h(279,9), + h(151,9), h(407,9), h( 87,9), h(343,9), h(215,9), + h(471,9), h( 55,9), h(311,9), h(183,9), h(439,9), + h(119,9), h(375,9), h(247,9), h(503,9), h( 15,9), + h(271,9), h(143,9), h(399,9), h( 79,9), h(335,9), + h(207,9), h(463,9), h( 47,9), h(303,9), h(175,9), + h(431,9), h(111,9), h(367,9), h(239,9), h(495,9), + h( 31,9), h(287,9), h(159,9), h(415,9), h( 95,9), + h(351,9), h(223,9), h(479,9), h( 63,9), h(319,9), + h(191,9), h(447,9), h(127,9), h(383,9), h(255,9), + h(511,9), h( 0,7), h( 64,7), h( 32,7), h( 96,7), + h( 16,7), h( 80,7), h( 48,7), h(112,7), h( 8,7), + h( 72,7), h( 40,7), h(104,7), h( 24,7), h( 88,7), + h( 56,7), h(120,7), h( 4,7), h( 68,7), h( 36,7), + h(100,7), h( 20,7), h( 84,7), h( 52,7), h(116,7), + h( 3,8), h(131,8), h( 67,8), h(195,8), h( 35,8), + h(163,8), h( 99,8), h(227,8) +]; + +#[rustfmt::skip] +pub const STATIC_DTREE: [Value; D_CODES] = [ + h( 0,5), h(16,5), h( 8,5), h(24,5), h( 4,5), + h(20,5), h(12,5), h(28,5), h( 2,5), h(18,5), + h(10,5), h(26,5), h( 6,5), h(22,5), h(14,5), + h(30,5), h( 1,5), h(17,5), h( 9,5), h(25,5), + h( 5,5), h(21,5), h(13,5), h(29,5), h( 3,5), + h(19,5), h(11,5), h(27,5), h( 7,5), h(23,5) +]; + +#[rustfmt::skip] +pub const DIST_CODE: [u8; DIST_CODE_LEN] = [ + 0, 1, 2, 3, 4, 4, 5, 5, 6, 6, 6, 6, 7, 7, 7, 7, 8, 8, 8, 8, + 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, + 11, 11, 11, 11, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 0, 16, 17, + 18, 18, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 22, 22, 22, 22, 22, 22, 22, 22, + 23, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, + 24, 24, 24, 24, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, + 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, + 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27, + 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, + 27, 27, 27, 27, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, + 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, + 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, + 28, 28, 28, 28, 28, 28, 28, 28, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, + 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, + 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, + 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29 +]; + +#[rustfmt::skip] +pub const LENGTH_CODE: [u8; STD_MAX_MATCH-STD_MIN_MATCH+1] = [ + 0, 1, 2, 3, 4, 5, 6, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 12, 12, + 13, 13, 13, 13, 14, 14, 14, 14, 15, 15, 15, 15, 16, 16, 16, 16, 16, 16, 16, 16, + 17, 17, 17, 17, 17, 17, 17, 17, 18, 18, 18, 18, 18, 18, 18, 18, 19, 19, 19, 19, + 19, 19, 19, 19, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, + 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 22, 22, 22, 22, + 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 23, 23, 23, 23, 23, 23, 23, 23, + 23, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, + 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, + 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, + 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 26, 26, 26, 26, 26, 26, 26, 26, + 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, + 26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, + 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 28 +]; + +pub const BASE_LENGTH: [u8; LENGTH_CODES] = [ + 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, 0, +]; + +#[rustfmt::skip] +pub const BASE_DIST: [u16; D_CODES] = [ + 0, 1, 2, 3, 4, 6, 8, 12, 16, 24, + 32, 48, 64, 96, 128, 192, 256, 384, 512, 768, + 1024, 1536, 2048, 3072, 4096, 6144, 8192, 12288, 16384, 24576 +]; diff --git a/third_party/rust/zlib-rs/src/deflate/window.rs b/third_party/rust/zlib-rs/src/deflate/window.rs new file mode 100644 index 000000000000..769e2cadc3e4 --- /dev/null +++ b/third_party/rust/zlib-rs/src/deflate/window.rs @@ -0,0 +1,146 @@ +use crate::allocate::Allocator; +use core::mem::MaybeUninit; + +#[derive(Debug)] +pub struct Window<'a> { + // the full window allocation. This is longer than w_size so that operations don't need to + // perform bounds checks. + buf: &'a mut [MaybeUninit], + + // number of initialized bytes + filled: usize, + + window_bits: usize, + + high_water: usize, +} + +impl<'a> Window<'a> { + pub fn new_in(alloc: &Allocator<'a>, window_bits: usize) -> Option { + let buf = alloc.allocate_slice::(2 * ((1 << window_bits) + Self::padding()))?; + + Some(Self { + buf, + filled: 0, + window_bits, + high_water: 0, + }) + } + + pub fn clone_in(&self, alloc: &Allocator<'a>) -> Option { + let mut clone = Self::new_in(alloc, self.window_bits)?; + + clone.buf.copy_from_slice(self.buf); + clone.filled = self.filled; + clone.high_water = self.high_water; + + Some(clone) + } + + pub unsafe fn drop_in(&mut self, alloc: &Allocator) { + if !self.buf.is_empty() { + let buf = core::mem::take(&mut self.buf); + alloc.deallocate(buf.as_mut_ptr(), buf.len()); + } + } + + pub fn capacity(&self) -> usize { + 2 * (1 << self.window_bits) + } + + /// Returns a shared reference to the filled portion of the buffer. + #[inline] + pub fn filled(&self) -> &[u8] { + // safety: `self.buf` has been initialized for at least `filled` elements + unsafe { core::slice::from_raw_parts(self.buf.as_ptr().cast(), self.filled) } + } + + /// Returns a mutable reference to the filled portion of the buffer. + #[inline] + pub fn filled_mut(&mut self) -> &mut [u8] { + // safety: `self.buf` has been initialized for at least `filled` elements + unsafe { core::slice::from_raw_parts_mut(self.buf.as_mut_ptr().cast(), self.filled) } + } + + /// # Safety + /// + /// `src` must point to `range.end - range.start` valid (initialized!) bytes + pub unsafe fn copy_and_initialize(&mut self, range: core::ops::Range, src: *const u8) { + let (start, end) = (range.start, range.end); + + let dst = self.buf[range].as_mut_ptr() as *mut u8; + core::ptr::copy_nonoverlapping(src, dst, end - start); + + if start >= self.filled { + self.filled = Ord::max(self.filled, end); + } + + self.high_water = Ord::max(self.high_water, self.filled); + } + + // this library has many functions that operated in a chunked fashion on memory. For + // performance, we want to minimize bounds checks. Therefore we reserve initialize some extra + // memory at the end of the window so that chunked operations can use the whole buffer. If they + // go slightly over `self.capacity` that's okay, we account for that here by making sure the + // memory there is initialized! + pub fn initialize_out_of_bounds(&mut self) { + const WIN_INIT: usize = crate::deflate::STD_MAX_MATCH; + + // If the WIN_INIT bytes after the end of the current data have never been + // written, then zero those bytes in order to avoid memory check reports of + // the use of uninitialized (or uninitialised as Julian writes) bytes by + // the longest match routines. Update the high water mark for the next + // time through here. WIN_INIT is set to STD_MAX_MATCH since the longest match + // routines allow scanning to strstart + STD_MAX_MATCH, ignoring lookahead. + if self.high_water < self.capacity() { + let curr = self.filled().len(); + + if self.high_water < curr { + // Previous high water mark below current data -- zero WIN_INIT + // bytes or up to end of window, whichever is less. + let init = Ord::min(self.capacity() - curr, WIN_INIT); + + self.buf[curr..][..init].fill(MaybeUninit::new(0)); + + self.high_water = curr + init; + + self.filled += init; + } else if self.high_water < curr + WIN_INIT { + // High water mark at or above current data, but below current data + // plus WIN_INIT -- zero out to current data plus WIN_INIT, or up + // to end of window, whichever is less. + let init = Ord::min( + curr + WIN_INIT - self.high_water, + self.capacity() - self.high_water, + ); + + self.buf[self.high_water..][..init].fill(MaybeUninit::new(0)); + + self.high_water += init; + self.filled += init; + } + } + } + + pub fn initialize_at_least(&mut self, at_least: usize) { + let end = at_least.clamp(self.high_water, self.buf.len()); + self.buf[self.high_water..end].fill(MaybeUninit::new(0)); + + self.high_water = end; + self.filled = end; + } + + // padding required so that SIMD operations going out-of-bounds are not a problem + pub fn padding() -> usize { + #[cfg(feature = "std")] + #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] + if std::is_x86_feature_detected!("pclmulqdq") + && std::is_x86_feature_detected!("sse2") + && std::is_x86_feature_detected!("sse4.1") + { + return 8; + } + + 0 + } +} diff --git a/third_party/rust/zlib-rs/src/inflate.rs b/third_party/rust/zlib-rs/src/inflate.rs new file mode 100644 index 000000000000..2fc3963a9e0a --- /dev/null +++ b/third_party/rust/zlib-rs/src/inflate.rs @@ -0,0 +1,2284 @@ +#![allow(non_snake_case)] // TODO ultimately remove this +#![allow(clippy::missing_safety_doc)] // obviously needs to be fixed long-term + +use core::ffi::{c_char, c_int, c_long, c_ulong}; +use core::marker::PhantomData; +use core::mem::MaybeUninit; + +mod bitreader; +mod inffixed_tbl; +mod inftrees; +mod window; + +use crate::allocate::Allocator; +use crate::c_api::internal_state; +use crate::{ + adler32::adler32, + c_api::{gz_header, z_checksum, z_size, z_stream, Z_DEFLATED}, + read_buf::ReadBuf, + Code, InflateFlush, ReturnCode, DEF_WBITS, MAX_WBITS, MIN_WBITS, +}; + +use crate::crc32::{crc32, Crc32Fold}; + +use self::{ + bitreader::BitReader, + inftrees::{inflate_table, CodeType, InflateTable}, + window::Window, +}; + +#[repr(C)] +pub struct InflateStream<'a> { + pub(crate) next_in: *mut crate::c_api::Bytef, + pub(crate) avail_in: crate::c_api::uInt, + pub(crate) total_in: crate::c_api::z_size, + pub(crate) next_out: *mut crate::c_api::Bytef, + pub(crate) avail_out: crate::c_api::uInt, + pub(crate) total_out: crate::c_api::z_size, + pub(crate) msg: *mut c_char, + pub(crate) state: &'a mut State<'a>, + pub(crate) alloc: Allocator<'a>, + pub(crate) data_type: c_int, + pub(crate) adler: crate::c_api::z_checksum, + pub(crate) reserved: crate::c_api::uLong, +} + +#[cfg(feature = "__internal-test")] +#[doc(hidden)] +pub const INFLATE_STATE_SIZE: usize = core::mem::size_of::(); + +#[cfg(feature = "__internal-test")] +#[doc(hidden)] +pub unsafe fn set_mode_dict(strm: &mut z_stream) { + unsafe { + (*(strm.state as *mut State)).mode = Mode::Dict; + } +} + +impl<'a> InflateStream<'a> { + const _S: () = assert!(core::mem::size_of::() == core::mem::size_of::()); + const _A: () = assert!(core::mem::align_of::() == core::mem::align_of::()); + + /// # Safety + /// + /// The `strm` pointer must be either `NULL` or a correctly initalized `z_stream`. Here + /// correctly initalized does not just mean that the pointer is valid and well-aligned, but + /// also that it has been initialized by that `inflateInit_` or `inflateInit2_`. + #[inline(always)] + pub unsafe fn from_stream_ref(strm: *const z_stream) -> Option<&'a Self> { + if strm.is_null() { + return None; + } + + // safety: ptr points to a valid value of type z_stream (if non-null) + let stream = unsafe { &*strm }; + + if stream.zalloc.is_none() || stream.zfree.is_none() { + return None; + } + + if stream.state.is_null() { + return None; + } + + // safety: InflateStream has the same layout as z_stream + let stream = unsafe { &*(strm as *const InflateStream) }; + + Some(stream) + } + + /// # Safety + /// + /// The `strm` pointer must be either `NULL` or a correctly initalized `z_stream`. Here + /// correctly initalized does not just mean that the pointer is valid and well-aligned, but + /// also that it has been initialized by that `inflateInit_` or `inflateInit2_`. + #[inline(always)] + pub unsafe fn from_stream_mut(strm: *mut z_stream) -> Option<&'a mut Self> { + if strm.is_null() { + return None; + } + + // safety: ptr points to a valid value of type z_stream (if non-null) + let stream = unsafe { &mut *strm }; + + if stream.zalloc.is_none() || stream.zfree.is_none() { + return None; + } + + if stream.state.is_null() { + return None; + } + + // safety: InflateStream has the same layout as z_stream + let stream = unsafe { &mut *(strm as *mut InflateStream) }; + + Some(stream) + } + + fn as_z_stream_mut(&mut self) -> &mut z_stream { + // safety: a valid &mut InflateStream is also a valid &mut z_stream + unsafe { &mut *(self as *mut _ as *mut z_stream) } + } +} + +const MAX_BITS: u8 = 15; // maximum number of bits in a code +const MAX_DIST_EXTRA_BITS: u8 = 13; // maximum number of extra distance bits + // +pub fn uncompress_slice<'a>( + output: &'a mut [u8], + input: &[u8], + config: InflateConfig, +) -> (&'a mut [u8], ReturnCode) { + let output_uninit = unsafe { + core::slice::from_raw_parts_mut(output.as_mut_ptr() as *mut MaybeUninit, output.len()) + }; + + uncompress(output_uninit, input, config) +} + +/// Inflates `source` into `dest`, and writes the final inflated size into `dest_len`. +pub fn uncompress<'a>( + output: &'a mut [MaybeUninit], + input: &[u8], + config: InflateConfig, +) -> (&'a mut [u8], ReturnCode) { + let mut dest_len_ptr = output.len() as z_checksum; + + // for detection of incomplete stream when *destLen == 0 + let mut buf = [0u8]; + + let mut left; + let mut len = input.len() as u64; + + let dest = if output.is_empty() { + left = 1; + + buf.as_mut_ptr() + } else { + left = output.len() as u64; + dest_len_ptr = 0; + + output.as_mut_ptr() as *mut u8 + }; + + let mut stream = z_stream { + next_in: input.as_ptr() as *mut u8, + avail_in: 0, + + zalloc: None, + zfree: None, + opaque: core::ptr::null_mut(), + + ..z_stream::default() + }; + + let err = init(&mut stream, config); + if err != ReturnCode::Ok { + return (&mut [], err); + } + + stream.next_out = dest; + stream.avail_out = 0; + + let Some(stream) = (unsafe { InflateStream::from_stream_mut(&mut stream) }) else { + return (&mut [], ReturnCode::StreamError); + }; + + let err = loop { + if stream.avail_out == 0 { + stream.avail_out = Ord::min(left, u32::MAX as u64) as u32; + left -= stream.avail_out as u64; + } + + if stream.avail_in == 0 { + stream.avail_in = Ord::min(len, u32::MAX as u64) as u32; + len -= stream.avail_in as u64; + } + + let err = unsafe { inflate(stream, InflateFlush::NoFlush) }; + + if err != ReturnCode::Ok { + break err; + } + }; + + if !output.is_empty() { + dest_len_ptr = stream.total_out; + } else if stream.total_out != 0 && err == ReturnCode::BufError { + left = 1; + } + + let avail_out = stream.avail_out; + + end(stream); + + let ret = match err { + ReturnCode::StreamEnd => ReturnCode::Ok, + ReturnCode::NeedDict => ReturnCode::DataError, + ReturnCode::BufError if (left + avail_out as u64) != 0 => ReturnCode::DataError, + _ => err, + }; + + // SAFETY: we have now initialized these bytes + let output_slice = unsafe { + core::slice::from_raw_parts_mut(output.as_mut_ptr() as *mut u8, dest_len_ptr as usize) + }; + + (output_slice, ret) +} + +#[derive(Debug, Clone, Copy)] +pub enum Mode { + Head, + Flags, + Time, + Os, + ExLen, + Extra, + Name, + Comment, + HCrc, + Sync, + Mem, + Length, + Type, + TypeDo, + Stored, + CopyBlock, + Check, + Len_, + Len, + Lit, + LenExt, + Dist, + DistExt, + Match, + Table, + LenLens, + CodeLens, + DictId, + Dict, + Done, + Bad, +} + +#[derive(Clone, Copy)] +#[allow(clippy::enum_variant_names)] +enum Codes { + Fixed(&'static [Code]), + Codes, + Len, + Dist, +} + +impl Default for Codes { + fn default() -> Self { + Codes::Fixed(&[]) + } +} + +#[derive(Default, Clone, Copy)] +struct Table { + codes: Codes, + bits: usize, +} + +pub(crate) struct State<'a> { + /// Current inflate mode + mode: Mode, + + /// true if processing the last block + last: bool, + /// bitflag + /// + /// - bit 0 true if zlib + /// - bit 1 true if gzip + /// - bit 2 true to validate check value + wrap: usize, + + /// table for length/literal codes + len_table: Table, + + /// table for dist codes + dist_table: Table, + + /// log base 2 of requested window size + wbits: usize, + // allocated window if needed (capacity == 0 if unused) + window: Window<'a>, + + /// place to store gzip header if needed + head: Option<&'a mut gz_header>, + + // + /// number of code length code lengths + ncode: usize, + /// number of length code lengths + nlen: usize, + /// number of distance code lengths + ndist: usize, + /// number of code lengths in lens[] + have: usize, + /// next available space in codes[] + next: usize, // represented as an index, don't want a self-referential structure here + + // IO + bit_reader: BitReader<'a>, + + writer: ReadBuf<'a>, + total: usize, + + /// length of a block to copy + length: usize, + /// distance back to copy the string from + offset: usize, + + /// extra bits needed + extra: usize, + + /// if false, allow invalid distance too far + sane: bool, + /// bits back of last unprocessed length/lit + back: usize, + + /// initial length of match + was: usize, + + /// size of memory copying chunk + chunksize: usize, + + in_available: usize, + out_available: usize, + + /// temporary storage space for code lengths + lens: [u16; 320], + /// work area for code table building + work: [u16; 288], + + error_message: Option<&'static str>, + flush: InflateFlush, + + checksum: u32, + crc_fold: Crc32Fold, + + havedict: bool, + dmax: usize, + flags: i32, + + codes_codes: [Code; crate::ENOUGH_LENS], + len_codes: [Code; crate::ENOUGH_LENS], + dist_codes: [Code; crate::ENOUGH_DISTS], +} + +impl<'a> State<'a> { + fn new(reader: &'a [u8], writer: ReadBuf<'a>) -> Self { + let in_available = reader.len(); + let out_available = writer.capacity(); + + Self { + flush: InflateFlush::NoFlush, + + last: false, + wrap: 0, + mode: Mode::Head, + length: 0, + + len_table: Table::default(), + dist_table: Table::default(), + + wbits: 0, + offset: 0, + extra: 0, + sane: true, + back: 0, + was: 0, + chunksize: 0, + in_available, + out_available, + + bit_reader: BitReader::new(reader), + + writer, + total: 0, + + window: Window::empty(), + head: None, + + lens: [0u16; 320], + work: [0u16; 288], + + ncode: 0, + nlen: 0, + ndist: 0, + have: 0, + next: 0, + + error_message: None, + + checksum: 0, + crc_fold: Crc32Fold::new(), + + havedict: false, + dmax: 0, + flags: 0, + + codes_codes: [Code::default(); crate::ENOUGH_LENS], + len_codes: [Code::default(); crate::ENOUGH_LENS], + dist_codes: [Code::default(); crate::ENOUGH_DISTS], + } + } + + fn len_table_ref(&self) -> &[Code] { + match self.len_table.codes { + Codes::Fixed(fixed) => fixed, + Codes::Codes => &self.codes_codes, + Codes::Len => &self.len_codes, + Codes::Dist => &self.dist_codes, + } + } + + fn dist_table_ref(&self) -> &[Code] { + match self.dist_table.codes { + Codes::Fixed(fixed) => fixed, + Codes::Codes => &self.codes_codes, + Codes::Len => &self.len_codes, + Codes::Dist => &self.dist_codes, + } + } + + fn len_table_get(&self, index: usize) -> Code { + self.len_table_ref()[index] + } + + fn dist_table_get(&self, index: usize) -> Code { + self.dist_table_ref()[index] + } +} + +macro_rules! pull_byte { + ($self:expr) => { + match $self.bit_reader.pull_byte() { + Err(return_code) => return $self.inflate_leave(return_code), + Ok(_) => (), + } + }; +} + +macro_rules! need_bits { + ($self:expr, $n:expr) => { + match $self.bit_reader.need_bits($n) { + Err(return_code) => return $self.inflate_leave(return_code), + Ok(v) => v, + } + }; +} + +// swaps endianness +const fn zswap32(q: u32) -> u32 { + u32::from_be(q.to_le()) +} + +const INFLATE_FAST_MIN_HAVE: usize = 15; +const INFLATE_FAST_MIN_LEFT: usize = 260; + +impl<'a> State<'a> { + fn dispatch(&mut self) -> ReturnCode { + match self.mode { + Mode::Head => self.head(), + Mode::Flags => self.flags(), + Mode::Time => self.time(), + Mode::Os => self.os(), + Mode::ExLen => self.ex_len(), + Mode::Extra => self.extra(), + Mode::Name => self.name(), + Mode::Comment => self.comment(), + Mode::HCrc => self.hcrc(), + Mode::Sync => self.sync(), + Mode::Type => self.type_(), + Mode::TypeDo => self.type_do(), + Mode::Stored => self.stored(), + Mode::CopyBlock => self.copy_block(), + Mode::Check => self.check(), + Mode::Len => self.len(), + Mode::Len_ => self.len_(), + Mode::LenExt => self.len_ext(), + Mode::Lit => self.lit(), + Mode::Dist => self.dist(), + Mode::DistExt => self.dist_ext(), + Mode::Match => self.match_(), + Mode::Done => todo!(), + Mode::Table => self.table(), + Mode::LenLens => self.len_lens(), + Mode::CodeLens => self.code_lens(), + Mode::Dict => self.dict(), + Mode::DictId => self.dict_id(), + Mode::Bad => self.bad("repeated call with bad state\0"), + Mode::Mem => self.mem(), + Mode::Length => self.length(), + } + } + + // ---------------- + + /// Initial state + #[inline(never)] + fn head(&mut self) -> ReturnCode { + if self.wrap == 0 { + self.mode = Mode::TypeDo; + return self.type_do(); + } + + need_bits!(self, 16); + + // Gzip + if (self.wrap & 2) != 0 && self.bit_reader.hold() == 0x8b1f { + if self.wbits == 0 { + self.wbits = 15; + } + + let b0 = self.bit_reader.bits(8) as u8; + let b1 = (self.bit_reader.hold() >> 8) as u8; + self.checksum = crc32(crate::CRC32_INITIAL_VALUE, &[b0, b1]); + self.bit_reader.init_bits(); + + self.mode = Mode::Flags; + return self.flags(); + } + + // check if zlib header is allowed + if (self.wrap & 1) != 0 + && ((self.bit_reader.bits(8) << 8) + (self.bit_reader.hold() >> 8)) % 31 != 0 + { + self.mode = Mode::Bad; + return self.bad("incorrect header check\0"); + } + + if self.bit_reader.bits(4) != Z_DEFLATED as u64 { + self.mode = Mode::Bad; + return self.bad("unknown compression method\0"); + } + + self.bit_reader.drop_bits(4); + let len = self.bit_reader.bits(4) as usize + 8; + + if self.wbits == 0 { + self.wbits = len; + } + + if len > MAX_WBITS as usize || len > self.wbits { + self.mode = Mode::Bad; + return self.bad("invalid window size\0"); + } + + self.dmax = 1 << len; + self.flags = 0; // indicate zlib header + self.checksum = crate::ADLER32_INITIAL_VALUE as _; + + if self.bit_reader.hold() & 0x200 != 0 { + self.bit_reader.init_bits(); + + self.mode = Mode::DictId; + self.dict_id() + } else { + self.bit_reader.init_bits(); + + self.mode = Mode::Type; + self.type_() + } + } + + fn flags(&mut self) -> ReturnCode { + need_bits!(self, 16); + self.flags = self.bit_reader.hold() as i32; + + // Z_DEFLATED = 8 is the only supported method + if self.flags & 0xff != Z_DEFLATED { + self.mode = Mode::Bad; + return self.bad("unknown compression method\0"); + } + + if self.flags & 0xe000 != 0 { + self.mode = Mode::Bad; + return self.bad("unknown header flags set\0"); + } + + if let Some(head) = self.head.as_mut() { + head.text = ((self.bit_reader.hold() >> 8) & 1) as i32; + } + + if (self.flags & 0x0200) != 0 && (self.wrap & 4) != 0 { + let b0 = self.bit_reader.bits(8) as u8; + let b1 = (self.bit_reader.hold() >> 8) as u8; + self.checksum = crc32(self.checksum, &[b0, b1]); + } + + self.bit_reader.init_bits(); + self.mode = Mode::Time; + self.time() + } + + fn time(&mut self) -> ReturnCode { + need_bits!(self, 32); + if let Some(head) = self.head.as_mut() { + head.time = self.bit_reader.hold() as z_size; + } + + if (self.flags & 0x0200) != 0 && (self.wrap & 4) != 0 { + let bytes = (self.bit_reader.hold() as u32).to_ne_bytes(); + self.checksum = crc32(self.checksum, &bytes); + } + + self.bit_reader.init_bits(); + self.mode = Mode::Os; + self.os() + } + + fn os(&mut self) -> ReturnCode { + need_bits!(self, 16); + if let Some(head) = self.head.as_mut() { + head.xflags = (self.bit_reader.hold() & 0xff) as i32; + head.os = (self.bit_reader.hold() >> 8) as i32; + } + + if (self.flags & 0x0200) != 0 && (self.wrap & 4) != 0 { + let bytes = (self.bit_reader.hold() as u16).to_ne_bytes(); + self.checksum = crc32(self.checksum, &bytes); + } + + self.bit_reader.init_bits(); + self.mode = Mode::ExLen; + self.ex_len() + } + + fn ex_len(&mut self) -> ReturnCode { + if (self.flags & 0x0400) != 0 { + need_bits!(self, 16); + + // self.length (and head.extra_len) represent the length of the extra field + self.length = self.bit_reader.hold() as usize; + if let Some(head) = self.head.as_mut() { + head.extra_len = self.length as u32; + } + + if (self.flags & 0x0200) != 0 && (self.wrap & 4) != 0 { + let bytes = (self.bit_reader.hold() as u16).to_ne_bytes(); + self.checksum = crc32(self.checksum, &bytes); + } + self.bit_reader.init_bits(); + } else if let Some(head) = self.head.as_mut() { + head.extra = core::ptr::null_mut(); + } + + self.mode = Mode::Extra; + self.extra() + } + + fn extra(&mut self) -> ReturnCode { + if (self.flags & 0x0400) != 0 { + // self.length is the number of remaining `extra` bytes. But they may not all be available + let extra_available = Ord::min(self.length, self.bit_reader.bytes_remaining()); + let extra_slice = &self.bit_reader.as_slice()[..extra_available]; + + if !extra_slice.is_empty() { + if let Some(head) = self.head.as_mut() { + if !head.extra.is_null() { + let written_so_far = head.extra_len as usize - self.length; + + let count = Ord::min( + (head.extra_max as usize).saturating_sub(written_so_far), + extra_slice.len(), + ); + + unsafe { + core::ptr::copy_nonoverlapping( + self.bit_reader.as_ptr(), + head.extra.add(written_so_far), + count, + ); + } + } + } + + // Checksum + if (self.flags & 0x0200) != 0 && (self.wrap & 4) != 0 { + self.checksum = crc32(self.checksum, extra_slice) + } + + self.in_available -= extra_available; + self.bit_reader.advance(extra_available); + self.length -= extra_available; + } + + // Checks for errors occur after returning + if self.length != 0 { + return self.inflate_leave(ReturnCode::Ok); + } + } + + self.length = 0; + self.mode = Mode::Name; + self.name() + } + + fn name(&mut self) -> ReturnCode { + if (self.flags & 0x0800) != 0 { + if self.in_available == 0 { + return self.inflate_leave(ReturnCode::Ok); + } + + // the name string will always be null-terminated, but might be longer than we have + // space for in the header struct. Nonetheless, we read the whole thing. + let slice = self.bit_reader.as_slice(); + let null_terminator_index = slice.iter().position(|c| *c == 0); + + // we include the null terminator if it exists + let name_slice = match null_terminator_index { + Some(i) => &slice[..=i], + None => slice, + }; + + // if the header has space, store as much as possible in there + if let Some(head) = self.head.as_mut() { + if !head.name.is_null() { + let remaining_name_bytes = (head.name_max as usize).saturating_sub(self.length); + let copy = Ord::min(name_slice.len(), remaining_name_bytes); + + unsafe { + core::ptr::copy_nonoverlapping( + name_slice.as_ptr(), + head.name.add(self.length), + copy, + ) + }; + + self.length += copy; + } + } + + if (self.flags & 0x0200) != 0 && (self.wrap & 4) != 0 { + self.checksum = crc32(self.checksum, name_slice); + } + + let reached_end = name_slice.last() == Some(&0); + self.bit_reader.advance(name_slice.len()); + + if !reached_end && self.bit_reader.bytes_remaining() == 0 { + return self.inflate_leave(ReturnCode::Ok); + } + } else if let Some(head) = self.head.as_mut() { + head.name = core::ptr::null_mut(); + } + + self.length = 0; + self.mode = Mode::Comment; + self.comment() + } + + fn comment(&mut self) -> ReturnCode { + if (self.flags & 0x01000) != 0 { + if self.in_available == 0 { + return self.inflate_leave(ReturnCode::Ok); + } + + // the comment string will always be null-terminated, but might be longer than we have + // space for in the header struct. Nonetheless, we read the whole thing. + let slice = self.bit_reader.as_slice(); + let null_terminator_index = slice.iter().position(|c| *c == 0); + + // we include the null terminator if it exists + let comment_slice = match null_terminator_index { + Some(i) => &slice[..=i], + None => slice, + }; + + // if the header has space, store as much as possible in there + if let Some(head) = self.head.as_mut() { + if !head.comment.is_null() { + let remaining_comm_bytes = (head.comm_max as usize).saturating_sub(self.length); + let copy = Ord::min(comment_slice.len(), remaining_comm_bytes); + unsafe { + core::ptr::copy_nonoverlapping( + comment_slice.as_ptr(), + head.comment.add(self.length), + copy, + ) + }; + + self.length += copy; + } + } + + if (self.flags & 0x0200) != 0 && (self.wrap & 4) != 0 { + self.checksum = crc32(self.checksum, comment_slice); + } + + let reached_end = comment_slice.last() == Some(&0); + self.bit_reader.advance(comment_slice.len()); + + if !reached_end && self.bit_reader.bytes_remaining() == 0 { + return self.inflate_leave(ReturnCode::Ok); + } + } else if let Some(head) = self.head.as_mut() { + head.comment = core::ptr::null_mut(); + } + + self.mode = Mode::HCrc; + self.hcrc() + } + + fn hcrc(&mut self) -> ReturnCode { + if (self.flags & 0x0200) != 0 { + need_bits!(self, 16); + + if (self.wrap & 4) != 0 && self.bit_reader.hold() as u32 != (self.checksum & 0xffff) { + self.mode = Mode::Bad; + return self.bad("header crc mismatch\0"); + } + + self.bit_reader.init_bits(); + } + + if let Some(head) = self.head.as_mut() { + head.hcrc = (self.flags >> 9) & 1; + head.done = 1; + } + + // compute crc32 checksum if not in raw mode + if (self.wrap & 4 != 0) && self.flags != 0 { + self.crc_fold = Crc32Fold::new(); + self.checksum = crate::CRC32_INITIAL_VALUE; + } + + self.mode = Mode::Type; + self.type_() + } + + fn sync(&mut self) -> ReturnCode { + ReturnCode::StreamError + } + + fn lit(&mut self) -> ReturnCode { + if self.writer.remaining() == 0 { + #[cfg(all(test, feature = "std"))] + eprintln!("Ok: read_buf is full ({} bytes)", self.writer.capacity()); + return self.inflate_leave(ReturnCode::Ok); + } + + self.writer.push(self.length as u8); + + self.mode = Mode::Len; + + self.len() + } + + fn check(&mut self) -> ReturnCode { + if self.wrap != 0 { + need_bits!(self, 32); + + self.total += self.writer.len(); + + if self.wrap & 4 != 0 { + if self.flags != 0 { + self.crc_fold.fold(self.writer.filled(), self.checksum); + self.checksum = self.crc_fold.finish(); + } else { + self.checksum = adler32(self.checksum, self.writer.filled()); + } + } + + let given_checksum = if self.flags != 0 { + self.bit_reader.hold() as u32 + } else { + zswap32(self.bit_reader.hold() as u32) + }; + + if self.wrap & 4 != 0 && given_checksum != self.checksum { + self.mode = Mode::Bad; + return self.bad("incorrect data check\0"); + } + + self.bit_reader.init_bits(); + } + self.mode = Mode::Length; + self.length() + } + + fn length(&mut self) -> ReturnCode { + // for gzip, last bytes contain LENGTH + if self.wrap != 0 && self.flags != 0 { + need_bits!(self, 32); + if (self.wrap & 4) != 0 && self.bit_reader.hold() != self.total as u64 { + self.mode = Mode::Bad; + return self.bad("incorrect length check\0"); + } + + self.bit_reader.init_bits(); + } + + // inflate stream terminated properly + self.inflate_leave(ReturnCode::StreamEnd) + } + + fn type_(&mut self) -> ReturnCode { + use InflateFlush::*; + + match self.flush { + Block | Trees => self.inflate_leave(ReturnCode::Ok), + NoFlush | SyncFlush | Finish => self.type_do(), + } + } + + fn type_do(&mut self) -> ReturnCode { + if self.last { + self.bit_reader.next_byte_boundary(); + self.mode = Mode::Check; + return self.check(); + } + + need_bits!(self, 3); + self.last = self.bit_reader.bits(1) != 0; + self.bit_reader.drop_bits(1); + + match self.bit_reader.bits(2) { + 0 => { + // eprintln!("inflate: stored block (last = {last})"); + + self.bit_reader.drop_bits(2); + + self.mode = Mode::Stored; + self.stored() + } + 1 => { + // eprintln!("inflate: fixed codes block (last = {last})"); + + self.len_table = Table { + codes: Codes::Fixed(&self::inffixed_tbl::LENFIX), + bits: 9, + }; + + self.dist_table = Table { + codes: Codes::Fixed(&self::inffixed_tbl::DISTFIX), + bits: 5, + }; + + self.mode = Mode::Len_; + + self.bit_reader.drop_bits(2); + + if let InflateFlush::Trees = self.flush { + self.inflate_leave(ReturnCode::Ok) + } else { + self.len_() + } + } + 2 => { + // eprintln!("inflate: dynamic codes block (last = {last})"); + + self.bit_reader.drop_bits(2); + + self.mode = Mode::Table; + self.table() + } + 3 => { + // eprintln!("inflate: invalid block type"); + + self.bit_reader.drop_bits(2); + + self.mode = Mode::Bad; + self.bad("invalid block type\0") + } + _ => unsafe { core::hint::unreachable_unchecked() }, + } + } + + fn stored(&mut self) -> ReturnCode { + self.bit_reader.next_byte_boundary(); + + need_bits!(self, 32); + + let hold = self.bit_reader.bits(32) as u32; + + // eprintln!("hold {hold:#x}"); + + if hold as u16 != !((hold >> 16) as u16) { + self.mode = Mode::Bad; + return self.bad("invalid stored block lengths\0"); + } + + self.length = hold as usize & 0xFFFF; + // eprintln!("inflate: stored length {}", state.length); + + self.bit_reader.init_bits(); + + if let InflateFlush::Trees = self.flush { + self.inflate_leave(ReturnCode::Ok) + } else { + self.mode = Mode::CopyBlock; + self.copy_block() + } + } + + fn copy_block(&mut self) -> ReturnCode { + loop { + let mut copy = self.length; + + if copy == 0 { + break; + } + + copy = Ord::min(copy, self.writer.remaining()); + copy = Ord::min(copy, self.bit_reader.bytes_remaining()); + + if copy == 0 { + return self.inflate_leave(ReturnCode::Ok); + } + + self.writer.extend(&self.bit_reader.as_slice()[..copy]); + self.bit_reader.advance(copy); + + self.length -= copy; + } + + self.mode = Mode::Type; + self.type_() + } + + fn len_(&mut self) -> ReturnCode { + self.mode = Mode::Len; + self.len() + } + + fn len(&mut self) -> ReturnCode { + let avail_in = self.bit_reader.bytes_remaining(); + let avail_out = self.writer.remaining(); + + // INFLATE_FAST_MIN_LEFT is important. It makes sure there is at least 32 bytes of free + // space available. This means for many SIMD operations we don't need to process a + // remainder; we just copy blindly, and a later operation will overwrite the extra copied + // bytes + if avail_in >= INFLATE_FAST_MIN_HAVE && avail_out >= INFLATE_FAST_MIN_LEFT { + return inflate_fast_help(self, 0); + } + + self.back = 0; + + // get a literal, length, or end-of-block code + let mut here; + loop { + let bits = self.bit_reader.bits(self.len_table.bits); + here = self.len_table_get(bits as usize); + + if here.bits <= self.bit_reader.bits_in_buffer() { + break; + } + + pull_byte!(self); + } + + if here.op != 0 && here.op & 0xf0 == 0 { + let last = here; + loop { + let bits = self.bit_reader.bits((last.bits + last.op) as usize) as u16; + here = self.len_table_get((last.val + (bits >> last.bits)) as usize); + if last.bits + here.bits <= self.bit_reader.bits_in_buffer() { + break; + } + + pull_byte!(self); + } + + self.bit_reader.drop_bits(last.bits as usize); + self.back += last.bits as usize; + } + + self.bit_reader.drop_bits(here.bits as usize); + self.back += here.bits as usize; + self.length = here.val as usize; + + if here.op == 0 { + if self.writer.remaining() == 0 { + self.mode = Mode::Lit; + #[cfg(all(test, feature = "std"))] + eprintln!("Ok: read_buf is full ({} bytes)", self.writer.capacity()); + return self.inflate_leave(ReturnCode::Ok); + } + + self.writer.push(self.length as u8); + + self.mode = Mode::Len; + + self.len() + } else if here.op & 32 != 0 { + // end of block + + // eprintln!("inflate: end of block"); + + self.back = usize::MAX; + self.mode = Mode::Type; + self.type_() + } else if here.op & 64 != 0 { + self.mode = Mode::Bad; + self.bad("invalid literal/length code\0") + } else { + // length code + self.extra = (here.op & MAX_BITS) as usize; + self.mode = Mode::LenExt; + self.len_ext() + } + } + + fn len_ext(&mut self) -> ReturnCode { + let extra = self.extra; + + // get extra bits, if any + if extra != 0 { + need_bits!(self, extra); + self.length += self.bit_reader.bits(extra) as usize; + self.bit_reader.drop_bits(extra); + self.back += extra; + } + + // eprintln!("inflate: length {}", state.length); + + self.was = self.length; + self.mode = Mode::Dist; + self.dist() + } + + fn dist(&mut self) -> ReturnCode { + // get distance code + let mut here; + loop { + let bits = self.bit_reader.bits(self.dist_table.bits) as usize; + here = self.dist_table_get(bits); + if here.bits <= self.bit_reader.bits_in_buffer() { + break; + } + + pull_byte!(self); + } + + if here.op & 0xf0 == 0 { + let last = here; + + loop { + let bits = self.bit_reader.bits((last.bits + last.op) as usize); + here = self.dist_table_get(last.val as usize + ((bits as usize) >> last.bits)); + + if last.bits + here.bits <= self.bit_reader.bits_in_buffer() { + break; + } + + pull_byte!(self); + } + + self.bit_reader.drop_bits(last.bits as usize); + self.back += last.bits as usize; + } + + self.bit_reader.drop_bits(here.bits as usize); + + if here.op & 64 != 0 { + self.mode = Mode::Bad; + return self.bad("invalid distance code\0"); + } + + self.offset = here.val as usize; + + self.extra = (here.op & MAX_BITS) as usize; + self.mode = Mode::DistExt; + self.dist_ext() + } + + fn dist_ext(&mut self) -> ReturnCode { + let extra = self.extra; + + if extra > 0 { + need_bits!(self, extra); + self.offset += self.bit_reader.bits(extra) as usize; + self.bit_reader.drop_bits(extra); + self.back += extra; + } + + if self.offset > self.dmax { + self.mode = Mode::Bad; + return self.bad("invalid distance code too far back\0"); + } + + // eprintln!("inflate: distance {}", state.offset); + + self.mode = Mode::Match; + self.match_() + } + + /// copy match from window to output + + fn match_(&mut self) -> ReturnCode { + if self.writer.remaining() == 0 { + #[cfg(all(feature = "std", test))] + eprintln!( + "BufError: read_buf is full ({} bytes)", + self.writer.capacity() + ); + return self.inflate_leave(ReturnCode::Ok); + } + + // this is not quite right. not sure when that matters + let out = self.writer.remaining() + self.writer.len(); + let left = self.writer.remaining(); + + let copy = out - left; + + let copy = if self.offset > copy { + // copy from window to output + + let mut copy = self.offset - copy; + + if copy > self.window.have() { + if self.sane { + self.mode = Mode::Bad; + return self.bad("invalid distance too far back\0"); + } + + // TODO INFLATE_ALLOW_INVALID_DISTANCE_TOOFAR_ARRR + panic!("INFLATE_ALLOW_INVALID_DISTANCE_TOOFAR_ARRR") + } + + let wnext = self.window.next(); + let wsize = self.window.size(); + + let from = if copy > wnext { + copy -= wnext; + wsize - copy + } else { + wnext - copy + }; + + copy = Ord::min(copy, self.length); + copy = Ord::min(copy, left); + + self.writer.extend(&self.window.as_slice()[from..][..copy]); + + copy + } else { + let copy = Ord::min(self.length, self.writer.remaining()); + self.writer.copy_match(self.offset, copy); + + copy + }; + + self.length -= copy; + + if self.length == 0 { + self.mode = Mode::Len; + self.len() + } else { + // otherwise it seems to recurse? + self.match_() + } + } + + /// get dynamic table entries descriptor + + fn table(&mut self) -> ReturnCode { + need_bits!(self, 14); + self.nlen = self.bit_reader.bits(5) as usize + 257; + self.bit_reader.drop_bits(5); + self.ndist = self.bit_reader.bits(5) as usize + 1; + self.bit_reader.drop_bits(5); + self.ncode = self.bit_reader.bits(4) as usize + 4; + self.bit_reader.drop_bits(4); + + // TODO pkzit_bug_workaround + if self.nlen > 286 || self.ndist > 30 { + self.mode = Mode::Bad; + return self.bad("too many length or distance symbols\0"); + } + + self.have = 0; + self.mode = Mode::LenLens; + self.len_lens() + } + + /// get code length code lengths (not a typo) + + fn len_lens(&mut self) -> ReturnCode { + // permutation of code lengths ; + const ORDER: [u16; 19] = [ + 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15, + ]; + + while self.have < self.ncode { + need_bits!(self, 3); + self.lens[ORDER[self.have] as usize] = self.bit_reader.bits(3) as u16; + self.have += 1; + self.bit_reader.drop_bits(3); + } + + while self.have < 19 { + self.lens[ORDER[self.have] as usize] = 0; + self.have += 1; + } + + self.len_table.bits = 7; + + let InflateTable::Success(root) = inflate_table( + CodeType::Codes, + &self.lens, + 19, + &mut self.codes_codes, + self.len_table.bits, + &mut self.work, + ) else { + self.mode = Mode::Bad; + return self.bad("invalid code lengths set\0"); + }; + + self.len_table.codes = Codes::Codes; + self.len_table.bits = root; + + self.have = 0; + self.mode = Mode::CodeLens; + self.code_lens() + } + + /// get length and distance code code lengths + + fn code_lens(&mut self) -> ReturnCode { + while self.have < self.nlen + self.ndist { + let here = loop { + let bits = self.bit_reader.bits(self.len_table.bits); + let here = self.len_table_get(bits as usize); + if here.bits <= self.bit_reader.bits_in_buffer() { + break here; + } + + pull_byte!(self); + }; + + let here_bits = here.bits as usize; + + match here.val { + 0..=15 => { + self.bit_reader.drop_bits(here_bits); + self.lens[self.have] = here.val; + self.have += 1; + } + 16 => { + need_bits!(self, here_bits + 2); + self.bit_reader.drop_bits(here_bits); + if self.have == 0 { + self.mode = Mode::Bad; + return self.bad("invalid bit length repeat\0"); + } + + let len = self.lens[self.have - 1]; + let copy = 3 + self.bit_reader.bits(2) as usize; + self.bit_reader.drop_bits(2); + + if self.have + copy > self.nlen + self.ndist { + self.mode = Mode::Bad; + return self.bad("invalid bit length repeat\0"); + } + + for _ in 0..copy { + self.lens[self.have] = len; + self.have += 1; + } + } + 17 => { + need_bits!(self, here_bits + 3); + self.bit_reader.drop_bits(here_bits); + let len = 0; + let copy = 3 + self.bit_reader.bits(3) as usize; + self.bit_reader.drop_bits(3); + + if self.have + copy > self.nlen + self.ndist { + self.mode = Mode::Bad; + return self.bad("invalid bit length repeat\0"); + } + + for _ in 0..copy { + self.lens[self.have] = len as u16; + self.have += 1; + } + } + 18.. => { + need_bits!(self, here_bits + 7); + self.bit_reader.drop_bits(here_bits); + let len = 0; + let copy = 11 + self.bit_reader.bits(7) as usize; + self.bit_reader.drop_bits(7); + + if self.have + copy > self.nlen + self.ndist { + self.mode = Mode::Bad; + return self.bad("invalid bit length repeat\0"); + } + + for _ in 0..copy { + self.lens[self.have] = len as u16; + self.have += 1; + } + } + } + } + + // check for end-of-block code (better have one) + if self.lens[256] == 0 { + self.mode = Mode::Bad; + return self.bad("invalid code -- missing end-of-block\0"); + } + + // build code tables + + self.len_table.bits = 10; + + let InflateTable::Success(root) = inflate_table( + CodeType::Lens, + &self.lens, + self.nlen, + &mut self.len_codes, + self.len_table.bits, + &mut self.work, + ) else { + self.mode = Mode::Bad; + return self.bad("invalid literal/lengths set\0"); + }; + + self.len_table.codes = Codes::Len; + self.len_table.bits = root; + + self.dist_table.bits = 9; + + let InflateTable::Success(root) = inflate_table( + CodeType::Dists, + &self.lens[self.nlen..], + self.ndist, + &mut self.dist_codes, + self.dist_table.bits, + &mut self.work, + ) else { + self.mode = Mode::Bad; + return self.bad("invalid distances set\0"); + }; + + self.dist_table.bits = root; + self.dist_table.codes = Codes::Dist; + + self.mode = Mode::Len_; + + if matches!(self.flush, InflateFlush::Trees) { + return self.inflate_leave(ReturnCode::Ok); + } + + self.len_() + } + + fn dict_id(&mut self) -> ReturnCode { + need_bits!(self, 32); + + self.checksum = zswap32(self.bit_reader.hold() as u32); + + self.bit_reader.init_bits(); + + self.mode = Mode::Dict; + self.dict() + } + + fn dict(&mut self) -> ReturnCode { + if !self.havedict { + return self.inflate_leave(ReturnCode::NeedDict); + } + + self.checksum = crate::ADLER32_INITIAL_VALUE as _; + + self.mode = Mode::Type; + self.type_() + } + + fn mem(&mut self) -> ReturnCode { + self.inflate_leave(ReturnCode::MemError) + } + + fn bad(&mut self, msg: &'static str) -> ReturnCode { + #[cfg(all(feature = "std", test))] + dbg!(msg); + self.error_message = Some(msg); + self.inflate_leave(ReturnCode::DataError) + } + + // NOTE: it is crucial for the internal bookkeeping that this is the only route for actually + // leaving the inflate function call chain + fn inflate_leave(&mut self, return_code: ReturnCode) -> ReturnCode { + // actual logic is in `inflate` itself + return_code + } + + /// Stored in the `z_stream.data_type` field + fn decoding_state(&self) -> i32 { + let bit_reader_bits = self.bit_reader.bits_in_buffer() as i32; + debug_assert!(bit_reader_bits < 64); + + let last = if self.last { 64 } else { 0 }; + + let mode = match self.mode { + Mode::Type => 128, + Mode::Len_ | Mode::CopyBlock => 256, + _ => 0, + }; + + bit_reader_bits | last | mode + } +} + +fn inflate_fast_help(state: &mut State, _start: usize) -> ReturnCode { + let mut bit_reader = BitReader::new(&[]); + core::mem::swap(&mut bit_reader, &mut state.bit_reader); + + let mut writer = ReadBuf::new(&mut []); + core::mem::swap(&mut writer, &mut state.writer); + + let lcode = state.len_table_ref(); + let dcode = state.dist_table_ref(); + + // IDEA: use const generics for the bits here? + let lmask = (1u64 << state.len_table.bits) - 1; + let dmask = (1u64 << state.dist_table.bits) - 1; + + // TODO verify if this is relevant for us + let extra_safe = false; + + let window_size = state.window.size(); + + let mut bad = None; + + if bit_reader.bits_in_buffer() < 10 { + bit_reader.refill(); + } + + 'outer: loop { + let mut here = bit_reader.refill_and(|hold| lcode[(hold & lmask) as usize]); + + if here.op == 0 { + writer.push(here.val as u8); + bit_reader.drop_bits(here.bits as usize); + here = lcode[(bit_reader.hold() & lmask) as usize]; + + if here.op == 0 { + writer.push(here.val as u8); + bit_reader.drop_bits(here.bits as usize); + here = lcode[(bit_reader.hold() & lmask) as usize]; + } + } + + 'dolen: loop { + bit_reader.drop_bits(here.bits as usize); + let op = here.op; + + if op == 0 { + writer.push(here.val as u8); + } else if op & 16 != 0 { + let op = op & MAX_BITS; + let mut len = here.val + bit_reader.bits(op as usize) as u16; + bit_reader.drop_bits(op as usize); + + here = dcode[(bit_reader.hold() & dmask) as usize]; + + // we have two fast-path loads: 10+10 + 15+5 = 40, + // but we may need to refill here in the worst case + if bit_reader.bits_in_buffer() < MAX_BITS + MAX_DIST_EXTRA_BITS { + bit_reader.refill(); + } + + 'dodist: loop { + bit_reader.drop_bits(here.bits as usize); + let op = here.op; + + if op & 16 != 0 { + let op = op & MAX_BITS; + let dist = here.val + bit_reader.bits(op as usize) as u16; + + if dist as usize > state.dmax { + bad = Some("invalid distance too far back\0"); + state.mode = Mode::Bad; + break 'outer; + } + + bit_reader.drop_bits(op as usize); + + // max distance in output + let written = writer.len(); + + if dist as usize > written { + // copy fropm the window + if (dist as usize - written) > state.window.have() { + if state.sane { + bad = Some("invalid distance too far back\0"); + state.mode = Mode::Bad; + break 'outer; + } + + panic!("INFLATE_ALLOW_INVALID_DISTANCE_TOOFAR_ARRR") + } + + let mut op = dist as usize - written; + let mut from; + + let window_next = state.window.next(); + + if window_next == 0 { + // This case is hit when the window has just wrapped around + // by logic in `Window::extend`. It is special-cased because + // apparently this is quite common. + // + // the match is at the end of the window, even though the next + // position has now wrapped around. + from = window_size - op; + } else if window_next >= op { + // the standard case: a contiguous copy from the window, no wrapping + from = window_next - op; + } else { + // This case is hit when the window has recently wrapped around + // by logic in `Window::extend`. + // + // The match is (partially) at the end of the window + op -= window_next; + from = window_size - op; + + if op < len as usize { + // This case is hit when part of the match is at the end of the + // window, and part of it has wrapped around to the start. Copy + // the end section here, the start section will be copied below. + len -= op as u16; + writer.extend(&state.window.as_slice()[from..][..op]); + from = 0; + op = window_next; + } + } + + let copy = Ord::min(op, len as usize); + writer.extend(&state.window.as_slice()[from..][..copy]); + + if op < len as usize { + // here we need some bytes from the output itself + writer.copy_match(dist as usize, len as usize - op); + } + } else if extra_safe { + todo!() + } else { + writer.copy_match(dist as usize, len as usize) + } + } else if (op & 64) == 0 { + // 2nd level distance code + here = dcode[(here.val + bit_reader.bits(op as usize) as u16) as usize]; + continue 'dodist; + } else { + bad = Some("invalid distance code\0"); + state.mode = Mode::Bad; + break 'outer; + } + + break 'dodist; + } + } else if (op & 64) == 0 { + // 2nd level length code + here = lcode[(here.val + bit_reader.bits(op as usize) as u16) as usize]; + continue 'dolen; + } else if op & 32 != 0 { + // end of block + state.mode = Mode::Type; + break 'outer; + } else { + bad = Some("invalid literal/length code\0"); + state.mode = Mode::Bad; + break 'outer; + } + + break 'dolen; + } + + let remaining = bit_reader.bytes_remaining(); + if remaining.saturating_sub(INFLATE_FAST_MIN_LEFT - 1) > 0 + && writer.remaining() > INFLATE_FAST_MIN_LEFT + { + continue; + } + + break 'outer; + } + + // return unused bytes (on entry, bits < 8, so in won't go too far back) + bit_reader.return_unused_bytes(); + + state.bit_reader = bit_reader; + state.writer = writer; + + match state.mode { + Mode::Type => state.type_(), + Mode::Len => state.len(), + Mode::Bad => state.bad(bad.unwrap()), + _ => unreachable!(), + } +} + +pub fn prime(stream: &mut InflateStream, bits: i32, value: i32) -> ReturnCode { + if bits == 0 { + /* fall through */ + } else if bits < 0 { + stream.state.bit_reader.init_bits(); + } else if bits > 16 || stream.state.bit_reader.bits_in_buffer() + bits as u8 > 32 { + return ReturnCode::StreamError; + } else { + stream.state.bit_reader.prime(bits as u8, value as u64); + } + + ReturnCode::Ok +} + +#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq)] +pub struct InflateConfig { + pub window_bits: i32, +} + +impl Default for InflateConfig { + fn default() -> Self { + Self { + window_bits: DEF_WBITS, + } + } +} + +/// Initialize the stream in an inflate state +pub fn init(stream: &mut z_stream, config: InflateConfig) -> ReturnCode { + stream.msg = core::ptr::null_mut(); + + // for safety we must really make sure that alloc and free are consistent + // this is a (slight) deviation from stock zlib. In this crate we pick the rust + // allocator as the default, but `libz-rs-sys` configures the C allocator + #[cfg(feature = "rust-allocator")] + if stream.zalloc.is_none() || stream.zfree.is_none() { + stream.configure_default_rust_allocator() + } + + #[cfg(feature = "c-allocator")] + if stream.zalloc.is_none() || stream.zfree.is_none() { + stream.configure_default_c_allocator() + } + + if stream.zalloc.is_none() || stream.zfree.is_none() { + return ReturnCode::StreamError; + } + + let mut state = State::new(&[], ReadBuf::new(&mut [])); + + // TODO this can change depending on the used/supported SIMD instructions + state.chunksize = 32; + + let alloc = Allocator { + zalloc: stream.zalloc.unwrap(), + zfree: stream.zfree.unwrap(), + opaque: stream.opaque, + _marker: PhantomData, + }; + + // allocated here to have the same order as zlib + let Some(state_allocation) = alloc.allocate::() else { + return ReturnCode::MemError; + }; + + stream.state = state_allocation.write(state) as *mut _ as *mut internal_state; + + // SAFETY: we've correctly initialized the stream to be an InflateStream + let ret = if let Some(stream) = unsafe { InflateStream::from_stream_mut(stream) } { + reset_with_config(stream, config) + } else { + ReturnCode::StreamError + }; + + if ret != ReturnCode::Ok { + let ptr = stream.state; + stream.state = core::ptr::null_mut(); + // SAFETY: we assume deallocation does not cause UB + unsafe { alloc.deallocate(ptr, 1) }; + } + + ret +} + +pub fn reset_with_config(stream: &mut InflateStream, config: InflateConfig) -> ReturnCode { + let mut window_bits = config.window_bits; + let wrap; + + if window_bits < 0 { + wrap = 0; + + if window_bits < -MAX_WBITS { + return ReturnCode::StreamError; + } + + window_bits = -window_bits; + } else { + wrap = (window_bits >> 4) + 5; // TODO wth? + + if window_bits < 48 { + window_bits &= MAX_WBITS; + } + } + + if window_bits != 0 && !(MIN_WBITS..=MAX_WBITS).contains(&window_bits) { + #[cfg(feature = "std")] + eprintln!("invalid windowBits"); + return ReturnCode::StreamError; + } + + if stream.state.window.size() != 0 && stream.state.wbits != window_bits as usize { + let mut window = Window::empty(); + core::mem::swap(&mut window, &mut stream.state.window); + + let window = window.into_inner(); + assert!(!window.is_empty()); + unsafe { stream.alloc.deallocate(window.as_mut_ptr(), window.len()) }; + } + + stream.state.wrap = wrap as usize; + stream.state.wbits = window_bits as _; + + reset(stream) +} + +pub fn reset(stream: &mut InflateStream) -> ReturnCode { + // reset the state of the window + stream.state.window.clear(); + + stream.state.error_message = None; + + reset_keep(stream) +} + +pub fn reset_keep(stream: &mut InflateStream) -> ReturnCode { + stream.total_in = 0; + stream.total_out = 0; + stream.state.total = 0; + + stream.msg = core::ptr::null_mut(); + + let state = &mut stream.state; + + if state.wrap != 0 { + // to support ill-conceived Java test suite + stream.adler = (state.wrap & 1) as _; + } + + state.mode = Mode::Head; + state.checksum = crate::ADLER32_INITIAL_VALUE as u32; + + state.last = false; + state.havedict = false; + state.flags = -1; + state.dmax = 32768; + state.head = None; + state.bit_reader = BitReader::new(&[]); + + state.next = 0; + state.len_table = Table::default(); + state.dist_table = Table::default(); + + state.sane = true; + state.back = usize::MAX; + + ReturnCode::Ok +} + +pub unsafe fn inflate(stream: &mut InflateStream, flush: InflateFlush) -> ReturnCode { + if stream.next_out.is_null() || (stream.next_in.is_null() && stream.avail_in != 0) { + return ReturnCode::StreamError as _; + } + + let source_slice = core::slice::from_raw_parts(stream.next_in, stream.avail_in as usize); + let dest_slice = core::slice::from_raw_parts_mut(stream.next_out, stream.avail_out as usize); + + let state = &mut stream.state; + + // skip check + if let Mode::Type = state.mode { + state.mode = Mode::TypeDo; + } + + state.flush = flush; + + state.bit_reader.update_slice(source_slice); + state.writer = ReadBuf::new(dest_slice); + + state.in_available = stream.avail_in as _; + state.out_available = stream.avail_out as _; + + let mut err = state.dispatch(); + + let in_read = state.bit_reader.as_ptr() as usize - stream.next_in as usize; + let out_written = state.writer.next_out() as usize - stream.next_out as usize; + + stream.total_in += in_read as z_size; + stream.total_out += out_written as z_size; + state.total += out_written; + + stream.avail_in = state.bit_reader.bytes_remaining() as u32; + stream.next_in = state.bit_reader.as_ptr() as *mut u8; + + stream.avail_out = (state.writer.capacity() - state.writer.len()) as u32; + stream.next_out = state.writer.next_out() as *mut u8; + + stream.adler = state.checksum as z_checksum; + + let valid_mode = |mode| !matches!(mode, Mode::Bad | Mode::Mem | Mode::Sync); + let not_done = |mode| { + !matches!( + mode, + Mode::Check | Mode::Length | Mode::Bad | Mode::Mem | Mode::Sync + ) + }; + + let must_update_window = state.window.size() != 0 + || (out_written != 0 + && valid_mode(state.mode) + && (not_done(state.mode) || !matches!(state.flush, InflateFlush::Finish))); + + let update_checksum = state.wrap & 4 != 0; + + if must_update_window { + 'blk: { + // initialize the window if needed + if state.window.size() == 0 { + match Window::new_in(&stream.alloc, state.wbits) { + Some(window) => state.window = window, + None => { + state.mode = Mode::Mem; + err = ReturnCode::MemError; + break 'blk; + } + } + } + + state.window.extend( + &state.writer.filled()[..out_written], + state.flags, + update_checksum, + &mut state.checksum, + &mut state.crc_fold, + ); + } + } + + if let Some(msg) = state.error_message { + assert!(msg.ends_with(|c| c == '\0')); + stream.msg = msg.as_ptr() as *mut u8 as *mut core::ffi::c_char; + } + + stream.data_type = state.decoding_state(); + + if ((in_read == 0 && out_written == 0) || flush == InflateFlush::Finish as _) + && err == (ReturnCode::Ok as _) + { + ReturnCode::BufError as _ + } else { + err as _ + } +} + +fn syncsearch(mut got: usize, buf: &[u8]) -> (usize, usize) { + let len = buf.len(); + let mut next = 0; + + while next < len && got < 4 { + if buf[next] == if got < 2 { 0 } else { 0xff } { + got += 1; + } else if buf[next] != 0 { + got = 0; + } else { + got = 4 - got; + } + next += 1; + } + + (got, next) +} + +pub fn sync(stream: &mut InflateStream) -> ReturnCode { + let state = &mut stream.state; + + if stream.avail_in == 0 && state.bit_reader.bits_in_buffer() < 8 { + return ReturnCode::BufError; + } + /* if first time, start search in bit buffer */ + if !matches!(state.mode, Mode::Sync) { + state.mode = Mode::Sync; + + let (buf, len) = state.bit_reader.start_sync_search(); + + (state.have, _) = syncsearch(0, &buf[..len]); + } + + // search available input + let slice = unsafe { core::slice::from_raw_parts(stream.next_in, stream.avail_in as usize) }; + + let len; + (state.have, len) = syncsearch(state.have, slice); + stream.next_in = unsafe { stream.next_in.add(len) }; + stream.avail_in -= len as u32; + stream.total_in += len as z_size; + + /* return no joy or set up to restart inflate() on a new block */ + if state.have != 4 { + return ReturnCode::DataError; + } + + if state.flags == -1 { + state.wrap = 0; /* if no header yet, treat as raw */ + } else { + state.wrap &= !4; /* no point in computing a check value now */ + } + + let flags = state.flags; + let total_in = stream.total_in; + let total_out = stream.total_out; + + reset(stream); + + stream.total_in = total_in; + stream.total_out = total_out; + + stream.state.flags = flags; + stream.state.mode = Mode::Type; + + ReturnCode::Ok +} + +/* + Returns true if inflate is currently at the end of a block generated by + Z_SYNC_FLUSH or Z_FULL_FLUSH. This function is used by one PPP + implementation to provide an additional safety check. PPP uses + Z_SYNC_FLUSH but removes the length bytes of the resulting empty stored + block. When decompressing, PPP checks that at the end of input packet, + inflate is waiting for these length bytes. +*/ +pub fn sync_point(stream: &mut InflateStream) -> bool { + matches!(stream.state.mode, Mode::Stored) && stream.state.bit_reader.bits_in_buffer() == 0 +} + +pub unsafe fn copy<'a>( + dest: &mut MaybeUninit>, + source: &InflateStream<'a>, +) -> ReturnCode { + if source.next_out.is_null() || (source.next_in.is_null() && source.avail_in != 0) { + return ReturnCode::StreamError; + } + + // Safety: source and dest are both mutable references, so guaranteed not to overlap. + // dest being a reference to maybe uninitialized memory makes a copy of 1 DeflateStream valid. + unsafe { + core::ptr::copy_nonoverlapping(source, dest.as_mut_ptr(), 1); + } + + // allocated here to have the same order as zlib + let Some(state_allocation) = source.alloc.allocate::() else { + return ReturnCode::MemError; + }; + + let state = &source.state; + + let writer: MaybeUninit = + unsafe { core::ptr::read(&state.writer as *const _ as *const MaybeUninit) }; + + let mut copy = State { + mode: state.mode, + last: state.last, + wrap: state.wrap, + len_table: state.len_table, + dist_table: state.dist_table, + wbits: state.wbits, + window: Window::empty(), + head: None, + ncode: state.ncode, + nlen: state.nlen, + ndist: state.ndist, + have: state.have, + next: state.next, + bit_reader: state.bit_reader, + writer: ReadBuf::new(&mut []), + total: state.total, + length: state.length, + offset: state.offset, + extra: state.extra, + sane: state.sane, + back: state.back, + was: state.was, + chunksize: state.chunksize, + in_available: state.in_available, + out_available: state.out_available, + lens: state.lens, + work: state.work, + error_message: state.error_message, + flush: state.flush, + checksum: state.checksum, + crc_fold: state.crc_fold, + havedict: state.havedict, + dmax: state.dmax, + flags: state.flags, + codes_codes: state.codes_codes, + len_codes: state.len_codes, + dist_codes: state.dist_codes, + }; + + if !state.window.is_empty() { + let Some(window) = state.window.clone_in(&source.alloc) else { + source.alloc.deallocate(state_allocation.as_mut_ptr(), 1); + return ReturnCode::MemError; + }; + + copy.window = window; + } + + // write the cloned state into state_ptr + let state_ptr = state_allocation.write(copy); + + // insert the state_ptr into `dest` + let field_ptr = unsafe { core::ptr::addr_of_mut!((*dest.as_mut_ptr()).state) }; + unsafe { core::ptr::write(field_ptr as *mut *mut State, state_ptr) }; + + // update the writer; it cannot be cloned so we need to use some shennanigans + let field_ptr = unsafe { core::ptr::addr_of_mut!((*dest.as_mut_ptr()).state.writer) }; + unsafe { core::ptr::copy(writer.as_ptr(), field_ptr, 1) }; + + // update the gzhead field (it contains a mutable reference so we need to be careful + let field_ptr = unsafe { core::ptr::addr_of_mut!((*dest.as_mut_ptr()).state.head) }; + unsafe { core::ptr::copy(&source.state.head, field_ptr, 1) }; + + ReturnCode::Ok +} + +pub fn undermine(stream: &mut InflateStream, subvert: i32) -> ReturnCode { + stream.state.sane = (!subvert) != 0; + + ReturnCode::Ok +} + +pub fn mark(stream: &InflateStream) -> c_long { + if stream.next_out.is_null() || (stream.next_in.is_null() && stream.avail_in != 0) { + return c_long::MIN; + } + + let state = &stream.state; + + let length = match state.mode { + Mode::CopyBlock => state.length, + Mode::Match => state.was - state.length, + _ => 0, + }; + + (((state.back as c_long) as c_ulong) << 16) as c_long + length as c_long +} + +pub fn set_dictionary(stream: &mut InflateStream, dictionary: &[u8]) -> ReturnCode { + if stream.state.wrap != 0 && !matches!(stream.state.mode, Mode::Dict) { + return ReturnCode::StreamError; + } + + // check for correct dictionary identifier + if matches!(stream.state.mode, Mode::Dict) { + let dictid = adler32(1, dictionary); + + if dictid != stream.state.checksum { + return ReturnCode::DataError; + } + } + + let err = 'blk: { + // initialize the window if needed + if stream.state.window.size() == 0 { + match Window::new_in(&stream.alloc, stream.state.wbits) { + None => break 'blk ReturnCode::MemError, + Some(window) => stream.state.window = window, + } + } + + stream.state.window.extend( + dictionary, + stream.state.flags, + false, + &mut stream.state.checksum, + &mut stream.state.crc_fold, + ); + + ReturnCode::Ok + }; + + if err != ReturnCode::Ok { + stream.state.mode = Mode::Mem; + return ReturnCode::MemError; + } + + stream.state.havedict = true; + + ReturnCode::Ok +} + +pub fn end<'a>(stream: &'a mut InflateStream) -> &'a mut z_stream { + let mut state = State::new(&[], ReadBuf::new(&mut [])); + core::mem::swap(&mut state, stream.state); + + let mut window = Window::empty(); + core::mem::swap(&mut window, &mut state.window); + + let alloc = stream.alloc; + + // safety: window is not used again + if !window.is_empty() { + let window = window.into_inner(); + unsafe { alloc.deallocate(window.as_mut_ptr(), window.len()) }; + } + + let stream = stream.as_z_stream_mut(); + + let state_ptr = core::mem::replace(&mut stream.state, core::ptr::null_mut()); + + // safety: state_ptr is not used again + unsafe { alloc.deallocate(state_ptr as *mut State, 1) }; + + stream +} + +pub fn get_header<'a>( + stream: &mut InflateStream<'a>, + head: Option<&'a mut gz_header>, +) -> ReturnCode { + if (stream.state.wrap & 2) == 0 { + return ReturnCode::StreamError; + } + + stream.state.head = head.map(|head| { + head.done = 0; + head + }); + ReturnCode::Ok +} +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn uncompress_buffer_overflow() { + let mut output = [0; 1 << 13]; + let input = [ + 72, 137, 58, 0, 3, 39, 255, 255, 255, 255, 255, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 184, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 184, 14, 14, + 14, 14, 14, 14, 14, 63, 14, 14, 14, 14, 14, 14, 14, 14, 184, 14, 14, 255, 14, 103, 14, + 14, 14, 14, 14, 14, 61, 14, 255, 255, 63, 14, 14, 14, 14, 14, 14, 14, 14, 184, 14, 14, + 255, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 6, 14, 14, 14, 14, 14, 14, 14, 14, 71, + 4, 137, 106, + ]; + + let config = InflateConfig { window_bits: 15 }; + + let (_decompressed, err) = uncompress_slice(&mut output, &input, config); + assert_eq!(err, ReturnCode::DataError); + } +} diff --git a/third_party/rust/zlib-rs/src/inflate/bitreader.rs b/third_party/rust/zlib-rs/src/inflate/bitreader.rs new file mode 100644 index 000000000000..7622f35de22c --- /dev/null +++ b/third_party/rust/zlib-rs/src/inflate/bitreader.rs @@ -0,0 +1,203 @@ +use core::marker::PhantomData; + +use crate::ReturnCode; + +#[derive(Debug, Clone, Copy)] +pub(crate) struct BitReader<'a> { + ptr: *const u8, + end: *const u8, + bit_buffer: u64, + bits_used: u8, + _marker: PhantomData<&'a [u8]>, +} + +impl<'a> BitReader<'a> { + pub fn new(slice: &'a [u8]) -> Self { + let range = slice.as_ptr_range(); + + Self { + ptr: range.start, + end: range.end, + bit_buffer: 0, + bits_used: 0, + _marker: PhantomData, + } + } + + #[inline(always)] + pub fn update_slice(&mut self, slice: &[u8]) { + let range = slice.as_ptr_range(); + + *self = Self { + ptr: range.start, + end: range.end, + bit_buffer: self.bit_buffer, + bits_used: self.bits_used, + _marker: PhantomData, + }; + } + + #[inline(always)] + pub fn advance(&mut self, bytes: usize) { + self.ptr = Ord::min(unsafe { self.ptr.add(bytes) }, self.end); + } + + #[inline(always)] + pub fn as_ptr(&self) -> *const u8 { + self.ptr + } + + #[inline(always)] + pub fn as_slice(&self) -> &[u8] { + let len = self.bytes_remaining(); + unsafe { core::slice::from_raw_parts(self.ptr, len) } + } + + #[inline(always)] + pub fn bits_in_buffer(&self) -> u8 { + self.bits_used + } + + #[inline(always)] + pub fn hold(&self) -> u64 { + self.bit_buffer + } + + #[inline(always)] + pub fn bytes_remaining(&self) -> usize { + self.end as usize - self.ptr as usize + } + + #[inline(always)] + pub fn need_bits(&mut self, n: usize) -> Result<(), ReturnCode> { + while (self.bits_used as usize) < n { + self.pull_byte()?; + } + + Ok(()) + } + + /// Remove zero to seven bits as needed to go to a byte boundary + #[inline(always)] + pub fn next_byte_boundary(&mut self) { + self.bit_buffer >>= self.bits_used & 0b0111; + self.bits_used -= self.bits_used & 0b0111; + } + + #[inline(always)] + pub fn pull_byte(&mut self) -> Result { + if self.ptr == self.end { + return Err(ReturnCode::Ok); + } + + let byte = unsafe { *self.ptr }; + self.ptr = unsafe { self.ptr.add(1) }; + + self.bit_buffer |= (byte as u64) << self.bits_used; + self.bits_used += 8; + + Ok(byte) + } + + #[inline(always)] + pub fn refill(&mut self) { + debug_assert!(self.bytes_remaining() >= 8); + + let read = unsafe { core::ptr::read_unaligned(self.ptr.cast::()) }; + self.bit_buffer |= read << self.bits_used; + let increment = (63 - self.bits_used) >> 3; + self.ptr = self.ptr.wrapping_add(increment as usize); + self.bits_used |= 56; + } + + #[inline(always)] + pub fn refill_and(&mut self, f: impl Fn(u64) -> T) -> T { + debug_assert!(self.bytes_remaining() >= 8); + + // the trick of this function is that the read can happen concurrently + // with the arithmetic below. That makes the read effectively free. + let read = unsafe { core::ptr::read_unaligned(self.ptr.cast::()) }; + let next_bit_buffer = self.bit_buffer | read << self.bits_used; + + let increment = (63 - self.bits_used) >> 3; + self.ptr = self.ptr.wrapping_add(increment as usize); + self.bits_used |= 56; + + let result = f(self.bit_buffer); + + self.bit_buffer = next_bit_buffer; + + result + } + + #[inline(always)] + pub fn bits(&mut self, n: usize) -> u64 { + // debug_assert!( n <= self.bits_used, "{n} bits requested, but only {} avaliable", self.bits_used); + + let lowest_n_bits = (1 << n) - 1; + self.bit_buffer & lowest_n_bits + } + + #[inline(always)] + pub fn drop_bits(&mut self, n: usize) { + self.bit_buffer >>= n; + self.bits_used -= n as u8; + } + + #[inline(always)] + pub fn start_sync_search(&mut self) -> ([u8; 4], usize) { + let mut buf = [0u8; 4]; + + self.bit_buffer <<= self.bits_used & 7; + self.bits_used -= self.bits_used & 7; + + let mut len = 0; + while self.bits_used >= 8 { + buf[len] = self.bit_buffer as u8; + len += 1; + self.bit_buffer >>= 8; + self.bits_used -= 8; + } + + (buf, len) + } + + #[inline(always)] + pub fn init_bits(&mut self) { + self.bit_buffer = 0; + self.bits_used = 0; + } + + #[inline(always)] + pub fn prime(&mut self, bits: u8, value: u64) { + let value = value & ((1 << bits) - 1); + self.bit_buffer += value << self.bits_used; + self.bits_used += bits; + } + + #[inline(always)] + pub fn return_unused_bytes(&mut self) { + let len = self.bits_used >> 3; + self.ptr = unsafe { self.ptr.sub(len as usize) }; + self.bits_used -= len << 3; + self.bit_buffer &= (1u64 << self.bits_used) - 1u64; + + assert!(self.bits_used <= 32); + } +} + +#[cfg(feature = "std")] +impl std::io::Read for BitReader<'_> { + fn read(&mut self, buf: &mut [u8]) -> std::io::Result { + assert_eq!(self.bits_used, 0, "bit buffer not cleared before read"); + + let number_of_bytes = Ord::min(buf.len(), self.bytes_remaining()); + + // safety: `buf` is a mutable (exclusive) reference, so it cannot overlap the memory that + // the reader contains + unsafe { core::ptr::copy_nonoverlapping(self.ptr, buf.as_mut_ptr(), number_of_bytes) } + + self.ptr = unsafe { self.ptr.add(number_of_bytes) }; + Ok(number_of_bytes) + } +} diff --git a/third_party/rust/zlib-rs/src/inflate/inffixed_tbl.rs b/third_party/rust/zlib-rs/src/inflate/inffixed_tbl.rs new file mode 100644 index 000000000000..4bb2a9eac83d --- /dev/null +++ b/third_party/rust/zlib-rs/src/inflate/inffixed_tbl.rs @@ -0,0 +1,555 @@ +use crate::Code; + +const fn code(op: u8, bits: u8, val: u16) -> Code { + Code { op, bits, val } +} + +pub(crate) const LENFIX: [Code; 512] = [ + code(96, 7, 0), + code(0, 8, 80), + code(0, 8, 16), + code(20, 8, 115), + code(18, 7, 31), + code(0, 8, 112), + code(0, 8, 48), + code(0, 9, 192), + code(16, 7, 10), + code(0, 8, 96), + code(0, 8, 32), + code(0, 9, 160), + code(0, 8, 0), + code(0, 8, 128), + code(0, 8, 64), + code(0, 9, 224), + code(16, 7, 6), + code(0, 8, 88), + code(0, 8, 24), + code(0, 9, 144), + code(19, 7, 59), + code(0, 8, 120), + code(0, 8, 56), + code(0, 9, 208), + code(17, 7, 17), + code(0, 8, 104), + code(0, 8, 40), + code(0, 9, 176), + code(0, 8, 8), + code(0, 8, 136), + code(0, 8, 72), + code(0, 9, 240), + code(16, 7, 4), + code(0, 8, 84), + code(0, 8, 20), + code(21, 8, 227), + code(19, 7, 43), + code(0, 8, 116), + code(0, 8, 52), + code(0, 9, 200), + code(17, 7, 13), + code(0, 8, 100), + code(0, 8, 36), + code(0, 9, 168), + code(0, 8, 4), + code(0, 8, 132), + code(0, 8, 68), + code(0, 9, 232), + code(16, 7, 8), + code(0, 8, 92), + code(0, 8, 28), + code(0, 9, 152), + code(20, 7, 83), + code(0, 8, 124), + code(0, 8, 60), + code(0, 9, 216), + code(18, 7, 23), + code(0, 8, 108), + code(0, 8, 44), + code(0, 9, 184), + code(0, 8, 12), + code(0, 8, 140), + code(0, 8, 76), + code(0, 9, 248), + code(16, 7, 3), + code(0, 8, 82), + code(0, 8, 18), + code(21, 8, 163), + code(19, 7, 35), + code(0, 8, 114), + code(0, 8, 50), + code(0, 9, 196), + code(17, 7, 11), + code(0, 8, 98), + code(0, 8, 34), + code(0, 9, 164), + code(0, 8, 2), + code(0, 8, 130), + code(0, 8, 66), + code(0, 9, 228), + code(16, 7, 7), + code(0, 8, 90), + code(0, 8, 26), + code(0, 9, 148), + code(20, 7, 67), + code(0, 8, 122), + code(0, 8, 58), + code(0, 9, 212), + code(18, 7, 19), + code(0, 8, 106), + code(0, 8, 42), + code(0, 9, 180), + code(0, 8, 10), + code(0, 8, 138), + code(0, 8, 74), + code(0, 9, 244), + code(16, 7, 5), + code(0, 8, 86), + code(0, 8, 22), + code(64, 8, 0), + code(19, 7, 51), + code(0, 8, 118), + code(0, 8, 54), + code(0, 9, 204), + code(17, 7, 15), + code(0, 8, 102), + code(0, 8, 38), + code(0, 9, 172), + code(0, 8, 6), + code(0, 8, 134), + code(0, 8, 70), + code(0, 9, 236), + code(16, 7, 9), + code(0, 8, 94), + code(0, 8, 30), + code(0, 9, 156), + code(20, 7, 99), + code(0, 8, 126), + code(0, 8, 62), + code(0, 9, 220), + code(18, 7, 27), + code(0, 8, 110), + code(0, 8, 46), + code(0, 9, 188), + code(0, 8, 14), + code(0, 8, 142), + code(0, 8, 78), + code(0, 9, 252), + code(96, 7, 0), + code(0, 8, 81), + code(0, 8, 17), + code(21, 8, 131), + code(18, 7, 31), + code(0, 8, 113), + code(0, 8, 49), + code(0, 9, 194), + code(16, 7, 10), + code(0, 8, 97), + code(0, 8, 33), + code(0, 9, 162), + code(0, 8, 1), + code(0, 8, 129), + code(0, 8, 65), + code(0, 9, 226), + code(16, 7, 6), + code(0, 8, 89), + code(0, 8, 25), + code(0, 9, 146), + code(19, 7, 59), + code(0, 8, 121), + code(0, 8, 57), + code(0, 9, 210), + code(17, 7, 17), + code(0, 8, 105), + code(0, 8, 41), + code(0, 9, 178), + code(0, 8, 9), + code(0, 8, 137), + code(0, 8, 73), + code(0, 9, 242), + code(16, 7, 4), + code(0, 8, 85), + code(0, 8, 21), + code(16, 8, 258), + code(19, 7, 43), + code(0, 8, 117), + code(0, 8, 53), + code(0, 9, 202), + code(17, 7, 13), + code(0, 8, 101), + code(0, 8, 37), + code(0, 9, 170), + code(0, 8, 5), + code(0, 8, 133), + code(0, 8, 69), + code(0, 9, 234), + code(16, 7, 8), + code(0, 8, 93), + code(0, 8, 29), + code(0, 9, 154), + code(20, 7, 83), + code(0, 8, 125), + code(0, 8, 61), + code(0, 9, 218), + code(18, 7, 23), + code(0, 8, 109), + code(0, 8, 45), + code(0, 9, 186), + code(0, 8, 13), + code(0, 8, 141), + code(0, 8, 77), + code(0, 9, 250), + code(16, 7, 3), + code(0, 8, 83), + code(0, 8, 19), + code(21, 8, 195), + code(19, 7, 35), + code(0, 8, 115), + code(0, 8, 51), + code(0, 9, 198), + code(17, 7, 11), + code(0, 8, 99), + code(0, 8, 35), + code(0, 9, 166), + code(0, 8, 3), + code(0, 8, 131), + code(0, 8, 67), + code(0, 9, 230), + code(16, 7, 7), + code(0, 8, 91), + code(0, 8, 27), + code(0, 9, 150), + code(20, 7, 67), + code(0, 8, 123), + code(0, 8, 59), + code(0, 9, 214), + code(18, 7, 19), + code(0, 8, 107), + code(0, 8, 43), + code(0, 9, 182), + code(0, 8, 11), + code(0, 8, 139), + code(0, 8, 75), + code(0, 9, 246), + code(16, 7, 5), + code(0, 8, 87), + code(0, 8, 23), + code(64, 8, 0), + code(19, 7, 51), + code(0, 8, 119), + code(0, 8, 55), + code(0, 9, 206), + code(17, 7, 15), + code(0, 8, 103), + code(0, 8, 39), + code(0, 9, 174), + code(0, 8, 7), + code(0, 8, 135), + code(0, 8, 71), + code(0, 9, 238), + code(16, 7, 9), + code(0, 8, 95), + code(0, 8, 31), + code(0, 9, 158), + code(20, 7, 99), + code(0, 8, 127), + code(0, 8, 63), + code(0, 9, 222), + code(18, 7, 27), + code(0, 8, 111), + code(0, 8, 47), + code(0, 9, 190), + code(0, 8, 15), + code(0, 8, 143), + code(0, 8, 79), + code(0, 9, 254), + code(96, 7, 0), + code(0, 8, 80), + code(0, 8, 16), + code(20, 8, 115), + code(18, 7, 31), + code(0, 8, 112), + code(0, 8, 48), + code(0, 9, 193), + code(16, 7, 10), + code(0, 8, 96), + code(0, 8, 32), + code(0, 9, 161), + code(0, 8, 0), + code(0, 8, 128), + code(0, 8, 64), + code(0, 9, 225), + code(16, 7, 6), + code(0, 8, 88), + code(0, 8, 24), + code(0, 9, 145), + code(19, 7, 59), + code(0, 8, 120), + code(0, 8, 56), + code(0, 9, 209), + code(17, 7, 17), + code(0, 8, 104), + code(0, 8, 40), + code(0, 9, 177), + code(0, 8, 8), + code(0, 8, 136), + code(0, 8, 72), + code(0, 9, 241), + code(16, 7, 4), + code(0, 8, 84), + code(0, 8, 20), + code(21, 8, 227), + code(19, 7, 43), + code(0, 8, 116), + code(0, 8, 52), + code(0, 9, 201), + code(17, 7, 13), + code(0, 8, 100), + code(0, 8, 36), + code(0, 9, 169), + code(0, 8, 4), + code(0, 8, 132), + code(0, 8, 68), + code(0, 9, 233), + code(16, 7, 8), + code(0, 8, 92), + code(0, 8, 28), + code(0, 9, 153), + code(20, 7, 83), + code(0, 8, 124), + code(0, 8, 60), + code(0, 9, 217), + code(18, 7, 23), + code(0, 8, 108), + code(0, 8, 44), + code(0, 9, 185), + code(0, 8, 12), + code(0, 8, 140), + code(0, 8, 76), + code(0, 9, 249), + code(16, 7, 3), + code(0, 8, 82), + code(0, 8, 18), + code(21, 8, 163), + code(19, 7, 35), + code(0, 8, 114), + code(0, 8, 50), + code(0, 9, 197), + code(17, 7, 11), + code(0, 8, 98), + code(0, 8, 34), + code(0, 9, 165), + code(0, 8, 2), + code(0, 8, 130), + code(0, 8, 66), + code(0, 9, 229), + code(16, 7, 7), + code(0, 8, 90), + code(0, 8, 26), + code(0, 9, 149), + code(20, 7, 67), + code(0, 8, 122), + code(0, 8, 58), + code(0, 9, 213), + code(18, 7, 19), + code(0, 8, 106), + code(0, 8, 42), + code(0, 9, 181), + code(0, 8, 10), + code(0, 8, 138), + code(0, 8, 74), + code(0, 9, 245), + code(16, 7, 5), + code(0, 8, 86), + code(0, 8, 22), + code(64, 8, 0), + code(19, 7, 51), + code(0, 8, 118), + code(0, 8, 54), + code(0, 9, 205), + code(17, 7, 15), + code(0, 8, 102), + code(0, 8, 38), + code(0, 9, 173), + code(0, 8, 6), + code(0, 8, 134), + code(0, 8, 70), + code(0, 9, 237), + code(16, 7, 9), + code(0, 8, 94), + code(0, 8, 30), + code(0, 9, 157), + code(20, 7, 99), + code(0, 8, 126), + code(0, 8, 62), + code(0, 9, 221), + code(18, 7, 27), + code(0, 8, 110), + code(0, 8, 46), + code(0, 9, 189), + code(0, 8, 14), + code(0, 8, 142), + code(0, 8, 78), + code(0, 9, 253), + code(96, 7, 0), + code(0, 8, 81), + code(0, 8, 17), + code(21, 8, 131), + code(18, 7, 31), + code(0, 8, 113), + code(0, 8, 49), + code(0, 9, 195), + code(16, 7, 10), + code(0, 8, 97), + code(0, 8, 33), + code(0, 9, 163), + code(0, 8, 1), + code(0, 8, 129), + code(0, 8, 65), + code(0, 9, 227), + code(16, 7, 6), + code(0, 8, 89), + code(0, 8, 25), + code(0, 9, 147), + code(19, 7, 59), + code(0, 8, 121), + code(0, 8, 57), + code(0, 9, 211), + code(17, 7, 17), + code(0, 8, 105), + code(0, 8, 41), + code(0, 9, 179), + code(0, 8, 9), + code(0, 8, 137), + code(0, 8, 73), + code(0, 9, 243), + code(16, 7, 4), + code(0, 8, 85), + code(0, 8, 21), + code(16, 8, 258), + code(19, 7, 43), + code(0, 8, 117), + code(0, 8, 53), + code(0, 9, 203), + code(17, 7, 13), + code(0, 8, 101), + code(0, 8, 37), + code(0, 9, 171), + code(0, 8, 5), + code(0, 8, 133), + code(0, 8, 69), + code(0, 9, 235), + code(16, 7, 8), + code(0, 8, 93), + code(0, 8, 29), + code(0, 9, 155), + code(20, 7, 83), + code(0, 8, 125), + code(0, 8, 61), + code(0, 9, 219), + code(18, 7, 23), + code(0, 8, 109), + code(0, 8, 45), + code(0, 9, 187), + code(0, 8, 13), + code(0, 8, 141), + code(0, 8, 77), + code(0, 9, 251), + code(16, 7, 3), + code(0, 8, 83), + code(0, 8, 19), + code(21, 8, 195), + code(19, 7, 35), + code(0, 8, 115), + code(0, 8, 51), + code(0, 9, 199), + code(17, 7, 11), + code(0, 8, 99), + code(0, 8, 35), + code(0, 9, 167), + code(0, 8, 3), + code(0, 8, 131), + code(0, 8, 67), + code(0, 9, 231), + code(16, 7, 7), + code(0, 8, 91), + code(0, 8, 27), + code(0, 9, 151), + code(20, 7, 67), + code(0, 8, 123), + code(0, 8, 59), + code(0, 9, 215), + code(18, 7, 19), + code(0, 8, 107), + code(0, 8, 43), + code(0, 9, 183), + code(0, 8, 11), + code(0, 8, 139), + code(0, 8, 75), + code(0, 9, 247), + code(16, 7, 5), + code(0, 8, 87), + code(0, 8, 23), + code(64, 8, 0), + code(19, 7, 51), + code(0, 8, 119), + code(0, 8, 55), + code(0, 9, 207), + code(17, 7, 15), + code(0, 8, 103), + code(0, 8, 39), + code(0, 9, 175), + code(0, 8, 7), + code(0, 8, 135), + code(0, 8, 71), + code(0, 9, 239), + code(16, 7, 9), + code(0, 8, 95), + code(0, 8, 31), + code(0, 9, 159), + code(20, 7, 99), + code(0, 8, 127), + code(0, 8, 63), + code(0, 9, 223), + code(18, 7, 27), + code(0, 8, 111), + code(0, 8, 47), + code(0, 9, 191), + code(0, 8, 15), + code(0, 8, 143), + code(0, 8, 79), + code(0, 9, 255), +]; + +pub(crate) const DISTFIX: [Code; 32] = [ + code(16, 5, 1), + code(23, 5, 257), + code(19, 5, 17), + code(27, 5, 4097), + code(17, 5, 5), + code(25, 5, 1025), + code(21, 5, 65), + code(29, 5, 16385), + code(16, 5, 3), + code(24, 5, 513), + code(20, 5, 33), + code(28, 5, 8193), + code(18, 5, 9), + code(26, 5, 2049), + code(22, 5, 129), + code(64, 5, 0), + code(16, 5, 2), + code(23, 5, 385), + code(19, 5, 25), + code(27, 5, 6145), + code(17, 5, 7), + code(25, 5, 1537), + code(21, 5, 97), + code(29, 5, 24577), + code(16, 5, 4), + code(24, 5, 769), + code(20, 5, 49), + code(28, 5, 12289), + code(18, 5, 13), + code(26, 5, 3073), + code(22, 5, 193), + code(64, 5, 0), +]; diff --git a/third_party/rust/zlib-rs/src/inflate/inftrees.rs b/third_party/rust/zlib-rs/src/inflate/inftrees.rs new file mode 100644 index 000000000000..64a958e147cb --- /dev/null +++ b/third_party/rust/zlib-rs/src/inflate/inftrees.rs @@ -0,0 +1,358 @@ +#![forbid(unsafe_code)] + +use crate::{Code, ENOUGH_DISTS, ENOUGH_LENS}; + +pub(crate) enum CodeType { + Codes, + Lens, + Dists, +} + +const MAX_BITS: usize = 15; + +fn min_max(count: [u16; N]) -> (usize, usize) { + let mut max = MAX_BITS; + while max >= 1 { + if count[max] != 0 { + break; + } + max -= 1; + } + + let mut min = 1; + while min < max { + if count[min] != 0 { + break; + } + min += 1; + } + + (min, max) +} + +/// Length codes 257..285 base +const LBASE: [u16; 31] = [ + 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, 35, 43, 51, 59, 67, 83, 99, 115, 131, + 163, 195, 227, 258, 0, 0, +]; +/// Length codes 257..285 extra +const LEXT: [u16; 31] = [ + 16, 16, 16, 16, 16, 16, 16, 16, 17, 17, 17, 17, 18, 18, 18, 18, 19, 19, 19, 19, 20, 20, 20, 20, + 21, 21, 21, 21, 16, 77, 202, +]; +/// Distance codes 0..29 base +const DBASE: [u16; 32] = [ + 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, 257, 385, 513, 769, 1025, 1537, + 2049, 3073, 4097, 6145, 8193, 12289, 16385, 24577, 0, 0, +]; +/// Distance codes 0..29 extra +const DEXT: [u16; 32] = [ + 16, 16, 16, 16, 17, 17, 18, 18, 19, 19, 20, 20, 21, 21, 22, 22, 23, 23, 24, 24, 25, 25, 26, 26, + 27, 27, 28, 28, 29, 29, 64, 64, +]; + +#[repr(i32)] +#[derive(Debug, PartialEq, Eq)] +pub(crate) enum InflateTable { + EnoughIsNotEnough = 1, + Success(usize) = 0, + InvalidCode = -1, +} + +pub(crate) fn inflate_table( + codetype: CodeType, + lens: &[u16], + codes: usize, + table: &mut [Code], + bits: usize, + work: &mut [u16], +) -> InflateTable { + // number of codes of each length + let mut count = [0u16; MAX_BITS + 1]; + + for len in lens[0..codes].iter().copied() { + count[len as usize] += 1; + } + + let mut root = bits; + + let (min, max) = min_max(count); + root = Ord::min(root, max); + root = Ord::max(root, min); + + if max == 0 { + // no symbols to code at all + let code = Code { + op: 64, + bits: 1, + val: 0, + }; + + table[0] = code; + table[1] = code; + + return InflateTable::Success(1); + } + + /* check for an over-subscribed or incomplete set of lengths */ + let mut left = 1i32; + let mut len = 1; + while len <= MAX_BITS { + left <<= 1; + left -= count[len] as i32; + if left < 0 { + // over-subscribed + return InflateTable::InvalidCode; + } + len += 1; + } + + if left > 0 && (matches!(codetype, CodeType::Codes) || max != 1) { + // incomplete set + return InflateTable::InvalidCode; + } + + /* generate offsets into symbol table for each length for sorting */ + + // offsets in table for each length + let mut offs = [0u16; MAX_BITS + 1]; + for len in 1..MAX_BITS { + offs[len + 1] = offs[len] + count[len]; + } + + /* sort symbols by length, by symbol order within each length */ + for (sym, len) in lens[0..codes].iter().copied().enumerate() { + if len != 0 { + let offset = offs[len as usize]; + offs[len as usize] += 1; + work[offset as usize] = sym as u16; + } + } + + let (base, extra, match_) = match codetype { + CodeType::Codes => (&[] as &[_], &[] as &[_], 20), + CodeType::Lens => (&LBASE[..], &LEXT[..], 257), + CodeType::Dists => (&DBASE[..], &DEXT[..], 0), + }; + + let used = 1 << root; + + /* check available table space */ + if matches!(codetype, CodeType::Lens) && used > ENOUGH_LENS { + return InflateTable::EnoughIsNotEnough; + } + + if matches!(codetype, CodeType::Dists) && used > ENOUGH_DISTS { + return InflateTable::EnoughIsNotEnough; + } + + let mut huff = 0; // starting code + let mut reversed_huff = 0u32; // starting code, reversed + let mut sym = 0; + let mut len = min; + let mut next = 0usize; // index into `table` + let mut curr = root; + let mut drop_ = 0; + let mut low = usize::MAX; // trigger new subtable when len > root + let mut used = 1 << root; + let mask = used - 1; /* mask for comparing low */ + + // process all codes and make table entries + 'outer: loop { + // create table entry + let here = if work[sym] >= match_ { + Code { + bits: (len - drop_) as u8, + op: extra[(work[sym] - match_) as usize] as u8, + val: base[(work[sym] - match_) as usize], + } + } else if work[sym] + 1 < match_ { + Code { + bits: (len - drop_) as u8, + op: 0, + val: work[sym], + } + } else { + Code { + bits: (len - drop_) as u8, + op: 0b01100000, + val: 0, + } + }; + + // replicate for those indices with low len bits equal to huff + let incr = 1 << (len - drop_); + let min = 1 << curr; // also has the name 'fill' in the C code + + let base = &mut table[next + (huff >> drop_)..]; + for fill in (0..min).step_by(incr) { + base[fill] = here; + } + + // backwards increment the len-bit code huff + reversed_huff = reversed_huff.wrapping_add(0x80000000u32 >> (len - 1)); + huff = reversed_huff.reverse_bits() as usize; + + // go to next symbol, update count, len + sym += 1; + count[len] -= 1; + if count[len] == 0 { + if len == max { + break 'outer; + } + len = lens[work[sym] as usize] as usize; + } + + // create new sub-table if needed + if len > root && (huff & mask) != low { + /* if first time, transition to sub-tables */ + if drop_ == 0 { + drop_ = root; + } + + /* increment past last table */ + next += min; /* here min is 1 << curr */ + + /* determine length of next table */ + curr = len - drop_; + let mut left = 1 << curr; + while curr + drop_ < max { + left -= count[curr + drop_] as i32; + if left <= 0 { + break; + } + curr += 1; + left <<= 1; + } + + /* check for enough space */ + used += 1usize << curr; + + if matches!(codetype, CodeType::Lens) && used > ENOUGH_LENS { + return InflateTable::EnoughIsNotEnough; + } + + if matches!(codetype, CodeType::Dists) && used > ENOUGH_DISTS { + return InflateTable::EnoughIsNotEnough; + } + + /* point entry in root table to sub-table */ + low = huff & mask; + table[low] = Code { + op: curr as u8, + bits: root as u8, + val: next as u16, + }; + } + } + + /* fill in remaining table entry if code is incomplete (guaranteed to have + at most one remaining entry, since if the code is incomplete, the + maximum code length that was allowed to get this far is one bit) */ + if huff != 0 { + let here = Code { + op: 64, + bits: (len - drop_) as u8, + val: 0, + }; + + table[next..][huff] = here; + } + + /* set return parameters */ + InflateTable::Success(root) +} + +#[cfg(test)] +mod test { + use super::*; + + #[test] + fn not_enough_errors() { + // we need to call inflate_table() directly in order to manifest + // not-enough errors, since zlib insures that enough is always enough + + let table = [Code::default(); crate::ENOUGH_DISTS]; + + let mut work = [0; 16]; + let mut lens: [_; 16] = core::array::from_fn(|i| (i + 1) as u16); + lens[15] = 15; + + let mut next = table; + let bits = 15; + let ret = inflate_table(CodeType::Dists, &lens, 16, &mut next, bits, &mut work); + assert_eq!(ret, InflateTable::EnoughIsNotEnough); + + let mut next = table; + let bits = 1; + let ret = inflate_table(CodeType::Dists, &lens, 16, &mut next, bits, &mut work); + assert_eq!(ret, InflateTable::EnoughIsNotEnough); + } + + fn build_fixed_length_table(work: &mut [u16]) -> [Code; 512] { + let mut lens = [0; 288]; + + // literal/length table + let mut sym = 0usize; + while sym < 144 { + lens[sym] = 8; + sym += 1; + } + while sym < 256 { + lens[sym] = 9; + sym += 1; + } + while sym < 280 { + lens[sym] = 7; + sym += 1; + } + while sym < 288 { + lens[sym] = 8; + sym += 1; + } + + let mut next = [Code::default(); 512]; + let bits = 9; + inflate_table(CodeType::Lens, &lens, 288, &mut next, bits, work); + + core::array::from_fn(|i| { + let mut code = next[i]; + + code.op = if i & 0b0111_1111 == 99 { 64 } else { code.op }; + + code + }) + } + + #[test] + fn generate_fixed_length_table() { + let mut work = [0; 512]; + let generated = build_fixed_length_table(&mut work); + + assert_eq!(generated, crate::inflate::inffixed_tbl::LENFIX); + } + + fn build_fixed_distance_table(work: &mut [u16]) -> [Code; 32] { + let mut lens = [0; 288]; + + let mut sym = 0; + while sym < 32 { + lens[sym] = 5; + sym += 1; + } + + let mut next = [Code::default(); 32]; + let bits = 5; + inflate_table(CodeType::Dists, &lens, 32, &mut next, bits, work); + + next + } + + #[test] + fn generate_fixed_distance_table() { + let mut work = [0; 512]; + let generated = build_fixed_distance_table(&mut work); + + assert_eq!(generated, crate::inflate::inffixed_tbl::DISTFIX); + } +} diff --git a/third_party/rust/zlib-rs/src/inflate/window.rs b/third_party/rust/zlib-rs/src/inflate/window.rs new file mode 100644 index 000000000000..535aa01afe97 --- /dev/null +++ b/third_party/rust/zlib-rs/src/inflate/window.rs @@ -0,0 +1,267 @@ +use crate::{ + adler32::{adler32, adler32_fold_copy}, + allocate::Allocator, + crc32::Crc32Fold, +}; +use core::mem::MaybeUninit; + +// translation guide: +// +// wsize -> buf.capacity() +// wnext -> buf.ptr +// whave -> buf.filled.len() +#[derive(Debug)] +pub struct Window<'a> { + buf: &'a mut [MaybeUninit], + + have: usize, // number of bytes logically written to the window. this can be higher than + // buf.len() if we run out of space in the window + next: usize, // write head +} + +impl<'a> Window<'a> { + pub fn into_inner(self) -> &'a mut [MaybeUninit] { + self.buf + } + + pub fn is_empty(&self) -> bool { + self.size() == 0 + } + + pub fn size(&self) -> usize { + if self.buf.is_empty() { + // an empty `buf` is used when the window has not yet been allocated, + // or when it has been deallocated. + 0 + } else { + self.buf.len() - Self::padding() + } + } + + /// number of bytes in the window. Saturates at `Self::capacity`. + pub fn have(&self) -> usize { + self.have + } + + /// Position where the next byte will be written + pub fn next(&self) -> usize { + self.next + } + + pub fn empty() -> Self { + Self { + buf: &mut [], + have: 0, + next: 0, + } + } + + pub fn clear(&mut self) { + self.have = 0; + self.next = 0; + } + + pub fn as_slice(&self) -> &[u8] { + // safety: the slice is always from the initialized part of buf + unsafe { slice_assume_init(&self.buf[..self.have]) } + } + + #[cfg(test)] + fn extend_adler32(&mut self, slice: &[u8], checksum: &mut u32) { + self.extend(slice, 0, true, checksum, &mut Crc32Fold::new()); + } + + pub fn extend( + &mut self, + slice: &[u8], + flags: i32, + update_checksum: bool, + checksum: &mut u32, + crc_fold: &mut Crc32Fold, + ) { + let len = slice.len(); + let wsize = self.size(); + + if len >= wsize { + // We have to split the checksum over non-copied and copied bytes + let pos = len.saturating_sub(self.size()); + let (non_window_slice, window_slice) = slice.split_at(pos); + + if update_checksum { + if flags != 0 { + crc_fold.fold(non_window_slice, 0); + crc_fold.fold_copy(&mut self.buf[..wsize], window_slice); + } else { + *checksum = adler32(*checksum, non_window_slice); + *checksum = adler32_fold_copy(*checksum, self.buf, window_slice); + } + } else { + self.buf[..wsize].copy_from_slice(unsafe { slice_to_uninit(window_slice) }); + } + + self.next = 0; + self.have = self.size(); + } else { + let dist = Ord::min(wsize - self.next, slice.len()); + + // the end part goes onto the end of the window. The start part wraps around and is + // written to the start of the window. + let (end_part, start_part) = slice.split_at(dist); + + if update_checksum { + let dst = &mut self.buf[self.next..][..end_part.len()]; + if flags != 0 { + crc_fold.fold_copy(dst, end_part); + } else { + *checksum = adler32_fold_copy(*checksum, dst, end_part); + } + } else { + let end_part = unsafe { slice_to_uninit(end_part) }; + self.buf[self.next..][..end_part.len()].copy_from_slice(end_part); + } + + if !start_part.is_empty() { + if update_checksum { + let dst = &mut self.buf[..start_part.len()]; + if flags != 0 { + crc_fold.fold_copy(dst, start_part); + } else { + *checksum = adler32_fold_copy(*checksum, dst, start_part); + } + } else { + let start_part = unsafe { slice_to_uninit(start_part) }; + self.buf[..start_part.len()].copy_from_slice(start_part); + } + + self.next = start_part.len(); + self.have = self.size(); + } else { + self.next += dist; + if self.next == self.size() { + self.next = 0; + } + if self.have < self.size() { + self.have += dist; + } + } + } + } + + pub fn new_in(alloc: &Allocator<'a>, window_bits: usize) -> Option { + let buf = alloc.allocate_slice::((1 << window_bits) + Self::padding())?; + + Some(Self { + buf, + have: 0, + next: 0, + }) + } + + pub fn clone_in(&self, alloc: &Allocator<'a>) -> Option { + let buf = alloc.allocate_slice::(self.buf.len())?; + + Some(Self { + buf, + have: self.have, + next: self.next, + }) + } + + // padding required so that SIMD operations going out-of-bounds are not a problem + pub fn padding() -> usize { + 64 // very conservative + } +} + +unsafe fn slice_to_uninit(slice: &[u8]) -> &[MaybeUninit] { + &*(slice as *const [u8] as *const [MaybeUninit]) +} + +// TODO: This could use `MaybeUninit::slice_assume_init` when it is stable. +unsafe fn slice_assume_init(slice: &[MaybeUninit]) -> &[u8] { + &*(slice as *const [MaybeUninit] as *const [u8]) +} + +#[cfg(test)] +mod test { + use super::*; + + use crate::allocate::Allocator; + + fn init_window(window_bits_log2: usize) -> Window<'static> { + let mut window = Window::new_in(&Allocator::RUST, window_bits_log2).unwrap(); + window.buf.fill(MaybeUninit::new(0)); + window.have = 0; + window.next = 0; + window + } + + #[test] + fn extend_in_bounds() { + let mut checksum = 0; + + let mut window = init_window(4); + + window.extend_adler32(&[1; 5], &mut checksum); + assert_eq!(window.have, 5); + assert_eq!(window.next, 5); + + let slice = unsafe { slice_assume_init(&window.buf[..window.size()]) }; + assert_eq!(&[1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], slice); + + window.extend_adler32(&[2; 7], &mut checksum); + assert_eq!(window.have, 12); + assert_eq!(window.next, 12); + + let slice = unsafe { slice_assume_init(&window.buf[..window.size()]) }; + assert_eq!(&[1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0], slice); + + assert_eq!(checksum, 6946835); + + unsafe { Allocator::RUST.deallocate(window.buf.as_mut_ptr(), window.buf.len()) } + } + + #[test] + fn extend_crosses_bounds() { + let mut checksum = 0; + + let mut window = init_window(2); + + window.extend_adler32(&[1; 3], &mut checksum); + assert_eq!(window.have, 3); + assert_eq!(window.next, 3); + + let slice = unsafe { slice_assume_init(&window.buf[..window.size()]) }; + assert_eq!(&[1, 1, 1, 0], slice); + + window.extend_adler32(&[2; 3], &mut checksum); + assert_eq!(window.have, 4); + assert_eq!(window.next, 2); + + let slice = unsafe { slice_assume_init(&window.buf[..window.size()]) }; + assert_eq!(&[2, 2, 1, 2], slice); + + assert_eq!(checksum, 1769481); + + unsafe { Allocator::RUST.deallocate(window.buf.as_mut_ptr(), window.buf.len()) } + } + + #[test] + fn extend_out_of_bounds() { + let mut checksum = 0; + + let mut window = init_window(3); + + // adds 9 numbers, that won't fit into a window of size 8 + window.extend_adler32(&[1, 2, 3, 4, 5, 6, 7, 8, 9], &mut checksum); + assert_eq!(window.have, 8); + assert_eq!(window.next, 0); + + let slice = unsafe { slice_assume_init(&window.buf[..window.size()]) }; + assert_eq!(&[2, 3, 4, 5, 6, 7, 8, 9], slice); + + assert_eq!(checksum, 10813485); + + unsafe { Allocator::RUST.deallocate(window.buf.as_mut_ptr(), window.buf.len()) } + } +} diff --git a/third_party/rust/zlib-rs/src/lib.rs b/third_party/rust/zlib-rs/src/lib.rs new file mode 100644 index 000000000000..92dbaf4c9885 --- /dev/null +++ b/third_party/rust/zlib-rs/src/lib.rs @@ -0,0 +1,193 @@ +#![doc = core::include_str!("../README.md")] +#![cfg_attr(not(any(test, feature = "rust-allocator")), no_std)] + +#[cfg(any(feature = "rust-allocator", feature = "c-allocator"))] +extern crate alloc; + +mod adler32; +pub mod allocate; +pub mod c_api; +pub mod crc32; +pub mod deflate; +pub mod inflate; +pub mod read_buf; + +pub use adler32::{adler32, adler32_combine}; +pub use crc32::{crc32, crc32_combine}; + +#[macro_export] +macro_rules! trace { + ($($arg:tt)*) => { + // eprint!($($arg)*) + }; +} + +/// Maximum size of the dynamic table. The maximum number of code structures is +/// 1924, which is the sum of 1332 for literal/length codes and 592 for distance +/// codes. These values were found by exhaustive searches using the program +/// examples/enough.c found in the zlib distributions. The arguments to that +/// program are the number of symbols, the initial root table size, and the +/// maximum bit length of a code. "enough 286 10 15" for literal/length codes +/// returns 1332, and "enough 30 9 15" for distance codes returns 592. +/// The initial root table size (10 or 9) is found in the fifth argument of the +/// inflate_table() calls in inflate.c and infback.c. If the root table size is +/// changed, then these maximum sizes would be need to be recalculated and +/// updated. +#[allow(unused)] +pub(crate) const ENOUGH: usize = ENOUGH_LENS + ENOUGH_DISTS; +pub(crate) const ENOUGH_LENS: usize = 1332; +pub(crate) const ENOUGH_DISTS: usize = 592; + +/// initial adler-32 hash value +pub(crate) const ADLER32_INITIAL_VALUE: usize = 1; +/// initial crc-32 hash value +pub(crate) const CRC32_INITIAL_VALUE: u32 = 0; + +pub const MIN_WBITS: i32 = 8; // 256b LZ77 window +pub const MAX_WBITS: i32 = 15; // 32kb LZ77 window +pub(crate) const DEF_WBITS: i32 = MAX_WBITS; + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)] +pub enum DeflateFlush { + #[default] + /// if flush is set to `NoFlush`, that allows deflate to decide how much data + /// to accumulate before producing output, in order to maximize compression. + NoFlush = 0, + + /// If flush is set to `PartialFlush`, all pending output is flushed to the + /// output buffer, but the output is not aligned to a byte boundary. All of the + /// input data so far will be available to the decompressor, as for Z_SYNC_FLUSH. + /// This completes the current deflate block and follows it with an empty fixed + /// codes block that is 10 bits long. This assures that enough bytes are output + /// in order for the decompressor to finish the block before the empty fixed + /// codes block. + PartialFlush = 1, + + /// If the parameter flush is set to `SyncFlush`, all pending output is + /// flushed to the output buffer and the output is aligned on a byte boundary, so + /// that the decompressor can get all input data available so far. (In + /// particular avail_in is zero after the call if enough output space has been + /// provided before the call.) Flushing may degrade compression for some + /// compression algorithms and so it should be used only when necessary. This + /// completes the current deflate block and follows it with an empty stored block + /// that is three bits plus filler bits to the next byte, followed by four bytes + /// (00 00 ff ff). + SyncFlush = 2, + + /// If flush is set to `FullFlush`, all output is flushed as with + /// Z_SYNC_FLUSH, and the compression state is reset so that decompression can + /// restart from this point if previous compressed data has been damaged or if + /// random access is desired. Using `FullFlush` too often can seriously degrade + /// compression. + FullFlush = 3, + + /// If the parameter flush is set to `Finish`, pending input is processed, + /// pending output is flushed and deflate returns with `StreamEnd` if there was + /// enough output space. If deflate returns with `Ok` or `BufError`, this + /// function must be called again with `Finish` and more output space (updated + /// avail_out) but no more input data, until it returns with `StreamEnd` or an + /// error. After deflate has returned `StreamEnd`, the only possible operations + /// on the stream are deflateReset or deflateEnd. + /// + /// `Finish` can be used in the first deflate call after deflateInit if all the + /// compression is to be done in a single step. In order to complete in one + /// call, avail_out must be at least the value returned by deflateBound (see + /// below). Then deflate is guaranteed to return `StreamEnd`. If not enough + /// output space is provided, deflate will not return `StreamEnd`, and it must + /// be called again as described above. + Finish = 4, + + /// If flush is set to `Block`, a deflate block is completed and emitted, as + /// for `SyncFlush`, but the output is not aligned on a byte boundary, and up to + /// seven bits of the current block are held to be written as the next byte after + /// the next deflate block is completed. In this case, the decompressor may not + /// be provided enough bits at this point in order to complete decompression of + /// the data provided so far to the compressor. It may need to wait for the next + /// block to be emitted. This is for advanced applications that need to control + /// the emission of deflate blocks. + Block = 5, +} + +impl TryFrom for DeflateFlush { + type Error = (); + + fn try_from(value: i32) -> Result { + match value { + 0 => Ok(Self::NoFlush), + 1 => Ok(Self::PartialFlush), + 2 => Ok(Self::SyncFlush), + 3 => Ok(Self::FullFlush), + 4 => Ok(Self::Finish), + 5 => Ok(Self::Block), + _ => Err(()), + } + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)] +pub enum InflateFlush { + #[default] + NoFlush = 0, + SyncFlush = 2, + Finish = 4, + Block = 5, + Trees = 6, +} + +impl TryFrom for InflateFlush { + type Error = (); + + fn try_from(value: i32) -> Result { + match value { + 0 => Ok(Self::NoFlush), + 2 => Ok(Self::SyncFlush), + 4 => Ok(Self::Finish), + 5 => Ok(Self::Block), + 6 => Ok(Self::Trees), + _ => Err(()), + } + } +} + +#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)] +pub(crate) struct Code { + /// operation, extra bits, table bits + pub op: u8, + /// bits in this part of the code + pub bits: u8, + /// offset in table or code value + pub val: u16, +} + +#[derive(Debug, Copy, Clone, PartialEq, Eq)] +#[repr(i32)] +pub enum ReturnCode { + Ok = 0, + StreamEnd = 1, + NeedDict = 2, + ErrNo = -1, + StreamError = -2, + DataError = -3, + MemError = -4, + BufError = -5, + VersionError = -6, +} + +impl From for ReturnCode { + fn from(value: i32) -> Self { + use ReturnCode::*; + + match value { + 0 => Ok, + 1 => StreamEnd, + 2 => NeedDict, + -1 => ErrNo, + -2 => StreamError, + -3 => DataError, + -4 => MemError, + -5 => BufError, + -6 => VersionError, + _ => panic!("invalid return code {value}"), + } + } +} diff --git a/third_party/rust/zlib-rs/src/read_buf.rs b/third_party/rust/zlib-rs/src/read_buf.rs new file mode 100644 index 000000000000..2e9bffc918e9 --- /dev/null +++ b/third_party/rust/zlib-rs/src/read_buf.rs @@ -0,0 +1,553 @@ +#![allow(unused)] +// taken from https://docs.rs/tokio/latest/src/tokio/io/read_buf.rs.html#23-27 +// based on https://rust-lang.github.io/rfcs/2930-read-buf.html +use core::fmt; +use core::mem::MaybeUninit; + +use crate::allocate::Allocator; + +/// A wrapper around a byte buffer that is incrementally filled and initialized. +/// +/// This type is a sort of "double cursor". It tracks three regions in the +/// buffer: a region at the beginning of the buffer that has been logically +/// filled with data, a region that has been initialized at some point but not +/// yet logically filled, and a region at the end that may be uninitialized. +/// The filled region is guaranteed to be a subset of the initialized region. +/// +/// In summary, the contents of the buffer can be visualized as: +/// +/// ```not_rust +/// [ capacity ] +/// [ filled | unfilled ] +/// [ initialized | uninitialized ] +/// ``` +/// +/// It is undefined behavior to de-initialize any bytes from the uninitialized +/// region, since it is merely unknown whether this region is uninitialized or +/// not, and if part of it turns out to be initialized, it must stay initialized. +pub struct ReadBuf<'a> { + buf: &'a mut [MaybeUninit], + filled: usize, + initialized: usize, +} + +impl<'a> ReadBuf<'a> { + /// Creates a new `ReadBuf` from a fully initialized buffer. + #[inline] + pub fn new(buf: &'a mut [u8]) -> ReadBuf<'a> { + let initialized = buf.len(); + let buf = unsafe { slice_to_uninit_mut(buf) }; + ReadBuf { + buf, + filled: 0, + initialized, + } + } + + /// # Safety + /// + /// The `ptr` and `len` must for a valid `&mut [MaybeUninit]` + pub unsafe fn from_raw_parts(ptr: *mut u8, len: usize) -> Self { + let buf = core::slice::from_raw_parts_mut(ptr as _, len); + + Self { + buf, + filled: 0, + initialized: 0, + } + } + + /// Pointer to where the next byte will be written + #[inline] + pub fn next_out(&mut self) -> *mut MaybeUninit { + self.buf[self.filled..].as_mut_ptr() + } + + /// Pointer to the start of the `ReadBuf` + #[inline] + pub fn as_mut_ptr(&mut self) -> *mut MaybeUninit { + self.buf.as_mut_ptr() + } + + /// Creates a new `ReadBuf` from a fully uninitialized buffer. + /// + /// Use `assume_init` if part of the buffer is known to be already initialized. + #[inline] + pub fn uninit(buf: &'a mut [MaybeUninit]) -> ReadBuf<'a> { + ReadBuf { + buf, + filled: 0, + initialized: 0, + } + } + + /// Returns the total capacity of the buffer. + #[inline] + pub fn capacity(&self) -> usize { + self.buf.len() + } + + /// Returns the length of the filled part of the buffer + #[inline] + pub fn len(&self) -> usize { + self.filled + } + + /// Returns true if there are no bytes in this ReadBuf + #[inline] + pub fn is_empty(&self) -> bool { + self.filled == 0 + } + + /// Returns a shared reference to the filled portion of the buffer. + #[inline] + pub fn filled(&self) -> &[u8] { + let slice = &self.buf[..self.filled]; + // safety: filled describes how far into the buffer that the + // user has filled with bytes, so it's been initialized. + unsafe { slice_assume_init(slice) } + } + + /// Returns a mutable reference to the filled portion of the buffer. + #[inline] + pub fn filled_mut(&mut self) -> &mut [u8] { + let slice = &mut self.buf[..self.filled]; + // safety: filled describes how far into the buffer that the + // user has filled with bytes, so it's been initialized. + unsafe { slice_assume_init_mut(slice) } + } + + /// Returns a new `ReadBuf` comprised of the unfilled section up to `n`. + #[inline] + pub fn take(&mut self, n: usize) -> ReadBuf<'_> { + let max = core::cmp::min(self.remaining(), n); + // Safety: We don't set any of the `unfilled_mut` with `MaybeUninit::uninit`. + unsafe { ReadBuf::uninit(&mut self.unfilled_mut()[..max]) } + } + + /// Returns a shared reference to the initialized portion of the buffer. + /// + /// This includes the filled portion. + #[inline] + pub fn initialized(&self) -> &[u8] { + let slice = &self.buf[..self.initialized]; + // safety: initialized describes how far into the buffer that the + // user has at some point initialized with bytes. + unsafe { slice_assume_init(slice) } + } + + /// Returns a mutable reference to the initialized portion of the buffer. + /// + /// This includes the filled portion. + #[inline] + pub fn initialized_mut(&mut self) -> &mut [u8] { + let slice = &mut self.buf[..self.initialized]; + // safety: initialized describes how far into the buffer that the + // user has at some point initialized with bytes. + unsafe { slice_assume_init_mut(slice) } + } + + /// Returns a mutable reference to the entire buffer, without ensuring that it has been fully + /// initialized. + /// + /// The elements between 0 and `self.len()` are filled, and those between 0 and + /// `self.initialized().len()` are initialized (and so can be converted to a `&mut [u8]`). + /// + /// The caller of this method must ensure that these invariants are upheld. For example, if the + /// caller initializes some of the uninitialized section of the buffer, it must call + /// [`assume_init`](Self::assume_init) with the number of bytes initialized. + /// + /// # Safety + /// + /// The caller must not de-initialize portions of the buffer that have already been initialized. + /// This includes any bytes in the region marked as uninitialized by `ReadBuf`. + #[inline] + pub unsafe fn inner_mut(&mut self) -> &mut [MaybeUninit] { + self.buf + } + + /// Returns a mutable reference to the unfilled part of the buffer without ensuring that it has been fully + /// initialized. + /// + /// # Safety + /// + /// The caller must not de-initialize portions of the buffer that have already been initialized. + /// This includes any bytes in the region marked as uninitialized by `ReadBuf`. + #[inline] + pub unsafe fn unfilled_mut(&mut self) -> &mut [MaybeUninit] { + &mut self.buf[self.filled..] + } + + /// Returns a mutable reference to the unfilled part of the buffer, ensuring it is fully initialized. + /// + /// Since `ReadBuf` tracks the region of the buffer that has been initialized, this is effectively "free" after + /// the first use. + #[inline] + pub fn initialize_unfilled(&mut self) -> &mut [u8] { + self.initialize_unfilled_to(self.remaining()) + } + + /// Returns a mutable reference to the first `n` bytes of the unfilled part of the buffer, ensuring it is + /// fully initialized. + /// + /// # Panics + /// + /// Panics if `self.remaining()` is less than `n`. + #[inline] + #[track_caller] + pub fn initialize_unfilled_to(&mut self, n: usize) -> &mut [u8] { + assert!(self.remaining() >= n, "n overflows remaining"); + + // This can't overflow, otherwise the assert above would have failed. + let end = self.filled + n; + + if self.initialized < end { + unsafe { + self.buf[self.initialized..end] + .as_mut_ptr() + .write_bytes(0, end - self.initialized); + } + self.initialized = end; + } + + let slice = &mut self.buf[self.filled..end]; + // safety: just above, we checked that the end of the buf has + // been initialized to some value. + unsafe { slice_assume_init_mut(slice) } + } + + /// Returns the number of bytes at the end of the slice that have not yet been filled. + #[inline] + pub fn remaining(&self) -> usize { + self.capacity() - self.filled + } + + /// Clears the buffer, resetting the filled region to empty. + /// + /// The number of initialized bytes is not changed, and the contents of the buffer are not modified. + #[inline] + pub fn clear(&mut self) { + self.filled = 0; + } + + /// Advances the size of the filled region of the buffer. + /// + /// The number of initialized bytes is not changed. + /// + /// # Panics + /// + /// Panics if the filled region of the buffer would become larger than the initialized region. + #[inline] + #[track_caller] + pub fn advance(&mut self, n: usize) { + let new = self.filled.checked_add(n).expect("filled overflow"); + self.set_filled(new); + } + + /// Sets the size of the filled region of the buffer. + /// + /// The number of initialized bytes is not changed. + /// + /// Note that this can be used to *shrink* the filled region of the buffer in addition to growing it (for + /// example, by a `AsyncRead` implementation that compresses data in-place). + /// + /// # Panics + /// + /// Panics if the filled region of the buffer would become larger than the initialized region. + #[inline] + #[track_caller] + pub fn set_filled(&mut self, n: usize) { + assert!( + n <= self.initialized, + "filled must not become larger than initialized" + ); + self.filled = n; + } + + /// Asserts that the first `n` unfilled bytes of the buffer are initialized. + /// + /// `ReadBuf` assumes that bytes are never de-initialized, so this method does nothing when called with fewer + /// bytes than are already known to be initialized. + /// + /// # Safety + /// + /// The caller must ensure that `n` unfilled bytes of the buffer have already been initialized. + #[inline] + pub unsafe fn assume_init(&mut self, n: usize) { + let new = self.filled + n; + if new > self.initialized { + self.initialized = new; + } + } + + #[track_caller] + pub fn push(&mut self, byte: u8) { + assert!( + self.remaining() >= 1, + "read_buf is full ({} bytes)", + self.capacity() + ); + + self.buf[self.filled] = MaybeUninit::new(byte); + + self.initialized = Ord::max(self.initialized, self.filled + 1); + self.filled += 1; + } + + /// Appends data to the buffer, advancing the written position and possibly also the initialized position. + /// + /// # Panics + /// + /// Panics if `self.remaining()` is less than `buf.len()`. + #[inline(always)] + #[track_caller] + pub fn extend(&mut self, buf: &[u8]) { + assert!( + self.remaining() >= buf.len(), + "buf.len() must fit in remaining()" + ); + + // using simd here (on x86_64) was not fruitful + self.buf[self.filled..][..buf.len()].copy_from_slice(slice_to_uninit(buf)); + + let end = self.filled + buf.len(); + self.initialized = Ord::max(self.initialized, end); + self.filled = end; + } + + #[inline(always)] + pub fn copy_match(&mut self, offset_from_end: usize, length: usize) { + let current = self.filled; + + #[cfg(all(target_arch = "x86_64", feature = "std"))] + if std::is_x86_feature_detected!("avx512f") { + return self.copy_match_help::(offset_from_end, length); + } + + #[cfg(all(target_arch = "x86_64", feature = "std"))] + if std::is_x86_feature_detected!("avx2") { + return self.copy_match_help::(offset_from_end, length); + } + + #[cfg(all(target_arch = "x86_64", feature = "std"))] + if std::is_x86_feature_detected!("sse") { + return self.copy_match_help::(offset_from_end, length); + } + + self.copy_match_help::(offset_from_end, length) + } + + fn copy_match_help(&mut self, offset_from_end: usize, length: usize) { + let current = self.filled; + + let start = current.checked_sub(offset_from_end).expect("in bounds"); + let end = start.checked_add(length).expect("in bounds"); + + // Note also that the referenced string may overlap the current + // position; for example, if the last 2 bytes decoded have values + // X and Y, a string reference with + // adds X,Y,X,Y,X to the output stream. + + if end > current { + if offset_from_end == 1 { + // this will just repeat this value many times + let element = self.buf[current - 1]; + self.buf[current..][..length].fill(element); + } else { + for i in 0..length { + self.buf[current + i] = self.buf[start + i]; + } + } + } else { + Self::copy_chunked_within::(self.buf, current, start, end) + } + + // safety: we just copied length initialized bytes right beyond self.filled + unsafe { self.assume_init(length) }; + + self.advance(length); + } + + #[inline(always)] + fn copy_chunked_within( + buf: &mut [MaybeUninit], + current: usize, + start: usize, + end: usize, + ) { + if (end - start).next_multiple_of(core::mem::size_of::()) <= (buf.len() - current) { + unsafe { + Self::copy_chunk_unchecked::( + buf.as_ptr().add(start), + buf.as_mut_ptr().add(current), + buf.as_ptr().add(end), + ) + } + } else { + // a full simd copy does not fit in the output buffer + buf.copy_within(start..end, current); + } + } + + /// # Safety + /// + /// `src` must be safe to perform unaligned reads in `core::mem::size_of::()` chunks until + /// `end` is reached. `dst` must be safe to (unalingned) write that number of chunks. + #[inline(always)] + unsafe fn copy_chunk_unchecked( + mut src: *const MaybeUninit, + mut dst: *mut MaybeUninit, + end: *const MaybeUninit, + ) { + while src < end { + let chunk = C::load_chunk(src); + C::store_chunk(dst, chunk); + + src = src.add(core::mem::size_of::()); + dst = dst.add(core::mem::size_of::()); + } + } + + pub(crate) fn new_in(alloc: &Allocator<'a>, len: usize) -> Option { + let buf = alloc.allocate_slice::(len)?; + + Some(Self { + buf, + filled: 0, + initialized: 0, + }) + } + + pub(crate) fn clone_in(&self, alloc: &Allocator<'a>) -> Option { + let mut clone = Self::new_in(alloc, self.buf.len())?; + + clone.buf.copy_from_slice(self.buf); + clone.filled = self.filled; + clone.initialized = self.initialized; + + Some(clone) + } + + pub(crate) unsafe fn drop_in(&mut self, alloc: &Allocator<'a>) { + if !self.buf.is_empty() { + let buf = core::mem::take(&mut self.buf); + alloc.deallocate(buf.as_mut_ptr(), buf.len()); + } + } +} + +#[cfg(feature = "std")] +impl std::io::Write for ReadBuf<'_> { + fn write(&mut self, buf: &[u8]) -> std::io::Result { + if self.remaining() < buf.len() { + const MSG: &str = "failed to write whole buffer"; + return Err(std::io::Error::new(std::io::ErrorKind::WriteZero, MSG)); + } + + self.extend(buf); + + Ok(buf.len()) + } + + fn flush(&mut self) -> std::io::Result<()> { + /* do nothing */ + Ok(()) + } +} + +impl fmt::Debug for ReadBuf<'_> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("ReadBuf") + .field("filled", &self.filled) + .field("initialized", &self.initialized) + .field("capacity", &self.capacity()) + .finish() + } +} + +fn slice_to_uninit(slice: &[u8]) -> &[MaybeUninit] { + unsafe { &*(slice as *const [u8] as *const [MaybeUninit]) } +} + +unsafe fn slice_to_uninit_mut(slice: &mut [u8]) -> &mut [MaybeUninit] { + &mut *(slice as *mut [u8] as *mut [MaybeUninit]) +} + +// TODO: This could use `MaybeUninit::slice_assume_init` when it is stable. +unsafe fn slice_assume_init(slice: &[MaybeUninit]) -> &[u8] { + &*(slice as *const [MaybeUninit] as *const [u8]) +} + +// TODO: This could use `MaybeUninit::slice_assume_init_mut` when it is stable. +unsafe fn slice_assume_init_mut(slice: &mut [MaybeUninit]) -> &mut [u8] { + &mut *(slice as *mut [MaybeUninit] as *mut [u8]) +} + +trait Chunk { + /// Safety: must be valid to read a `Self::Chunk` value from `from` with an unaligned read. + unsafe fn load_chunk(from: *const MaybeUninit) -> Self; + + /// Safety: must be valid to write a `Self::Chunk` value to `out` with an unaligned write. + unsafe fn store_chunk(out: *mut MaybeUninit, chunk: Self); +} + +impl Chunk for u64 { + unsafe fn load_chunk(from: *const MaybeUninit) -> Self { + core::ptr::read_unaligned(from.cast()) + } + + unsafe fn store_chunk(out: *mut MaybeUninit, chunk: Self) { + core::ptr::copy_nonoverlapping( + chunk.to_ne_bytes().as_ptr().cast(), + out, + core::mem::size_of::(), + ) + } +} + +#[cfg(target_arch = "x86_64")] +impl Chunk for core::arch::x86_64::__m128i { + #[inline(always)] + unsafe fn load_chunk(from: *const MaybeUninit) -> Self { + core::arch::x86_64::_mm_loadu_si128(from.cast()) + } + + #[inline(always)] + unsafe fn store_chunk(out: *mut MaybeUninit, chunk: Self) { + core::arch::x86_64::_mm_storeu_si128(out as *mut Self, chunk); + } +} + +#[cfg(target_arch = "x86_64")] +impl Chunk for core::arch::x86_64::__m256i { + #[inline(always)] + unsafe fn load_chunk(from: *const MaybeUninit) -> Self { + core::arch::x86_64::_mm256_loadu_si256(from.cast()) + } + + #[inline(always)] + unsafe fn store_chunk(out: *mut MaybeUninit, chunk: Self) { + core::arch::x86_64::_mm256_storeu_si256(out as *mut Self, chunk); + } +} + +#[cfg(target_arch = "x86_64")] +impl Chunk for core::arch::x86_64::__m512i { + #[inline(always)] + unsafe fn load_chunk(from: *const MaybeUninit) -> Self { + // TODO AVX-512 is effectively unstable. + // We cross our fingers that LLVM optimizes this into a vmovdqu32 + // + // https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm512_loadu_si512&expand=3420&ig_expand=4110 + core::ptr::read_unaligned(from.cast()) + } + + #[inline(always)] + unsafe fn store_chunk(out: *mut MaybeUninit, chunk: Self) { + // TODO AVX-512 is effectively unstable. + // We cross our fingers that LLVM optimizes this into a vmovdqu32 + // + // https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm512_storeu_si512&expand=3420&ig_expand=4110,6550 + core::ptr::write_unaligned(out.cast(), chunk) + } +} diff --git a/toolkit/library/moz.build b/toolkit/library/moz.build index 2011e9f3b406..bf6a36a81031 100644 --- a/toolkit/library/moz.build +++ b/toolkit/library/moz.build @@ -157,9 +157,13 @@ USE_LIBS += [ "nss", "psshparser", "sqlite", - "zlib", ] +if not CONFIG["USE_LIBZ_RS"]: + USE_LIBS += [ + "zlib", + ] + if CONFIG["MOZ_WIDGET_TOOLKIT"] == "gtk": # The mozgtk library is a workaround that makes Gtk+ use libwayland-client # instead of mozwayland. The reason it works is that by being a dependency diff --git a/toolkit/library/rust/gkrust-features.mozbuild b/toolkit/library/rust/gkrust-features.mozbuild index 51156a54dfa2..893e9e701755 100644 --- a/toolkit/library/rust/gkrust-features.mozbuild +++ b/toolkit/library/rust/gkrust-features.mozbuild @@ -86,5 +86,8 @@ if CONFIG["MOZ_ICU4X"]: if CONFIG["JS_HAS_TEMPORAL_API"]: gkrust_features += ["icu4x_calendar"] +if CONFIG["USE_LIBZ_RS"]: + gkrust_features += ["libz-rs-sys"] + # This must remain last. gkrust_features = ["gkrust-shared/%s" % f for f in gkrust_features] diff --git a/toolkit/library/rust/shared/Cargo.toml b/toolkit/library/rust/shared/Cargo.toml index 46c349091570..27ee5d106eb3 100644 --- a/toolkit/library/rust/shared/Cargo.toml +++ b/toolkit/library/rust/shared/Cargo.toml @@ -113,6 +113,8 @@ url = "2.5.0" # Since we're building with at least rustc 1.63, enable rust 1.57 features (use of try_reserve methods). fallible_collections = { version = "0.4", features = ["rust_1_57"] } +libz-rs-sys = { git = "https://github.com/memorysafety/zlib-rs", rev = "692b0fd5a367cf4714b0b24e9e498e2a064d673c", features = ["custom-prefix"], optional = true } + [target.'cfg(not(target_os = "android"))'.dependencies] viaduct = "0.1" webext_storage_bridge = { path = "../../../components/extensions/storage/webext_storage_bridge" } diff --git a/toolkit/library/rust/shared/lib.rs b/toolkit/library/rust/shared/lib.rs index f46a22a9499f..986744503c9f 100644 --- a/toolkit/library/rust/shared/lib.rs +++ b/toolkit/library/rust/shared/lib.rs @@ -126,6 +126,9 @@ extern crate oblivious_http; extern crate mime_guess_ffi; +#[cfg(feature = "libz-rs-sys")] +extern crate libz_rs_sys; + #[cfg(feature = "uniffi_fixtures")] mod uniffi_fixtures { extern crate arithmetical;