From a990de90fe41456a23e58bd087d2f107d321f3a1 Mon Sep 17 00:00:00 2001 From: Valentin Popov Date: Fri, 19 Jul 2024 16:37:58 +0400 Subject: Deleted vendor folder --- vendor/miniz_oxide/.cargo-checksum.json | 1 - vendor/miniz_oxide/Cargo.toml | 74 - vendor/miniz_oxide/LICENSE | 21 - vendor/miniz_oxide/LICENSE-APACHE.md | 177 -- vendor/miniz_oxide/LICENSE-MIT.md | 21 - vendor/miniz_oxide/LICENSE-ZLIB.md | 11 - vendor/miniz_oxide/Readme.md | 44 - vendor/miniz_oxide/src/deflate/buffer.rs | 58 - vendor/miniz_oxide/src/deflate/core.rs | 2462 ----------------------- vendor/miniz_oxide/src/deflate/mod.rs | 227 --- vendor/miniz_oxide/src/deflate/stream.rs | 121 -- vendor/miniz_oxide/src/inflate/core.rs | 1992 ------------------ vendor/miniz_oxide/src/inflate/mod.rs | 337 ---- vendor/miniz_oxide/src/inflate/output_buffer.rs | 60 - vendor/miniz_oxide/src/inflate/stream.rs | 418 ---- vendor/miniz_oxide/src/lib.rs | 209 -- vendor/miniz_oxide/src/shared.rs | 25 - 17 files changed, 6258 deletions(-) delete mode 100644 vendor/miniz_oxide/.cargo-checksum.json delete mode 100644 vendor/miniz_oxide/Cargo.toml delete mode 100644 vendor/miniz_oxide/LICENSE delete mode 100644 vendor/miniz_oxide/LICENSE-APACHE.md delete mode 100644 vendor/miniz_oxide/LICENSE-MIT.md delete mode 100644 vendor/miniz_oxide/LICENSE-ZLIB.md delete mode 100644 vendor/miniz_oxide/Readme.md delete mode 100644 vendor/miniz_oxide/src/deflate/buffer.rs delete mode 100644 vendor/miniz_oxide/src/deflate/core.rs delete mode 100644 vendor/miniz_oxide/src/deflate/mod.rs delete mode 100644 vendor/miniz_oxide/src/deflate/stream.rs delete mode 100644 vendor/miniz_oxide/src/inflate/core.rs delete mode 100644 vendor/miniz_oxide/src/inflate/mod.rs delete mode 100644 vendor/miniz_oxide/src/inflate/output_buffer.rs delete mode 100644 vendor/miniz_oxide/src/inflate/stream.rs delete mode 100644 vendor/miniz_oxide/src/lib.rs delete mode 100644 vendor/miniz_oxide/src/shared.rs (limited to 'vendor/miniz_oxide') diff --git a/vendor/miniz_oxide/.cargo-checksum.json b/vendor/miniz_oxide/.cargo-checksum.json deleted file mode 100644 index 0490f2e..0000000 --- a/vendor/miniz_oxide/.cargo-checksum.json +++ /dev/null @@ -1 +0,0 @@ -{"files":{"Cargo.toml":"e63f554c89c275682109d3b6eb5f1597de27dc3cf2517944974c720f246ac1d7","LICENSE":"e190940e8ad3cdd4fca962a6508ed6865d589d314b1cb055f86000e124b88d8d","LICENSE-APACHE.md":"0d542e0c8804e39aa7f37eb00da5a762149dc682d7829451287e11b938e94594","LICENSE-MIT.md":"e190940e8ad3cdd4fca962a6508ed6865d589d314b1cb055f86000e124b88d8d","LICENSE-ZLIB.md":"c89bcc058da12a0fb24402b8ea4542a21515dd1da2e8c67bba4ed9bd269f1c96","Readme.md":"ab18cf701392873b1f7931909c659915dec0fe8b37ddad50b7cbbc678ebf47e6","src/deflate/buffer.rs":"76bcca4e79bef412eeebdd06d2d0a4348ed9ee17edbdaa6d451d8bf03b1cde85","src/deflate/core.rs":"428abdd660bcce43de28e5d82a1082cc8f88105c882038e6041a3fdffc207121","src/deflate/mod.rs":"8ade5b9683b8d728fe5e8f5c23e0630165bfdbef3e56a18b1b729f9bbd4a4b1d","src/deflate/stream.rs":"016c82b09a989492c8c8ea89027d339fcf59a5ca2155e7026ac094ca74344712","src/inflate/core.rs":"d326880ca0c2ecfdf706839a3e94820e71000dc431d97e4b7d4c2eb3ab6f8cc0","src/inflate/mod.rs":"6a6f658cd44c47f1ba402328fb78c27b24b8700a909ddac4c0c472b12046d1fa","src/inflate/output_buffer.rs":"1ae90d03ba8c9d667fe248b6066731774afdf93cc79cd3bf90e0711b963b0b72","src/inflate/stream.rs":"b1d96270d89b549bdc09352bfbd5a4fea24b479c0057c1f50b66b30ce2eb9cc1","src/lib.rs":"b0be6fbe7198abffe5155984389817219181acabcb9ec2f501baedc6c10797c4","src/shared.rs":"a8c47fcb566591e39fcd50d44f3b4d0f567318b8ca36c8d732ee0d8c99a14906"},"package":"e7810e0be55b428ada41041c41f32c9f1a42817901b4ccf45fa3d4b6561e74c7"} \ No newline at end of file diff --git a/vendor/miniz_oxide/Cargo.toml b/vendor/miniz_oxide/Cargo.toml deleted file mode 100644 index 34a8f9a..0000000 --- a/vendor/miniz_oxide/Cargo.toml +++ /dev/null @@ -1,74 +0,0 @@ -# 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 = "2018" -name = "miniz_oxide" -version = "0.7.1" -authors = [ - "Frommi ", - "oyvindln ", -] -exclude = [ - "benches/*", - "tests/*", -] -description = "DEFLATE compression and decompression library rewritten in Rust based on miniz" -homepage = "https://github.com/Frommi/miniz_oxide/tree/master/miniz_oxide" -documentation = "https://docs.rs/miniz_oxide" -readme = "Readme.md" -keywords = [ - "zlib", - "miniz", - "deflate", - "encoding", -] -categories = ["compression"] -license = "MIT OR Zlib OR Apache-2.0" -repository = "https://github.com/Frommi/miniz_oxide/tree/master/miniz_oxide" - -[lib] -name = "miniz_oxide" - -[dependencies.adler] -version = "1.0" -default-features = false - -[dependencies.alloc] -version = "1.0.0" -optional = true -package = "rustc-std-workspace-alloc" - -[dependencies.compiler_builtins] -version = "0.1.2" -optional = true - -[dependencies.core] -version = "1.0.0" -optional = true -package = "rustc-std-workspace-core" - -[dependencies.simd-adler32] -version = "0.3" -optional = true -default-features = false - -[features] -default = ["with-alloc"] -rustc-dep-of-std = [ - "core", - "alloc", - "compiler_builtins", - "adler/rustc-dep-of-std", -] -simd = ["simd-adler32"] -std = [] -with-alloc = [] diff --git a/vendor/miniz_oxide/LICENSE b/vendor/miniz_oxide/LICENSE deleted file mode 100644 index 64c5379..0000000 --- a/vendor/miniz_oxide/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -MIT License - -Copyright (c) 2017 Frommi - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/vendor/miniz_oxide/LICENSE-APACHE.md b/vendor/miniz_oxide/LICENSE-APACHE.md deleted file mode 100644 index f433b1a..0000000 --- a/vendor/miniz_oxide/LICENSE-APACHE.md +++ /dev/null @@ -1,177 +0,0 @@ - - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS diff --git a/vendor/miniz_oxide/LICENSE-MIT.md b/vendor/miniz_oxide/LICENSE-MIT.md deleted file mode 100644 index 64c5379..0000000 --- a/vendor/miniz_oxide/LICENSE-MIT.md +++ /dev/null @@ -1,21 +0,0 @@ -MIT License - -Copyright (c) 2017 Frommi - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/vendor/miniz_oxide/LICENSE-ZLIB.md b/vendor/miniz_oxide/LICENSE-ZLIB.md deleted file mode 100644 index 7f513d1..0000000 --- a/vendor/miniz_oxide/LICENSE-ZLIB.md +++ /dev/null @@ -1,11 +0,0 @@ -Copyright (c) 2020 Frommi - -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/vendor/miniz_oxide/Readme.md b/vendor/miniz_oxide/Readme.md deleted file mode 100644 index 62687c9..0000000 --- a/vendor/miniz_oxide/Readme.md +++ /dev/null @@ -1,44 +0,0 @@ -# miniz_oxide - -A fully safe, pure rust replacement for the [miniz](https://github.com/richgel999/miniz) DEFLATE/zlib encoder/decoder. -The main intention of this crate is to be used as a back-end for the [flate2](https://github.com/alexcrichton/flate2-rs), but it can also be used on it's own. Using flate2 with the ```rust_backend``` feature provides an easy to use streaming API for miniz_oxide. - -The library is fully [no_std](https://docs.rust-embedded.org/book/intro/no-std.html). By default, the `with-alloc` feature is enabled, which requires the use of the `alloc` and `collection` crates as it allocates memory. - -The `std` feature additionally turns on things only available if `no_std` is not used. Currently this only means implementing [Error](https://doc.rust-lang.org/stable/std/error/trait.Error.html) for the `DecompressError` error struct returned by the simple decompression functions if enabled together with `with-alloc`. - -Using the library with `default-features = false` removes the dependency on `alloc` -and `collection` crates, making it suitable for systems without an allocator. -Running without allocation reduces crate functionality: - -- The `deflate` module is removed completely -- Some `inflate` functions which return a `Vec` are removed - -miniz_oxide 0.5.x and 0.6.x Requires at least rust 1.40.0 0.3.x requires at least rust 0.36.0. - -miniz_oxide features no use of unsafe code. - -miniz_oxide can optionally be made to use a simd-accelerated version of adler32 via the [simd-adler32](https://crates.io/crates/simd-adler32) crate by enabling the 'simd' feature. This is not enabled by default as due to the use of simd intrinsics, the simd-adler32 has to use unsafe. The default setup uses the [adler](https://crates.io/crates/adler) crate which features no unsafe code. - -## Usage -Simple compression/decompression: -```rust - -use miniz_oxide::deflate::compress_to_vec; -use miniz_oxide::inflate::decompress_to_vec; - -fn roundtrip(data: &[u8]) { - // Compress the input - let compressed = compress_to_vec(data, 6); - // Decompress the compressed input and limit max output size to avoid going out of memory on large/malformed input. - let decompressed = decompress_to_vec_with_limit(compressed.as_slice(), 60000).expect("Failed to decompress!"); - // Check roundtrip succeeded - assert_eq!(data, decompressed); -} - -fn main() { - roundtrip("Hello, world!".as_bytes()); -} - -``` -These simple functions will do everything in one go and are thus not recommended for use cases outside of prototyping/testing as real world data can have any size and thus result in very large memory allocations for the output Vector. Consider using miniz_oxide via [flate2](https://github.com/alexcrichton/flate2-rs) which makes it easy to do streaming (de)compression or the low-level streaming functions instead. diff --git a/vendor/miniz_oxide/src/deflate/buffer.rs b/vendor/miniz_oxide/src/deflate/buffer.rs deleted file mode 100644 index f246c07..0000000 --- a/vendor/miniz_oxide/src/deflate/buffer.rs +++ /dev/null @@ -1,58 +0,0 @@ -//! Buffer wrappers implementing default so we can allocate the buffers with `Box::default()` -//! to avoid stack copies. Box::new() doesn't at the moment, and using a vec means we would lose -//! static length info. - -use crate::deflate::core::{LZ_DICT_SIZE, MAX_MATCH_LEN}; - -/// Size of the buffer of lz77 encoded data. -pub const LZ_CODE_BUF_SIZE: usize = 64 * 1024; -/// Size of the output buffer. -pub const OUT_BUF_SIZE: usize = (LZ_CODE_BUF_SIZE * 13) / 10; -pub const LZ_DICT_FULL_SIZE: usize = LZ_DICT_SIZE + MAX_MATCH_LEN - 1 + 1; - -/// Size of hash values in the hash chains. -pub const LZ_HASH_BITS: i32 = 15; -/// How many bits to shift when updating the current hash value. -pub const LZ_HASH_SHIFT: i32 = (LZ_HASH_BITS + 2) / 3; -/// Size of the chained hash tables. -pub const LZ_HASH_SIZE: usize = 1 << LZ_HASH_BITS; - -#[inline] -pub fn update_hash(current_hash: u16, byte: u8) -> u16 { - ((current_hash << LZ_HASH_SHIFT) ^ u16::from(byte)) & (LZ_HASH_SIZE as u16 - 1) -} - -pub struct HashBuffers { - pub dict: [u8; LZ_DICT_FULL_SIZE], - pub next: [u16; LZ_DICT_SIZE], - pub hash: [u16; LZ_DICT_SIZE], -} - -impl HashBuffers { - #[inline] - pub fn reset(&mut self) { - *self = HashBuffers::default(); - } -} - -impl Default for HashBuffers { - fn default() -> HashBuffers { - HashBuffers { - dict: [0; LZ_DICT_FULL_SIZE], - next: [0; LZ_DICT_SIZE], - hash: [0; LZ_DICT_SIZE], - } - } -} - -pub struct LocalBuf { - pub b: [u8; OUT_BUF_SIZE], -} - -impl Default for LocalBuf { - fn default() -> LocalBuf { - LocalBuf { - b: [0; OUT_BUF_SIZE], - } - } -} diff --git a/vendor/miniz_oxide/src/deflate/core.rs b/vendor/miniz_oxide/src/deflate/core.rs deleted file mode 100644 index d2db260..0000000 --- a/vendor/miniz_oxide/src/deflate/core.rs +++ /dev/null @@ -1,2462 +0,0 @@ -//! Streaming compression functionality. - -use alloc::boxed::Box; -use core::convert::TryInto; -use core::{cmp, mem}; - -use super::super::*; -use super::deflate_flags::*; -use super::CompressionLevel; -use crate::deflate::buffer::{ - update_hash, HashBuffers, LocalBuf, LZ_CODE_BUF_SIZE, LZ_DICT_FULL_SIZE, LZ_HASH_BITS, - LZ_HASH_SHIFT, LZ_HASH_SIZE, OUT_BUF_SIZE, -}; -use crate::shared::{update_adler32, HUFFMAN_LENGTH_ORDER, MZ_ADLER32_INIT}; -use crate::DataFormat; - -// Currently not bubbled up outside this module, so can fill in with more -// context eventually if needed. -type Result = core::result::Result; -struct Error {} - -const MAX_PROBES_MASK: i32 = 0xFFF; - -const MAX_SUPPORTED_HUFF_CODESIZE: usize = 32; - -/// Length code for length values. -#[rustfmt::skip] -const LEN_SYM: [u16; 256] = [ - 257, 258, 259, 260, 261, 262, 263, 264, 265, 265, 266, 266, 267, 267, 268, 268, - 269, 269, 269, 269, 270, 270, 270, 270, 271, 271, 271, 271, 272, 272, 272, 272, - 273, 273, 273, 273, 273, 273, 273, 273, 274, 274, 274, 274, 274, 274, 274, 274, - 275, 275, 275, 275, 275, 275, 275, 275, 276, 276, 276, 276, 276, 276, 276, 276, - 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, - 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, - 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, - 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, - 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, - 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, - 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, - 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, - 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, - 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, - 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, - 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 285 -]; - -/// Number of extra bits for length values. -#[rustfmt::skip] -const LEN_EXTRA: [u8; 256] = [ - 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 0 -]; - -/// Distance codes for distances smaller than 512. -#[rustfmt::skip] -const SMALL_DIST_SYM: [u8; 512] = [ - 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, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, - 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, - 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, - 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, - 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, - 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, - 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, - 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17 -]; - -/// Number of extra bits for distances smaller than 512. -#[rustfmt::skip] -const SMALL_DIST_EXTRA: [u8; 512] = [ - 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, - 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, - 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, - 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, - 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, - 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, - 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, - 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, - 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, - 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, - 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, - 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7 -]; - -/// Base values to calculate distances above 512. -#[rustfmt::skip] -const LARGE_DIST_SYM: [u8; 128] = [ - 0, 0, 18, 19, 20, 20, 21, 21, 22, 22, 22, 22, 23, 23, 23, 23, - 24, 24, 24, 24, 24, 24, 24, 24, 25, 25, 25, 25, 25, 25, 25, 25, - 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, - 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 -]; - -/// Number of extra bits distances above 512. -#[rustfmt::skip] -const LARGE_DIST_EXTRA: [u8; 128] = [ - 0, 0, 8, 8, 9, 9, 9, 9, 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, - 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 -]; - -#[rustfmt::skip] -const BITMASKS: [u32; 17] = [ - 0x0000, 0x0001, 0x0003, 0x0007, 0x000F, 0x001F, 0x003F, 0x007F, 0x00FF, - 0x01FF, 0x03FF, 0x07FF, 0x0FFF, 0x1FFF, 0x3FFF, 0x7FFF, 0xFFFF -]; - -/// The maximum number of checks for matches in the hash table the compressor will make for each -/// compression level. -const NUM_PROBES: [u32; 11] = [0, 1, 6, 32, 16, 32, 128, 256, 512, 768, 1500]; - -#[derive(Copy, Clone)] -struct SymFreq { - key: u16, - sym_index: u16, -} - -pub mod deflate_flags { - /// Whether to use a zlib wrapper. - pub const TDEFL_WRITE_ZLIB_HEADER: u32 = 0x0000_1000; - /// Should we compute the adler32 checksum. - pub const TDEFL_COMPUTE_ADLER32: u32 = 0x0000_2000; - /// Should we use greedy parsing (as opposed to lazy parsing where look ahead one or more - /// bytes to check for better matches.) - pub const TDEFL_GREEDY_PARSING_FLAG: u32 = 0x0000_4000; - /// Used in miniz to skip zero-initializing hash and dict. We don't do this here, so - /// this flag is ignored. - pub const TDEFL_NONDETERMINISTIC_PARSING_FLAG: u32 = 0x0000_8000; - /// Only look for matches with a distance of 0. - pub const TDEFL_RLE_MATCHES: u32 = 0x0001_0000; - /// Only use matches that are at least 6 bytes long. - pub const TDEFL_FILTER_MATCHES: u32 = 0x0002_0000; - /// Force the compressor to only output static blocks. (Blocks using the default huffman codes - /// specified in the deflate specification.) - pub const TDEFL_FORCE_ALL_STATIC_BLOCKS: u32 = 0x0004_0000; - /// Force the compressor to only output raw/uncompressed blocks. - pub const TDEFL_FORCE_ALL_RAW_BLOCKS: u32 = 0x0008_0000; -} - -/// Strategy setting for compression. -/// -/// The non-default settings offer some special-case compression variants. -#[repr(i32)] -#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] -pub enum CompressionStrategy { - /// Don't use any of the special strategies. - Default = 0, - /// Only use matches that are at least 5 bytes long. - Filtered = 1, - /// Don't look for matches, only huffman encode the literals. - HuffmanOnly = 2, - /// Only look for matches with a distance of 1, i.e do run-length encoding only. - RLE = 3, - /// Only use static/fixed blocks. (Blocks using the default huffman codes - /// specified in the deflate specification.) - Fixed = 4, -} - -/// A list of deflate flush types. -#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] -pub enum TDEFLFlush { - /// Normal operation. - /// - /// Compress as much as there is space for, and then return waiting for more input. - None = 0, - - /// Try to flush all the current data and output an empty raw block. - Sync = 2, - - /// Same as [`Sync`][Self::Sync], but reset the dictionary so that the following data does not - /// depend on previous data. - Full = 3, - - /// Try to flush everything and end the deflate stream. - /// - /// On success this will yield a [`TDEFLStatus::Done`] return status. - Finish = 4, -} - -impl From for TDEFLFlush { - fn from(flush: MZFlush) -> Self { - match flush { - MZFlush::None => TDEFLFlush::None, - MZFlush::Sync => TDEFLFlush::Sync, - MZFlush::Full => TDEFLFlush::Full, - MZFlush::Finish => TDEFLFlush::Finish, - _ => TDEFLFlush::None, // TODO: ??? What to do ??? - } - } -} - -impl TDEFLFlush { - pub fn new(flush: i32) -> Result { - match flush { - 0 => Ok(TDEFLFlush::None), - 2 => Ok(TDEFLFlush::Sync), - 3 => Ok(TDEFLFlush::Full), - 4 => Ok(TDEFLFlush::Finish), - _ => Err(MZError::Param), - } - } -} - -/// Return status of compression. -#[repr(i32)] -#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] -pub enum TDEFLStatus { - /// Usage error. - /// - /// This indicates that either the [`CompressorOxide`] experienced a previous error, or the - /// stream has already been [`TDEFLFlush::Finish`]'d. - BadParam = -2, - - /// Error putting data into output buffer. - /// - /// This usually indicates a too-small buffer. - PutBufFailed = -1, - - /// Compression succeeded normally. - Okay = 0, - - /// Compression succeeded and the deflate stream was ended. - /// - /// This is the result of calling compression with [`TDEFLFlush::Finish`]. - Done = 1, -} - -const MAX_HUFF_SYMBOLS: usize = 288; -/// Size of hash chain for fast compression mode. -const LEVEL1_HASH_SIZE_MASK: u32 = 4095; -/// The number of huffman tables used by the compressor. -/// Literal/length, Distances and Length of the huffman codes for the other two tables. -const MAX_HUFF_TABLES: usize = 3; -/// Literal/length codes -const MAX_HUFF_SYMBOLS_0: usize = 288; -/// Distance codes. -const MAX_HUFF_SYMBOLS_1: usize = 32; -/// Huffman length values. -const MAX_HUFF_SYMBOLS_2: usize = 19; -/// Size of the chained hash table. -pub(crate) const LZ_DICT_SIZE: usize = 32_768; -/// Mask used when stepping through the hash chains. -const LZ_DICT_SIZE_MASK: usize = (LZ_DICT_SIZE as u32 - 1) as usize; -/// The minimum length of a match. -const MIN_MATCH_LEN: u8 = 3; -/// The maximum length of a match. -pub(crate) const MAX_MATCH_LEN: usize = 258; - -const DEFAULT_FLAGS: u32 = NUM_PROBES[4] | TDEFL_WRITE_ZLIB_HEADER; - -mod zlib { - const DEFAULT_CM: u8 = 8; - const DEFAULT_CINFO: u8 = 7 << 4; - const _DEFAULT_FDICT: u8 = 0; - const DEFAULT_CMF: u8 = DEFAULT_CM | DEFAULT_CINFO; - /// The 16-bit value consisting of CMF and FLG must be divisible by this to be valid. - const FCHECK_DIVISOR: u8 = 31; - - /// Generate FCHECK from CMF and FLG (without FCKECH )so that they are correct according to the - /// specification, i.e (CMF*256 + FCHK) % 31 = 0. - /// Returns flg with the FCHKECK bits added (any existing FCHECK bits are ignored). - fn add_fcheck(cmf: u8, flg: u8) -> u8 { - let rem = ((usize::from(cmf) * 256) + usize::from(flg)) % usize::from(FCHECK_DIVISOR); - - // Clear existing FCHECK if any - let flg = flg & 0b11100000; - - // Casting is safe as rem can't overflow since it is a value mod 31 - // We can simply add the value to flg as (31 - rem) will never be above 2^5 - flg + (FCHECK_DIVISOR - rem as u8) - } - - fn zlib_level_from_flags(flags: u32) -> u8 { - use super::NUM_PROBES; - - let num_probes = flags & (super::MAX_PROBES_MASK as u32); - if flags & super::TDEFL_GREEDY_PARSING_FLAG != 0 { - if num_probes <= 1 { - 0 - } else { - 1 - } - } else if num_probes >= NUM_PROBES[9] { - 3 - } else { - 2 - } - } - - /// Get the zlib header for the level using the default window size and no - /// dictionary. - fn header_from_level(level: u8) -> [u8; 2] { - let cmf = DEFAULT_CMF; - [cmf, add_fcheck(cmf, (level as u8) << 6)] - } - - /// Create a zlib header from the given compression flags. - /// Only level is considered. - pub fn header_from_flags(flags: u32) -> [u8; 2] { - let level = zlib_level_from_flags(flags); - header_from_level(level) - } - - #[cfg(test)] - mod test { - #[test] - fn zlib() { - use super::super::*; - use super::*; - - let test_level = |level, expected| { - let flags = create_comp_flags_from_zip_params( - level, - MZ_DEFAULT_WINDOW_BITS, - CompressionStrategy::Default as i32, - ); - assert_eq!(zlib_level_from_flags(flags), expected); - }; - - assert_eq!(zlib_level_from_flags(DEFAULT_FLAGS), 2); - test_level(0, 0); - test_level(1, 0); - test_level(2, 1); - test_level(3, 1); - for i in 4..=8 { - test_level(i, 2) - } - test_level(9, 3); - test_level(10, 3); - } - - #[test] - fn test_header() { - let header = super::header_from_level(3); - assert_eq!( - ((usize::from(header[0]) * 256) + usize::from(header[1])) % 31, - 0 - ); - } - } -} - -fn memset(slice: &mut [T], val: T) { - for x in slice { - *x = val - } -} - -#[cfg(test)] -#[inline] -fn write_u16_le(val: u16, slice: &mut [u8], pos: usize) { - slice[pos] = val as u8; - slice[pos + 1] = (val >> 8) as u8; -} - -// Read the two bytes starting at pos and interpret them as an u16. -#[inline] -const fn read_u16_le(slice: &[u8], pos: usize) -> u16 { - // The compiler is smart enough to optimize this into an unaligned load. - slice[pos] as u16 | ((slice[pos + 1] as u16) << 8) -} - -/// Main compression struct. -pub struct CompressorOxide { - lz: LZOxide, - params: ParamsOxide, - huff: Box, - dict: DictOxide, -} - -impl CompressorOxide { - /// Create a new `CompressorOxide` with the given flags. - /// - /// # Notes - /// This function may be changed to take different parameters in the future. - pub fn new(flags: u32) -> Self { - CompressorOxide { - lz: LZOxide::new(), - params: ParamsOxide::new(flags), - /// Put HuffmanOxide on the heap with default trick to avoid - /// excessive stack copies. - huff: Box::default(), - dict: DictOxide::new(flags), - } - } - - /// Get the adler32 checksum of the currently encoded data. - pub const fn adler32(&self) -> u32 { - self.params.adler32 - } - - /// Get the return status of the previous [`compress`](fn.compress.html) - /// call with this compressor. - pub const fn prev_return_status(&self) -> TDEFLStatus { - self.params.prev_return_status - } - - /// Get the raw compressor flags. - /// - /// # Notes - /// This function may be deprecated or changed in the future to use more rust-style flags. - pub const fn flags(&self) -> i32 { - self.params.flags as i32 - } - - /// Returns whether the compressor is wrapping the data in a zlib format or not. - pub fn data_format(&self) -> DataFormat { - if (self.params.flags & TDEFL_WRITE_ZLIB_HEADER) != 0 { - DataFormat::Zlib - } else { - DataFormat::Raw - } - } - - /// Reset the state of the compressor, keeping the same parameters. - /// - /// This avoids re-allocating data. - pub fn reset(&mut self) { - // LZ buf and huffman has no settings or dynamic memory - // that needs to be saved, so we simply replace them. - self.lz = LZOxide::new(); - self.params.reset(); - *self.huff = HuffmanOxide::default(); - self.dict.reset(); - } - - /// Set the compression level of the compressor. - /// - /// Using this to change level after compression has started is supported. - /// # Notes - /// The compression strategy will be reset to the default one when this is called. - pub fn set_compression_level(&mut self, level: CompressionLevel) { - let format = self.data_format(); - self.set_format_and_level(format, level as u8); - } - - /// Set the compression level of the compressor using an integer value. - /// - /// Using this to change level after compression has started is supported. - /// # Notes - /// The compression strategy will be reset to the default one when this is called. - pub fn set_compression_level_raw(&mut self, level: u8) { - let format = self.data_format(); - self.set_format_and_level(format, level); - } - - /// Update the compression settings of the compressor. - /// - /// Changing the `DataFormat` after compression has started will result in - /// a corrupted stream. - /// - /// # Notes - /// This function mainly intended for setting the initial settings after e.g creating with - /// `default` or after calling `CompressorOxide::reset()`, and behaviour may be changed - /// to disallow calling it after starting compression in the future. - pub fn set_format_and_level(&mut self, data_format: DataFormat, level: u8) { - let flags = create_comp_flags_from_zip_params( - level.into(), - data_format.to_window_bits(), - CompressionStrategy::Default as i32, - ); - self.params.update_flags(flags); - self.dict.update_flags(flags); - } -} - -impl Default for CompressorOxide { - /// Initialize the compressor with a level of 4, zlib wrapper and - /// the default strategy. - fn default() -> Self { - CompressorOxide { - lz: LZOxide::new(), - params: ParamsOxide::new(DEFAULT_FLAGS), - /// Put HuffmanOxide on the heap with default trick to avoid - /// excessive stack copies. - huff: Box::default(), - dict: DictOxide::new(DEFAULT_FLAGS), - } - } -} - -/// Callback function and user used in `compress_to_output`. -pub struct CallbackFunc<'a> { - pub put_buf_func: &'a mut dyn FnMut(&[u8]) -> bool, -} - -impl<'a> CallbackFunc<'a> { - fn flush_output( - &mut self, - saved_output: SavedOutputBufferOxide, - params: &mut ParamsOxide, - ) -> i32 { - // TODO: As this could be unsafe since - // we can't verify the function pointer - // this whole function should maybe be unsafe as well. - let call_success = (self.put_buf_func)(¶ms.local_buf.b[0..saved_output.pos as usize]); - - if !call_success { - params.prev_return_status = TDEFLStatus::PutBufFailed; - return params.prev_return_status as i32; - } - - params.flush_remaining as i32 - } -} - -struct CallbackBuf<'a> { - pub out_buf: &'a mut [u8], -} - -impl<'a> CallbackBuf<'a> { - fn flush_output( - &mut self, - saved_output: SavedOutputBufferOxide, - params: &mut ParamsOxide, - ) -> i32 { - if saved_output.local { - let n = cmp::min( - saved_output.pos as usize, - self.out_buf.len() - params.out_buf_ofs, - ); - (&mut self.out_buf[params.out_buf_ofs..params.out_buf_ofs + n]) - .copy_from_slice(¶ms.local_buf.b[..n]); - - params.out_buf_ofs += n; - if saved_output.pos != n { - params.flush_ofs = n as u32; - params.flush_remaining = (saved_output.pos - n) as u32; - } - } else { - params.out_buf_ofs += saved_output.pos; - } - - params.flush_remaining as i32 - } -} - -enum CallbackOut<'a> { - Func(CallbackFunc<'a>), - Buf(CallbackBuf<'a>), -} - -impl<'a> CallbackOut<'a> { - fn new_output_buffer<'b>( - &'b mut self, - local_buf: &'b mut [u8], - out_buf_ofs: usize, - ) -> OutputBufferOxide<'b> { - let is_local; - let buf_len = OUT_BUF_SIZE - 16; - let chosen_buffer = match *self { - CallbackOut::Buf(ref mut cb) if cb.out_buf.len() - out_buf_ofs >= OUT_BUF_SIZE => { - is_local = false; - &mut cb.out_buf[out_buf_ofs..out_buf_ofs + buf_len] - } - _ => { - is_local = true; - &mut local_buf[..buf_len] - } - }; - - OutputBufferOxide { - inner: chosen_buffer, - inner_pos: 0, - local: is_local, - bit_buffer: 0, - bits_in: 0, - } - } -} - -struct CallbackOxide<'a> { - in_buf: Option<&'a [u8]>, - in_buf_size: Option<&'a mut usize>, - out_buf_size: Option<&'a mut usize>, - out: CallbackOut<'a>, -} - -impl<'a> CallbackOxide<'a> { - fn new_callback_buf(in_buf: &'a [u8], out_buf: &'a mut [u8]) -> Self { - CallbackOxide { - in_buf: Some(in_buf), - in_buf_size: None, - out_buf_size: None, - out: CallbackOut::Buf(CallbackBuf { out_buf }), - } - } - - fn new_callback_func(in_buf: &'a [u8], callback_func: CallbackFunc<'a>) -> Self { - CallbackOxide { - in_buf: Some(in_buf), - in_buf_size: None, - out_buf_size: None, - out: CallbackOut::Func(callback_func), - } - } - - fn update_size(&mut self, in_size: Option, out_size: Option) { - if let (Some(in_size), Some(size)) = (in_size, self.in_buf_size.as_mut()) { - **size = in_size; - } - - if let (Some(out_size), Some(size)) = (out_size, self.out_buf_size.as_mut()) { - **size = out_size - } - } - - fn flush_output( - &mut self, - saved_output: SavedOutputBufferOxide, - params: &mut ParamsOxide, - ) -> i32 { - if saved_output.pos == 0 { - return params.flush_remaining as i32; - } - - self.update_size(Some(params.src_pos), None); - match self.out { - CallbackOut::Func(ref mut cf) => cf.flush_output(saved_output, params), - CallbackOut::Buf(ref mut cb) => cb.flush_output(saved_output, params), - } - } -} - -struct OutputBufferOxide<'a> { - pub inner: &'a mut [u8], - pub inner_pos: usize, - pub local: bool, - - pub bit_buffer: u32, - pub bits_in: u32, -} - -impl<'a> OutputBufferOxide<'a> { - fn put_bits(&mut self, bits: u32, len: u32) { - assert!(bits <= ((1u32 << len) - 1u32)); - self.bit_buffer |= bits << self.bits_in; - self.bits_in += len; - while self.bits_in >= 8 { - self.inner[self.inner_pos] = self.bit_buffer as u8; - self.inner_pos += 1; - self.bit_buffer >>= 8; - self.bits_in -= 8; - } - } - - const fn save(&self) -> SavedOutputBufferOxide { - SavedOutputBufferOxide { - pos: self.inner_pos, - bit_buffer: self.bit_buffer, - bits_in: self.bits_in, - local: self.local, - } - } - - fn load(&mut self, saved: SavedOutputBufferOxide) { - self.inner_pos = saved.pos; - self.bit_buffer = saved.bit_buffer; - self.bits_in = saved.bits_in; - self.local = saved.local; - } - - fn pad_to_bytes(&mut self) { - if self.bits_in != 0 { - let len = 8 - self.bits_in; - self.put_bits(0, len); - } - } -} - -struct SavedOutputBufferOxide { - pub pos: usize, - pub bit_buffer: u32, - pub bits_in: u32, - pub local: bool, -} - -struct BitBuffer { - pub bit_buffer: u64, - pub bits_in: u32, -} - -impl BitBuffer { - fn put_fast(&mut self, bits: u64, len: u32) { - self.bit_buffer |= bits << self.bits_in; - self.bits_in += len; - } - - fn flush(&mut self, output: &mut OutputBufferOxide) -> Result<()> { - let pos = output.inner_pos; - { - // isolation to please borrow checker - let inner = &mut output.inner[pos..pos + 8]; - let bytes = u64::to_le_bytes(self.bit_buffer); - inner.copy_from_slice(&bytes); - } - match output.inner_pos.checked_add((self.bits_in >> 3) as usize) { - Some(n) if n <= output.inner.len() => output.inner_pos = n, - _ => return Err(Error {}), - } - self.bit_buffer >>= self.bits_in & !7; - self.bits_in &= 7; - Ok(()) - } -} - -/// A struct containing data about huffman codes and symbol frequencies. -/// -/// NOTE: Only the literal/lengths have enough symbols to actually use -/// the full array. It's unclear why it's defined like this in miniz, -/// it could be for cache/alignment reasons. -struct HuffmanOxide { - /// Number of occurrences of each symbol. - pub count: [[u16; MAX_HUFF_SYMBOLS]; MAX_HUFF_TABLES], - /// The bits of the huffman code assigned to the symbol - pub codes: [[u16; MAX_HUFF_SYMBOLS]; MAX_HUFF_TABLES], - /// The length of the huffman code assigned to the symbol. - pub code_sizes: [[u8; MAX_HUFF_SYMBOLS]; MAX_HUFF_TABLES], -} - -/// Tables used for literal/lengths in `HuffmanOxide`. -const LITLEN_TABLE: usize = 0; -/// Tables for distances. -const DIST_TABLE: usize = 1; -/// Tables for the run-length encoded huffman lengths for literals/lengths/distances. -const HUFF_CODES_TABLE: usize = 2; - -/// Status of RLE encoding of huffman code lengths. -struct Rle { - pub z_count: u32, - pub repeat_count: u32, - pub prev_code_size: u8, -} - -impl Rle { - fn prev_code_size( - &mut self, - packed_code_sizes: &mut [u8], - packed_pos: &mut usize, - h: &mut HuffmanOxide, - ) -> Result<()> { - let mut write = |buf| write(buf, packed_code_sizes, packed_pos); - let counts = &mut h.count[HUFF_CODES_TABLE]; - if self.repeat_count != 0 { - if self.repeat_count < 3 { - counts[self.prev_code_size as usize] = - counts[self.prev_code_size as usize].wrapping_add(self.repeat_count as u16); - let code = self.prev_code_size; - write(&[code, code, code][..self.repeat_count as usize])?; - } else { - counts[16] = counts[16].wrapping_add(1); - write(&[16, (self.repeat_count - 3) as u8][..])?; - } - self.repeat_count = 0; - } - - Ok(()) - } - - fn zero_code_size( - &mut self, - packed_code_sizes: &mut [u8], - packed_pos: &mut usize, - h: &mut HuffmanOxide, - ) -> Result<()> { - let mut write = |buf| write(buf, packed_code_sizes, packed_pos); - let counts = &mut h.count[HUFF_CODES_TABLE]; - if self.z_count != 0 { - if self.z_count < 3 { - counts[0] = counts[0].wrapping_add(self.z_count as u16); - write(&[0, 0, 0][..self.z_count as usize])?; - } else if self.z_count <= 10 { - counts[17] = counts[17].wrapping_add(1); - write(&[17, (self.z_count - 3) as u8][..])?; - } else { - counts[18] = counts[18].wrapping_add(1); - write(&[18, (self.z_count - 11) as u8][..])?; - } - self.z_count = 0; - } - - Ok(()) - } -} - -fn write(src: &[u8], dst: &mut [u8], dst_pos: &mut usize) -> Result<()> { - match dst.get_mut(*dst_pos..*dst_pos + src.len()) { - Some(s) => s.copy_from_slice(src), - None => return Err(Error {}), - } - *dst_pos += src.len(); - Ok(()) -} - -impl Default for HuffmanOxide { - fn default() -> Self { - HuffmanOxide { - count: [[0; MAX_HUFF_SYMBOLS]; MAX_HUFF_TABLES], - codes: [[0; MAX_HUFF_SYMBOLS]; MAX_HUFF_TABLES], - code_sizes: [[0; MAX_HUFF_SYMBOLS]; MAX_HUFF_TABLES], - } - } -} - -impl HuffmanOxide { - fn radix_sort_symbols<'a>( - symbols0: &'a mut [SymFreq], - symbols1: &'a mut [SymFreq], - ) -> &'a mut [SymFreq] { - let mut hist = [[0; 256]; 2]; - - for freq in symbols0.iter() { - hist[0][(freq.key & 0xFF) as usize] += 1; - hist[1][((freq.key >> 8) & 0xFF) as usize] += 1; - } - - let mut n_passes = 2; - if symbols0.len() == hist[1][0] { - n_passes -= 1; - } - - let mut current_symbols = symbols0; - let mut new_symbols = symbols1; - - for (pass, hist_item) in hist.iter().enumerate().take(n_passes) { - let mut offsets = [0; 256]; - let mut offset = 0; - for i in 0..256 { - offsets[i] = offset; - offset += hist_item[i]; - } - - for sym in current_symbols.iter() { - let j = ((sym.key >> (pass * 8)) & 0xFF) as usize; - new_symbols[offsets[j]] = *sym; - offsets[j] += 1; - } - - mem::swap(&mut current_symbols, &mut new_symbols); - } - - current_symbols - } - - fn calculate_minimum_redundancy(symbols: &mut [SymFreq]) { - match symbols.len() { - 0 => (), - 1 => symbols[0].key = 1, - n => { - symbols[0].key += symbols[1].key; - let mut root = 0; - let mut leaf = 2; - for next in 1..n - 1 { - if (leaf >= n) || (symbols[root].key < symbols[leaf].key) { - symbols[next].key = symbols[root].key; - symbols[root].key = next as u16; - root += 1; - } else { - symbols[next].key = symbols[leaf].key; - leaf += 1; - } - - if (leaf >= n) || (root < next && symbols[root].key < symbols[leaf].key) { - symbols[next].key = symbols[next].key.wrapping_add(symbols[root].key); - symbols[root].key = next as u16; - root += 1; - } else { - symbols[next].key = symbols[next].key.wrapping_add(symbols[leaf].key); - leaf += 1; - } - } - - symbols[n - 2].key = 0; - for next in (0..n - 2).rev() { - symbols[next].key = symbols[symbols[next].key as usize].key + 1; - } - - let mut avbl = 1; - let mut used = 0; - let mut dpth = 0; - let mut root = (n - 2) as i32; - let mut next = (n - 1) as i32; - while avbl > 0 { - while (root >= 0) && (symbols[root as usize].key == dpth) { - used += 1; - root -= 1; - } - while avbl > used { - symbols[next as usize].key = dpth; - next -= 1; - avbl -= 1; - } - avbl = 2 * used; - dpth += 1; - used = 0; - } - } - } - } - - fn enforce_max_code_size(num_codes: &mut [i32], code_list_len: usize, max_code_size: usize) { - if code_list_len <= 1 { - return; - } - - num_codes[max_code_size] += num_codes[max_code_size + 1..].iter().sum::(); - let total = num_codes[1..=max_code_size] - .iter() - .rev() - .enumerate() - .fold(0u32, |total, (i, &x)| total + ((x as u32) << i)); - - for _ in (1 << max_code_size)..total { - num_codes[max_code_size] -= 1; - for i in (1..max_code_size).rev() { - if num_codes[i] != 0 { - num_codes[i] -= 1; - num_codes[i + 1] += 2; - break; - } - } - } - } - - fn optimize_table( - &mut self, - table_num: usize, - table_len: usize, - code_size_limit: usize, - static_table: bool, - ) { - let mut num_codes = [0i32; MAX_SUPPORTED_HUFF_CODESIZE + 1]; - let mut next_code = [0u32; MAX_SUPPORTED_HUFF_CODESIZE + 1]; - - if static_table { - for &code_size in &self.code_sizes[table_num][..table_len] { - num_codes[code_size as usize] += 1; - } - } else { - let mut symbols0 = [SymFreq { - key: 0, - sym_index: 0, - }; MAX_HUFF_SYMBOLS]; - let mut symbols1 = [SymFreq { - key: 0, - sym_index: 0, - }; MAX_HUFF_SYMBOLS]; - - let mut num_used_symbols = 0; - for i in 0..table_len { - if self.count[table_num][i] != 0 { - symbols0[num_used_symbols] = SymFreq { - key: self.count[table_num][i], - sym_index: i as u16, - }; - num_used_symbols += 1; - } - } - - let symbols = Self::radix_sort_symbols( - &mut symbols0[..num_used_symbols], - &mut symbols1[..num_used_symbols], - ); - Self::calculate_minimum_redundancy(symbols); - - for symbol in symbols.iter() { - num_codes[symbol.key as usize] += 1; - } - - Self::enforce_max_code_size(&mut num_codes, num_used_symbols, code_size_limit); - - memset(&mut self.code_sizes[table_num][..], 0); - memset(&mut self.codes[table_num][..], 0); - - let mut last = num_used_symbols; - for (i, &num_item) in num_codes - .iter() - .enumerate() - .take(code_size_limit + 1) - .skip(1) - { - let first = last - num_item as usize; - for symbol in &symbols[first..last] { - self.code_sizes[table_num][symbol.sym_index as usize] = i as u8; - } - last = first; - } - } - - let mut j = 0; - next_code[1] = 0; - for i in 2..=code_size_limit { - j = (j + num_codes[i - 1]) << 1; - next_code[i] = j as u32; - } - - for (&code_size, huff_code) in self.code_sizes[table_num] - .iter() - .take(table_len) - .zip(self.codes[table_num].iter_mut().take(table_len)) - { - if code_size == 0 { - continue; - } - - let mut code = next_code[code_size as usize]; - next_code[code_size as usize] += 1; - - let mut rev_code = 0; - for _ in 0..code_size { - rev_code = (rev_code << 1) | (code & 1); - code >>= 1; - } - *huff_code = rev_code as u16; - } - } - - fn start_static_block(&mut self, output: &mut OutputBufferOxide) { - memset(&mut self.code_sizes[LITLEN_TABLE][0..144], 8); - memset(&mut self.code_sizes[LITLEN_TABLE][144..256], 9); - memset(&mut self.code_sizes[LITLEN_TABLE][256..280], 7); - memset(&mut self.code_sizes[LITLEN_TABLE][280..288], 8); - - memset(&mut self.code_sizes[DIST_TABLE][..32], 5); - - self.optimize_table(LITLEN_TABLE, 288, 15, true); - self.optimize_table(DIST_TABLE, 32, 15, true); - - output.put_bits(0b01, 2) - } - - fn start_dynamic_block(&mut self, output: &mut OutputBufferOxide) -> Result<()> { - // There will always be one, and only one end of block code. - self.count[0][256] = 1; - - self.optimize_table(0, MAX_HUFF_SYMBOLS_0, 15, false); - self.optimize_table(1, MAX_HUFF_SYMBOLS_1, 15, false); - - let num_lit_codes = 286 - - &self.code_sizes[0][257..286] - .iter() - .rev() - .take_while(|&x| *x == 0) - .count(); - - let num_dist_codes = 30 - - &self.code_sizes[1][1..30] - .iter() - .rev() - .take_while(|&x| *x == 0) - .count(); - - let mut code_sizes_to_pack = [0u8; MAX_HUFF_SYMBOLS_0 + MAX_HUFF_SYMBOLS_1]; - let mut packed_code_sizes = [0u8; MAX_HUFF_SYMBOLS_0 + MAX_HUFF_SYMBOLS_1]; - - let total_code_sizes_to_pack = num_lit_codes + num_dist_codes; - - code_sizes_to_pack[..num_lit_codes].copy_from_slice(&self.code_sizes[0][..num_lit_codes]); - - code_sizes_to_pack[num_lit_codes..total_code_sizes_to_pack] - .copy_from_slice(&self.code_sizes[1][..num_dist_codes]); - - let mut rle = Rle { - z_count: 0, - repeat_count: 0, - prev_code_size: 0xFF, - }; - - memset(&mut self.count[HUFF_CODES_TABLE][..MAX_HUFF_SYMBOLS_2], 0); - - let mut packed_pos = 0; - for &code_size in &code_sizes_to_pack[..total_code_sizes_to_pack] { - if code_size == 0 { - rle.prev_code_size(&mut packed_code_sizes, &mut packed_pos, self)?; - rle.z_count += 1; - if rle.z_count == 138 { - rle.zero_code_size(&mut packed_code_sizes, &mut packed_pos, self)?; - } - } else { - rle.zero_code_size(&mut packed_code_sizes, &mut packed_pos, self)?; - if code_size != rle.prev_code_size { - rle.prev_code_size(&mut packed_code_sizes, &mut packed_pos, self)?; - self.count[HUFF_CODES_TABLE][code_size as usize] = - self.count[HUFF_CODES_TABLE][code_size as usize].wrapping_add(1); - write(&[code_size], &mut packed_code_sizes, &mut packed_pos)?; - } else { - rle.repeat_count += 1; - if rle.repeat_count == 6 { - rle.prev_code_size(&mut packed_code_sizes, &mut packed_pos, self)?; - } - } - } - rle.prev_code_size = code_size; - } - - if rle.repeat_count != 0 { - rle.prev_code_size(&mut packed_code_sizes, &mut packed_pos, self)?; - } else { - rle.zero_code_size(&mut packed_code_sizes, &mut packed_pos, self)?; - } - - self.optimize_table(2, MAX_HUFF_SYMBOLS_2, 7, false); - - output.put_bits(2, 2); - - output.put_bits((num_lit_codes - 257) as u32, 5); - output.put_bits((num_dist_codes - 1) as u32, 5); - - let mut num_bit_lengths = 18 - - HUFFMAN_LENGTH_ORDER - .iter() - .rev() - .take_while(|&swizzle| self.code_sizes[HUFF_CODES_TABLE][*swizzle as usize] == 0) - .count(); - - num_bit_lengths = cmp::max(4, num_bit_lengths + 1); - output.put_bits(num_bit_lengths as u32 - 4, 4); - for &swizzle in &HUFFMAN_LENGTH_ORDER[..num_bit_lengths] { - output.put_bits( - u32::from(self.code_sizes[HUFF_CODES_TABLE][swizzle as usize]), - 3, - ); - } - - let mut packed_code_size_index = 0; - while packed_code_size_index < packed_pos { - let code = packed_code_sizes[packed_code_size_index] as usize; - packed_code_size_index += 1; - assert!(code < MAX_HUFF_SYMBOLS_2); - output.put_bits( - u32::from(self.codes[HUFF_CODES_TABLE][code]), - u32::from(self.code_sizes[HUFF_CODES_TABLE][code]), - ); - if code >= 16 { - output.put_bits( - u32::from(packed_code_sizes[packed_code_size_index]), - [2, 3, 7][code - 16], - ); - packed_code_size_index += 1; - } - } - - Ok(()) - } -} - -struct DictOxide { - /// The maximum number of checks in the hash chain, for the initial, - /// and the lazy match respectively. - pub max_probes: [u32; 2], - /// Buffer of input data. - /// Padded with 1 byte to simplify matching code in `compress_fast`. - pub b: Box, - - pub code_buf_dict_pos: usize, - pub lookahead_size: usize, - pub lookahead_pos: usize, - pub size: usize, -} - -const fn probes_from_flags(flags: u32) -> [u32; 2] { - [ - 1 + ((flags & 0xFFF) + 2) / 3, - 1 + (((flags & 0xFFF) >> 2) + 2) / 3, - ] -} - -impl DictOxide { - fn new(flags: u32) -> Self { - DictOxide { - max_probes: probes_from_flags(flags), - b: Box::default(), - code_buf_dict_pos: 0, - lookahead_size: 0, - lookahead_pos: 0, - size: 0, - } - } - - fn update_flags(&mut self, flags: u32) { - self.max_probes = probes_from_flags(flags); - } - - fn reset(&mut self) { - self.b.reset(); - self.code_buf_dict_pos = 0; - self.lookahead_size = 0; - self.lookahead_pos = 0; - self.size = 0; - } - - /// Do an unaligned read of the data at `pos` in the dictionary and treat it as if it was of - /// type T. - #[inline] - fn read_unaligned_u32(&self, pos: usize) -> u32 { - // Masking the value here helps avoid bounds checks. - let pos = (pos & LZ_DICT_SIZE_MASK) as usize; - let end = pos + 4; - // Somehow this assertion makes things faster. - assert!(end < LZ_DICT_FULL_SIZE); - - let bytes: [u8; 4] = self.b.dict[pos..end].try_into().unwrap(); - u32::from_le_bytes(bytes) - } - - /// Do an unaligned read of the data at `pos` in the dictionary and treat it as if it was of - /// type T. - #[inline] - fn read_unaligned_u64(&self, pos: usize) -> u64 { - let pos = pos as usize; - let bytes: [u8; 8] = self.b.dict[pos..pos + 8].try_into().unwrap(); - u64::from_le_bytes(bytes) - } - - /// Do an unaligned read of the data at `pos` in the dictionary and treat it as if it was of - /// type T. - #[inline] - fn read_as_u16(&self, pos: usize) -> u16 { - read_u16_le(&self.b.dict[..], pos) - } - - /// Try to find a match for the data at lookahead_pos in the dictionary that is - /// longer than `match_len`. - /// Returns a tuple containing (match_distance, match_length). Will be equal to the input - /// values if no better matches were found. - fn find_match( - &self, - lookahead_pos: usize, - max_dist: usize, - max_match_len: u32, - mut match_dist: u32, - mut match_len: u32, - ) -> (u32, u32) { - // Clamp the match len and max_match_len to be valid. (It should be when this is called, but - // do it for now just in case for safety reasons.) - // This should normally end up as at worst conditional moves, - // so it shouldn't slow us down much. - // TODO: Statically verify these so we don't need to do this. - let max_match_len = cmp::min(MAX_MATCH_LEN as u32, max_match_len); - match_len = cmp::max(match_len, 1); - - let pos = lookahead_pos as usize & LZ_DICT_SIZE_MASK; - let mut probe_pos = pos; - // Number of probes into the hash chains. - let mut num_probes_left = self.max_probes[(match_len >= 32) as usize]; - - // If we already have a match of the full length don't bother searching for another one. - if max_match_len <= match_len { - return (match_dist, match_len); - } - - // Read the last byte of the current match, and the next one, used to compare matches. - let mut c01: u16 = self.read_as_u16(pos as usize + match_len as usize - 1); - // Read the two bytes at the end position of the current match. - let s01: u16 = self.read_as_u16(pos as usize); - - 'outer: loop { - let mut dist; - 'found: loop { - num_probes_left -= 1; - if num_probes_left == 0 { - // We have done as many probes in the hash chain as the current compression - // settings allow, so return the best match we found, if any. - return (match_dist, match_len); - } - - for _ in 0..3 { - let next_probe_pos = self.b.next[probe_pos as usize] as usize; - - dist = (lookahead_pos - next_probe_pos) & 0xFFFF; - if next_probe_pos == 0 || dist > max_dist { - // We reached the end of the hash chain, or the next value is further away - // than the maximum allowed distance, so return the best match we found, if - // any. - return (match_dist, match_len); - } - - // Mask the position value to get the position in the hash chain of the next - // position to match against. - probe_pos = next_probe_pos & LZ_DICT_SIZE_MASK; - - if self.read_as_u16((probe_pos + match_len as usize - 1) as usize) == c01 { - break 'found; - } - } - } - - if dist == 0 { - // We've looked through the whole match range, so return the best match we - // found. - return (match_dist, match_len); - } - - // Check if the two first bytes match. - if self.read_as_u16(probe_pos as usize) != s01 { - continue; - } - - let mut p = pos + 2; - let mut q = probe_pos + 2; - // The first two bytes matched, so check the full length of the match. - for _ in 0..32 { - let p_data: u64 = self.read_unaligned_u64(p); - let q_data: u64 = self.read_unaligned_u64(q); - // Compare of 8 bytes at a time by using unaligned loads of 64-bit integers. - let xor_data = p_data ^ q_data; - if xor_data == 0 { - p += 8; - q += 8; - } else { - // If not all of the last 8 bytes matched, check how may of them did. - let trailing = xor_data.trailing_zeros(); - - let probe_len = p - pos + (trailing as usize >> 3); - if probe_len > match_len as usize { - match_dist = dist as u32; - match_len = cmp::min(max_match_len, probe_len as u32); - if match_len == max_match_len { - // We found a match that had the maximum allowed length, - // so there is now point searching further. - return (match_dist, match_len); - } - // We found a better match, so save the last two bytes for further match - // comparisons. - c01 = self.read_as_u16(pos + match_len as usize - 1) - } - continue 'outer; - } - } - - return (dist as u32, cmp::min(max_match_len, MAX_MATCH_LEN as u32)); - } - } -} - -struct ParamsOxide { - pub flags: u32, - pub greedy_parsing: bool, - pub block_index: u32, - - pub saved_match_dist: u32, - pub saved_match_len: u32, - pub saved_lit: u8, - - pub flush: TDEFLFlush, - pub flush_ofs: u32, - pub flush_remaining: u32, - pub finished: bool, - - pub adler32: u32, - - pub src_pos: usize, - - pub out_buf_ofs: usize, - pub prev_return_status: TDEFLStatus, - - pub saved_bit_buffer: u32, - pub saved_bits_in: u32, - - pub local_buf: Box, -} - -impl ParamsOxide { - fn new(flags: u32) -> Self { - ParamsOxide { - flags, - greedy_parsing: flags & TDEFL_GREEDY_PARSING_FLAG != 0, - block_index: 0, - saved_match_dist: 0, - saved_match_len: 0, - saved_lit: 0, - flush: TDEFLFlush::None, - flush_ofs: 0, - flush_remaining: 0, - finished: false, - adler32: MZ_ADLER32_INIT, - src_pos: 0, - out_buf_ofs: 0, - prev_return_status: TDEFLStatus::Okay, - saved_bit_buffer: 0, - saved_bits_in: 0, - local_buf: Box::default(), - } - } - - fn update_flags(&mut self, flags: u32) { - self.flags = flags; - self.greedy_parsing = self.flags & TDEFL_GREEDY_PARSING_FLAG != 0; - } - - /// Reset state, saving settings. - fn reset(&mut self) { - self.block_index = 0; - self.saved_match_len = 0; - self.saved_match_dist = 0; - self.saved_lit = 0; - self.flush = TDEFLFlush::None; - self.flush_ofs = 0; - self.flush_remaining = 0; - self.finished = false; - self.adler32 = MZ_ADLER32_INIT; - self.src_pos = 0; - self.out_buf_ofs = 0; - self.prev_return_status = TDEFLStatus::Okay; - self.saved_bit_buffer = 0; - self.saved_bits_in = 0; - self.local_buf.b = [0; OUT_BUF_SIZE]; - } -} - -struct LZOxide { - pub codes: [u8; LZ_CODE_BUF_SIZE], - pub code_position: usize, - pub flag_position: usize, - - // The total number of bytes in the current block. - // (Could maybe use usize, but it's not possible to exceed a block size of ) - pub total_bytes: u32, - pub num_flags_left: u32, -} - -impl LZOxide { - const fn new() -> Self { - LZOxide { - codes: [0; LZ_CODE_BUF_SIZE], - code_position: 1, - flag_position: 0, - total_bytes: 0, - num_flags_left: 8, - } - } - - fn write_code(&mut self, val: u8) { - self.codes[self.code_position] = val; - self.code_position += 1; - } - - fn init_flag(&mut self) { - if self.num_flags_left == 8 { - *self.get_flag() = 0; - self.code_position -= 1; - } else { - *self.get_flag() >>= self.num_flags_left; - } - } - - fn get_flag(&mut self) -> &mut u8 { - &mut self.codes[self.flag_position] - } - - fn plant_flag(&mut self) { - self.flag_position = self.code_position; - self.code_position += 1; - } - - fn consume_flag(&mut self) { - self.num_flags_left -= 1; - if self.num_flags_left == 0 { - self.num_flags_left = 8; - self.plant_flag(); - } - } -} - -fn compress_lz_codes( - huff: &HuffmanOxide, - output: &mut OutputBufferOxide, - lz_code_buf: &[u8], -) -> Result { - let mut flags = 1; - let mut bb = BitBuffer { - bit_buffer: u64::from(output.bit_buffer), - bits_in: output.bits_in, - }; - - let mut i: usize = 0; - while i < lz_code_buf.len() { - if flags == 1 { - flags = u32::from(lz_code_buf[i]) | 0x100; - i += 1; - } - - // The lz code was a length code - if flags & 1 == 1 { - flags >>= 1; - - let sym; - let num_extra_bits; - - let match_len = lz_code_buf[i] as usize; - - let match_dist = read_u16_le(lz_code_buf, i + 1); - - i += 3; - - debug_assert!(huff.code_sizes[0][LEN_SYM[match_len] as usize] != 0); - bb.put_fast( - u64::from(huff.codes[0][LEN_SYM[match_len] as usize]), - u32::from(huff.code_sizes[0][LEN_SYM[match_len] as usize]), - ); - bb.put_fast( - match_len as u64 & u64::from(BITMASKS[LEN_EXTRA[match_len] as usize]), - u32::from(LEN_EXTRA[match_len]), - ); - - if match_dist < 512 { - sym = SMALL_DIST_SYM[match_dist as usize] as usize; - num_extra_bits = SMALL_DIST_EXTRA[match_dist as usize] as usize; - } else { - sym = LARGE_DIST_SYM[(match_dist >> 8) as usize] as usize; - num_extra_bits = LARGE_DIST_EXTRA[(match_dist >> 8) as usize] as usize; - } - - debug_assert!(huff.code_sizes[1][sym] != 0); - bb.put_fast( - u64::from(huff.codes[1][sym]), - u32::from(huff.code_sizes[1][sym]), - ); - bb.put_fast( - u64::from(match_dist) & u64::from(BITMASKS[num_extra_bits as usize]), - num_extra_bits as u32, - ); - } else { - // The lz code was a literal - for _ in 0..3 { - flags >>= 1; - let lit = lz_code_buf[i]; - i += 1; - - debug_assert!(huff.code_sizes[0][lit as usize] != 0); - bb.put_fast( - u64::from(huff.codes[0][lit as usize]), - u32::from(huff.code_sizes[0][lit as usize]), - ); - - if flags & 1 == 1 || i >= lz_code_buf.len() { - break; - } - } - } - - bb.flush(output)?; - } - - output.bits_in = 0; - output.bit_buffer = 0; - while bb.bits_in != 0 { - let n = cmp::min(bb.bits_in, 16); - output.put_bits(bb.bit_buffer as u32 & BITMASKS[n as usize], n); - bb.bit_buffer >>= n; - bb.bits_in -= n; - } - - // Output the end of block symbol. - output.put_bits( - u32::from(huff.codes[0][256]), - u32::from(huff.code_sizes[0][256]), - ); - - Ok(true) -} - -fn compress_block( - huff: &mut HuffmanOxide, - output: &mut OutputBufferOxide, - lz: &LZOxide, - static_block: bool, -) -> Result { - if static_block { - huff.start_static_block(output); - } else { - huff.start_dynamic_block(output)?; - } - - compress_lz_codes(huff, output, &lz.codes[..lz.code_position]) -} - -fn flush_block( - d: &mut CompressorOxide, - callback: &mut CallbackOxide, - flush: TDEFLFlush, -) -> Result { - let mut saved_buffer; - { - let mut output = callback - .out - .new_output_buffer(&mut d.params.local_buf.b, d.params.out_buf_ofs); - output.bit_buffer = d.params.saved_bit_buffer; - output.bits_in = d.params.saved_bits_in; - - let use_raw_block = (d.params.flags & TDEFL_FORCE_ALL_RAW_BLOCKS != 0) - && (d.dict.lookahead_pos - d.dict.code_buf_dict_pos) <= d.dict.size; - - assert!(d.params.flush_remaining == 0); - d.params.flush_ofs = 0; - d.params.flush_remaining = 0; - - d.lz.init_flag(); - - // If we are at the start of the stream, write the zlib header if requested. - if d.params.flags & TDEFL_WRITE_ZLIB_HEADER != 0 && d.params.block_index == 0 { - let header = zlib::header_from_flags(d.params.flags as u32); - output.put_bits(header[0].into(), 8); - output.put_bits(header[1].into(), 8); - } - - // Output the block header. - output.put_bits((flush == TDEFLFlush::Finish) as u32, 1); - - saved_buffer = output.save(); - - let comp_success = if !use_raw_block { - let use_static = - (d.params.flags & TDEFL_FORCE_ALL_STATIC_BLOCKS != 0) || (d.lz.total_bytes < 48); - compress_block(&mut d.huff, &mut output, &d.lz, use_static)? - } else { - false - }; - - // If we failed to compress anything and the output would take up more space than the output - // data, output a stored block instead, which has at most 5 bytes of overhead. - // We only use some simple heuristics for now. - // A stored block will have an overhead of at least 4 bytes containing the block length - // but usually more due to the length parameters having to start at a byte boundary and thus - // requiring up to 5 bytes of padding. - // As a static block will have an overhead of at most 1 bit per byte - // (as literals are either 8 or 9 bytes), a raw block will - // never take up less space if the number of input bytes are less than 32. - let expanded = (d.lz.total_bytes > 32) - && (output.inner_pos - saved_buffer.pos + 1 >= (d.lz.total_bytes as usize)) - && (d.dict.lookahead_pos - d.dict.code_buf_dict_pos <= d.dict.size); - - if use_raw_block || expanded { - output.load(saved_buffer); - - // Block header. - output.put_bits(0, 2); - - // Block length has to start on a byte boundary, s opad. - output.pad_to_bytes(); - - // Block length and ones complement of block length. - output.put_bits(d.lz.total_bytes & 0xFFFF, 16); - output.put_bits(!d.lz.total_bytes & 0xFFFF, 16); - - // Write the actual bytes. - for i in 0..d.lz.total_bytes { - let pos = (d.dict.code_buf_dict_pos + i as usize) & LZ_DICT_SIZE_MASK; - output.put_bits(u32::from(d.dict.b.dict[pos as usize]), 8); - } - } else if !comp_success { - output.load(saved_buffer); - compress_block(&mut d.huff, &mut output, &d.lz, true)?; - } - - if flush != TDEFLFlush::None { - if flush == TDEFLFlush::Finish { - output.pad_to_bytes(); - if d.params.flags & TDEFL_WRITE_ZLIB_HEADER != 0 { - let mut adler = d.params.adler32; - for _ in 0..4 { - output.put_bits((adler >> 24) & 0xFF, 8); - adler <<= 8; - } - } - } else { - // Sync or Full flush. - // Output an empty raw block. - output.put_bits(0, 3); - output.pad_to_bytes(); - output.put_bits(0, 16); - output.put_bits(0xFFFF, 16); - } - } - - memset(&mut d.huff.count[0][..MAX_HUFF_SYMBOLS_0], 0); - memset(&mut d.huff.count[1][..MAX_HUFF_SYMBOLS_1], 0); - - d.lz.code_position = 1; - d.lz.flag_position = 0; - d.lz.num_flags_left = 8; - d.dict.code_buf_dict_pos += d.lz.total_bytes as usize; - d.lz.total_bytes = 0; - d.params.block_index += 1; - - saved_buffer = output.save(); - - d.params.saved_bit_buffer = saved_buffer.bit_buffer; - d.params.saved_bits_in = saved_buffer.bits_in; - } - - Ok(callback.flush_output(saved_buffer, &mut d.params)) -} - -fn record_literal(h: &mut HuffmanOxide, lz: &mut LZOxide, lit: u8) { - lz.total_bytes += 1; - lz.write_code(lit); - - *lz.get_flag() >>= 1; - lz.consume_flag(); - - h.count[0][lit as usize] += 1; -} - -fn record_match(h: &mut HuffmanOxide, lz: &mut LZOxide, mut match_len: u32, mut match_dist: u32) { - assert!(match_len >= MIN_MATCH_LEN.into()); - assert!(match_dist >= 1); - assert!(match_dist as usize <= LZ_DICT_SIZE); - - lz.total_bytes += match_len; - match_dist -= 1; - match_len -= u32::from(MIN_MATCH_LEN); - lz.write_code(match_len as u8); - lz.write_code(match_dist as u8); - lz.write_code((match_dist >> 8) as u8); - - *lz.get_flag() >>= 1; - *lz.get_flag() |= 0x80; - lz.consume_flag(); - - let symbol = if match_dist < 512 { - SMALL_DIST_SYM[match_dist as usize] - } else { - LARGE_DIST_SYM[((match_dist >> 8) & 127) as usize] - } as usize; - h.count[1][symbol] += 1; - h.count[0][LEN_SYM[match_len as usize] as usize] += 1; -} - -fn compress_normal(d: &mut CompressorOxide, callback: &mut CallbackOxide) -> bool { - let mut src_pos = d.params.src_pos; - let in_buf = match callback.in_buf { - None => return true, - Some(in_buf) => in_buf, - }; - - let mut lookahead_size = d.dict.lookahead_size; - let mut lookahead_pos = d.dict.lookahead_pos; - let mut saved_lit = d.params.saved_lit; - let mut saved_match_dist = d.params.saved_match_dist; - let mut saved_match_len = d.params.saved_match_len; - - while src_pos < in_buf.len() || (d.params.flush != TDEFLFlush::None && lookahead_size != 0) { - let src_buf_left = in_buf.len() - src_pos; - let num_bytes_to_process = cmp::min(src_buf_left, MAX_MATCH_LEN - lookahead_size as usize); - - if lookahead_size + d.dict.size >= usize::from(MIN_MATCH_LEN) - 1 - && num_bytes_to_process > 0 - { - let dictb = &mut d.dict.b; - - let mut dst_pos = (lookahead_pos + lookahead_size as usize) & LZ_DICT_SIZE_MASK; - let mut ins_pos = lookahead_pos + lookahead_size as usize - 2; - // Start the hash value from the first two bytes - let mut hash = update_hash( - u16::from(dictb.dict[(ins_pos & LZ_DICT_SIZE_MASK) as usize]), - dictb.dict[((ins_pos + 1) & LZ_DICT_SIZE_MASK) as usize], - ); - - lookahead_size += num_bytes_to_process; - - for &c in &in_buf[src_pos..src_pos + num_bytes_to_process] { - // Add byte to input buffer. - dictb.dict[dst_pos as usize] = c; - if (dst_pos as usize) < MAX_MATCH_LEN - 1 { - dictb.dict[LZ_DICT_SIZE + dst_pos as usize] = c; - } - - // Generate hash from the current byte, - hash = update_hash(hash, c); - dictb.next[(ins_pos & LZ_DICT_SIZE_MASK) as usize] = dictb.hash[hash as usize]; - // and insert it into the hash chain. - dictb.hash[hash as usize] = ins_pos as u16; - dst_pos = (dst_pos + 1) & LZ_DICT_SIZE_MASK; - ins_pos += 1; - } - src_pos += num_bytes_to_process; - } else { - let dictb = &mut d.dict.b; - for &c in &in_buf[src_pos..src_pos + num_bytes_to_process] { - let dst_pos = (lookahead_pos + lookahead_size) & LZ_DICT_SIZE_MASK; - dictb.dict[dst_pos as usize] = c; - if (dst_pos as usize) < MAX_MATCH_LEN - 1 { - dictb.dict[LZ_DICT_SIZE + dst_pos as usize] = c; - } - - lookahead_size += 1; - if lookahead_size + d.dict.size >= MIN_MATCH_LEN.into() { - let ins_pos = lookahead_pos + lookahead_size - 3; - let hash = ((u32::from(dictb.dict[(ins_pos & LZ_DICT_SIZE_MASK) as usize]) - << (LZ_HASH_SHIFT * 2)) - ^ ((u32::from(dictb.dict[((ins_pos + 1) & LZ_DICT_SIZE_MASK) as usize]) - << LZ_HASH_SHIFT) - ^ u32::from(c))) - & (LZ_HASH_SIZE as u32 - 1); - - dictb.next[(ins_pos & LZ_DICT_SIZE_MASK) as usize] = dictb.hash[hash as usize]; - dictb.hash[hash as usize] = ins_pos as u16; - } - } - - src_pos += num_bytes_to_process; - } - - d.dict.size = cmp::min(LZ_DICT_SIZE - lookahead_size, d.dict.size); - if d.params.flush == TDEFLFlush::None && (lookahead_size as usize) < MAX_MATCH_LEN { - break; - } - - let mut len_to_move = 1; - let mut cur_match_dist = 0; - let mut cur_match_len = if saved_match_len != 0 { - saved_match_len - } else { - u32::from(MIN_MATCH_LEN) - 1 - }; - let cur_pos = lookahead_pos & LZ_DICT_SIZE_MASK; - if d.params.flags & (TDEFL_RLE_MATCHES | TDEFL_FORCE_ALL_RAW_BLOCKS) != 0 { - // If TDEFL_RLE_MATCHES is set, we only look for repeating sequences of the current byte. - if d.dict.size != 0 && d.params.flags & TDEFL_FORCE_ALL_RAW_BLOCKS == 0 { - let c = d.dict.b.dict[((cur_pos.wrapping_sub(1)) & LZ_DICT_SIZE_MASK) as usize]; - cur_match_len = d.dict.b.dict[cur_pos as usize..(cur_pos + lookahead_size) as usize] - .iter() - .take_while(|&x| *x == c) - .count() as u32; - if cur_match_len < MIN_MATCH_LEN.into() { - cur_match_len = 0 - } else { - cur_match_dist = 1 - } - } - } else { - // Try to find a match for the bytes at the current position. - let dist_len = d.dict.find_match( - lookahead_pos, - d.dict.size, - lookahead_size as u32, - cur_match_dist, - cur_match_len, - ); - cur_match_dist = dist_len.0; - cur_match_len = dist_len.1; - } - - let far_and_small = cur_match_len == MIN_MATCH_LEN.into() && cur_match_dist >= 8 * 1024; - let filter_small = d.params.flags & TDEFL_FILTER_MATCHES != 0 && cur_match_len <= 5; - if far_and_small || filter_small || cur_pos == cur_match_dist as usize { - cur_match_dist = 0; - cur_match_len = 0; - } - - if saved_match_len != 0 { - if cur_match_len > saved_match_len { - record_literal(&mut d.huff, &mut d.lz, saved_lit); - if cur_match_len >= 128 { - record_match(&mut d.huff, &mut d.lz, cur_match_len, cur_match_dist); - saved_match_len = 0; - len_to_move = cur_match_len as usize; - } else { - saved_lit = d.dict.b.dict[cur_pos as usize]; - saved_match_dist = cur_match_dist; - saved_match_len = cur_match_len; - } - } else { - record_match(&mut d.huff, &mut d.lz, saved_match_len, saved_match_dist); - len_to_move = (saved_match_len - 1) as usize; - saved_match_len = 0; - } - } else if cur_match_dist == 0 { - record_literal( - &mut d.huff, - &mut d.lz, - d.dict.b.dict[cmp::min(cur_pos as usize, d.dict.b.dict.len() - 1)], - ); - } else if d.params.greedy_parsing - || (d.params.flags & TDEFL_RLE_MATCHES != 0) - || cur_match_len >= 128 - { - // If we are using lazy matching, check for matches at the next byte if the current - // match was shorter than 128 bytes. - record_match(&mut d.huff, &mut d.lz, cur_match_len, cur_match_dist); - len_to_move = cur_match_len as usize; - } else { - saved_lit = d.dict.b.dict[cmp::min(cur_pos as usize, d.dict.b.dict.len() - 1)]; - saved_match_dist = cur_match_dist; - saved_match_len = cur_match_len; - } - - lookahead_pos += len_to_move; - assert!(lookahead_size >= len_to_move); - lookahead_size -= len_to_move; - d.dict.size = cmp::min(d.dict.size + len_to_move, LZ_DICT_SIZE); - - let lz_buf_tight = d.lz.code_position > LZ_CODE_BUF_SIZE - 8; - let raw = d.params.flags & TDEFL_FORCE_ALL_RAW_BLOCKS != 0; - let fat = ((d.lz.code_position * 115) >> 7) >= d.lz.total_bytes as usize; - let fat_or_raw = (d.lz.total_bytes > 31 * 1024) && (fat || raw); - - if lz_buf_tight || fat_or_raw { - d.params.src_pos = src_pos; - // These values are used in flush_block, so we need to write them back here. - d.dict.lookahead_size = lookahead_size; - d.dict.lookahead_pos = lookahead_pos; - - let n = flush_block(d, callback, TDEFLFlush::None) - .unwrap_or(TDEFLStatus::PutBufFailed as i32); - if n != 0 { - d.params.saved_lit = saved_lit; - d.params.saved_match_dist = saved_match_dist; - d.params.saved_match_len = saved_match_len; - return n > 0; - } - } - } - - d.params.src_pos = src_pos; - d.dict.lookahead_size = lookahead_size; - d.dict.lookahead_pos = lookahead_pos; - d.params.saved_lit = saved_lit; - d.params.saved_match_dist = saved_match_dist; - d.params.saved_match_len = saved_match_len; - true -} - -const COMP_FAST_LOOKAHEAD_SIZE: usize = 4096; - -fn compress_fast(d: &mut CompressorOxide, callback: &mut CallbackOxide) -> bool { - let mut src_pos = d.params.src_pos; - let mut lookahead_size = d.dict.lookahead_size; - let mut lookahead_pos = d.dict.lookahead_pos; - - let mut cur_pos = lookahead_pos & LZ_DICT_SIZE_MASK; - let in_buf = match callback.in_buf { - None => return true, - Some(in_buf) => in_buf, - }; - - debug_assert!(d.lz.code_position < LZ_CODE_BUF_SIZE - 2); - - while src_pos < in_buf.len() || (d.params.flush != TDEFLFlush::None && lookahead_size > 0) { - let mut dst_pos = ((lookahead_pos + lookahead_size) & LZ_DICT_SIZE_MASK) as usize; - let mut num_bytes_to_process = cmp::min( - in_buf.len() - src_pos, - (COMP_FAST_LOOKAHEAD_SIZE - lookahead_size) as usize, - ); - lookahead_size += num_bytes_to_process; - - while num_bytes_to_process != 0 { - let n = cmp::min(LZ_DICT_SIZE - dst_pos, num_bytes_to_process); - d.dict.b.dict[dst_pos..dst_pos + n].copy_from_slice(&in_buf[src_pos..src_pos + n]); - - if dst_pos < MAX_MATCH_LEN - 1 { - let m = cmp::min(n, MAX_MATCH_LEN - 1 - dst_pos); - d.dict.b.dict[dst_pos + LZ_DICT_SIZE..dst_pos + LZ_DICT_SIZE + m] - .copy_from_slice(&in_buf[src_pos..src_pos + m]); - } - - src_pos += n; - dst_pos = (dst_pos + n) & LZ_DICT_SIZE_MASK as usize; - num_bytes_to_process -= n; - } - - d.dict.size = cmp::min(LZ_DICT_SIZE - lookahead_size, d.dict.size); - if d.params.flush == TDEFLFlush::None && lookahead_size < COMP_FAST_LOOKAHEAD_SIZE { - break; - } - - while lookahead_size >= 4 { - let mut cur_match_len = 1; - - let first_trigram = d.dict.read_unaligned_u32(cur_pos) & 0xFF_FFFF; - - let hash = (first_trigram ^ (first_trigram >> (24 - (LZ_HASH_BITS - 8)))) - & LEVEL1_HASH_SIZE_MASK; - - let mut probe_pos = usize::from(d.dict.b.hash[hash as usize]); - d.dict.b.hash[hash as usize] = lookahead_pos as u16; - - let mut cur_match_dist = (lookahead_pos - probe_pos as usize) as u16; - if cur_match_dist as usize <= d.dict.size { - probe_pos &= LZ_DICT_SIZE_MASK; - - let trigram = d.dict.read_unaligned_u32(probe_pos) & 0xFF_FFFF; - - if first_trigram == trigram { - // Trigram was tested, so we can start with "+ 3" displacement. - let mut p = cur_pos + 3; - let mut q = probe_pos + 3; - cur_match_len = (|| { - for _ in 0..32 { - let p_data: u64 = d.dict.read_unaligned_u64(p); - let q_data: u64 = d.dict.read_unaligned_u64(q); - let xor_data = p_data ^ q_data; - if xor_data == 0 { - p += 8; - q += 8; - } else { - let trailing = xor_data.trailing_zeros(); - return p as u32 - cur_pos as u32 + (trailing >> 3); - } - } - - if cur_match_dist == 0 { - 0 - } else { - MAX_MATCH_LEN as u32 - } - })(); - - if cur_match_len < MIN_MATCH_LEN.into() - || (cur_match_len == MIN_MATCH_LEN.into() && cur_match_dist >= 8 * 1024) - { - let lit = first_trigram as u8; - cur_match_len = 1; - d.lz.write_code(lit); - *d.lz.get_flag() >>= 1; - d.huff.count[0][lit as usize] += 1; - } else { - // Limit the match to the length of the lookahead so we don't create a match - // that ends after the end of the input data. - cur_match_len = cmp::min(cur_match_len, lookahead_size as u32); - debug_assert!(cur_match_len >= MIN_MATCH_LEN.into()); - debug_assert!(cur_match_dist >= 1); - debug_assert!(cur_match_dist as usize <= LZ_DICT_SIZE); - cur_match_dist -= 1; - - d.lz.write_code((cur_match_len - u32::from(MIN_MATCH_LEN)) as u8); - d.lz.write_code(cur_match_dist as u8); - d.lz.write_code((cur_match_dist >> 8) as u8); - - *d.lz.get_flag() >>= 1; - *d.lz.get_flag() |= 0x80; - if cur_match_dist < 512 { - d.huff.count[1][SMALL_DIST_SYM[cur_match_dist as usize] as usize] += 1; - } else { - d.huff.count[1] - [LARGE_DIST_SYM[(cur_match_dist >> 8) as usize] as usize] += 1; - } - - d.huff.count[0][LEN_SYM[(cur_match_len - u32::from(MIN_MATCH_LEN)) as usize] - as usize] += 1; - } - } else { - d.lz.write_code(first_trigram as u8); - *d.lz.get_flag() >>= 1; - d.huff.count[0][first_trigram as u8 as usize] += 1; - } - - d.lz.consume_flag(); - d.lz.total_bytes += cur_match_len; - lookahead_pos += cur_match_len as usize; - d.dict.size = cmp::min(d.dict.size + cur_match_len as usize, LZ_DICT_SIZE); - cur_pos = (cur_pos + cur_match_len as usize) & LZ_DICT_SIZE_MASK; - lookahead_size -= cur_match_len as usize; - - if d.lz.code_position > LZ_CODE_BUF_SIZE - 8 { - // These values are used in flush_block, so we need to write them back here. - d.dict.lookahead_size = lookahead_size; - d.dict.lookahead_pos = lookahead_pos; - - let n = match flush_block(d, callback, TDEFLFlush::None) { - Err(_) => { - d.params.src_pos = src_pos; - d.params.prev_return_status = TDEFLStatus::PutBufFailed; - return false; - } - Ok(status) => status, - }; - if n != 0 { - d.params.src_pos = src_pos; - return n > 0; - } - debug_assert!(d.lz.code_position < LZ_CODE_BUF_SIZE - 2); - - lookahead_size = d.dict.lookahead_size; - lookahead_pos = d.dict.lookahead_pos; - } - } - } - - while lookahead_size != 0 { - let lit = d.dict.b.dict[cur_pos as usize]; - d.lz.total_bytes += 1; - d.lz.write_code(lit); - *d.lz.get_flag() >>= 1; - d.lz.consume_flag(); - - d.huff.count[0][lit as usize] += 1; - lookahead_pos += 1; - d.dict.size = cmp::min(d.dict.size + 1, LZ_DICT_SIZE); - cur_pos = (cur_pos + 1) & LZ_DICT_SIZE_MASK; - lookahead_size -= 1; - - if d.lz.code_position > LZ_CODE_BUF_SIZE - 8 { - // These values are used in flush_block, so we need to write them back here. - d.dict.lookahead_size = lookahead_size; - d.dict.lookahead_pos = lookahead_pos; - - let n = match flush_block(d, callback, TDEFLFlush::None) { - Err(_) => { - d.params.prev_return_status = TDEFLStatus::PutBufFailed; - d.params.src_pos = src_pos; - return false; - } - Ok(status) => status, - }; - if n != 0 { - d.params.src_pos = src_pos; - return n > 0; - } - - lookahead_size = d.dict.lookahead_size; - lookahead_pos = d.dict.lookahead_pos; - } - } - } - - d.params.src_pos = src_pos; - d.dict.lookahead_size = lookahead_size; - d.dict.lookahead_pos = lookahead_pos; - true -} - -fn flush_output_buffer(c: &mut CallbackOxide, p: &mut ParamsOxide) -> (TDEFLStatus, usize, usize) { - let mut res = (TDEFLStatus::Okay, p.src_pos, 0); - if let CallbackOut::Buf(ref mut cb) = c.out { - let n = cmp::min(cb.out_buf.len() - p.out_buf_ofs, p.flush_remaining as usize); - if n != 0 { - (&mut cb.out_buf[p.out_buf_ofs..p.out_buf_ofs + n]) - .copy_from_slice(&p.local_buf.b[p.flush_ofs as usize..p.flush_ofs as usize + n]); - } - p.flush_ofs += n as u32; - p.flush_remaining -= n as u32; - p.out_buf_ofs += n; - res.2 = p.out_buf_ofs; - } - - if p.finished && p.flush_remaining == 0 { - res.0 = TDEFLStatus::Done - } - res -} - -/// Main compression function. Tries to compress as much as possible from `in_buf` and -/// puts compressed output into `out_buf`. -/// -/// The value of `flush` determines if the compressor should attempt to flush all output -/// and alternatively try to finish the stream. -/// -/// Use [`TDEFLFlush::Finish`] on the final call to signal that the stream is finishing. -/// -/// Note that this function does not keep track of whether a flush marker has been output, so -/// if called using [`TDEFLFlush::Sync`], the caller needs to ensure there is enough space in the -/// output buffer if they want to avoid repeated flush markers. -/// See #105 for details. -/// -/// # Returns -/// Returns a tuple containing the current status of the compressor, the current position -/// in the input buffer and the current position in the output buffer. -pub fn compress( - d: &mut CompressorOxide, - in_buf: &[u8], - out_buf: &mut [u8], - flush: TDEFLFlush, -) -> (TDEFLStatus, usize, usize) { - compress_inner( - d, - &mut CallbackOxide::new_callback_buf(in_buf, out_buf), - flush, - ) -} - -/// Main compression function. Callbacks output. -/// -/// # Returns -/// Returns a tuple containing the current status of the compressor, the current position -/// in the input buffer. -/// -/// The caller is responsible for ensuring the `CallbackFunc` struct will not cause undefined -/// behaviour. -pub fn compress_to_output( - d: &mut CompressorOxide, - in_buf: &[u8], - flush: TDEFLFlush, - mut callback_func: impl FnMut(&[u8]) -> bool, -) -> (TDEFLStatus, usize) { - let res = compress_inner( - d, - &mut CallbackOxide::new_callback_func( - in_buf, - CallbackFunc { - put_buf_func: &mut callback_func, - }, - ), - flush, - ); - - (res.0, res.1) -} - -fn compress_inner( - d: &mut CompressorOxide, - callback: &mut CallbackOxide, - flush: TDEFLFlush, -) -> (TDEFLStatus, usize, usize) { - d.params.out_buf_ofs = 0; - d.params.src_pos = 0; - - let prev_ok = d.params.prev_return_status == TDEFLStatus::Okay; - let flush_finish_once = d.params.flush != TDEFLFlush::Finish || flush == TDEFLFlush::Finish; - - d.params.flush = flush; - if !prev_ok || !flush_finish_once { - d.params.prev_return_status = TDEFLStatus::BadParam; - return (d.params.prev_return_status, 0, 0); - } - - if d.params.flush_remaining != 0 || d.params.finished { - let res = flush_output_buffer(callback, &mut d.params); - d.params.prev_return_status = res.0; - return res; - } - - let one_probe = d.params.flags & MAX_PROBES_MASK as u32 == 1; - let greedy = d.params.flags & TDEFL_GREEDY_PARSING_FLAG != 0; - let filter_or_rle_or_raw = d.params.flags - & (TDEFL_FILTER_MATCHES | TDEFL_FORCE_ALL_RAW_BLOCKS | TDEFL_RLE_MATCHES) - != 0; - - let compress_success = if one_probe && greedy && !filter_or_rle_or_raw { - compress_fast(d, callback) - } else { - compress_normal(d, callback) - }; - - if !compress_success { - return ( - d.params.prev_return_status, - d.params.src_pos, - d.params.out_buf_ofs, - ); - } - - if let Some(in_buf) = callback.in_buf { - if d.params.flags & (TDEFL_WRITE_ZLIB_HEADER | TDEFL_COMPUTE_ADLER32) != 0 { - d.params.adler32 = update_adler32(d.params.adler32, &in_buf[..d.params.src_pos]); - } - } - - let flush_none = d.params.flush == TDEFLFlush::None; - let in_left = callback.in_buf.map_or(0, |buf| buf.len()) - d.params.src_pos; - let remaining = in_left != 0 || d.params.flush_remaining != 0; - if !flush_none && d.dict.lookahead_size == 0 && !remaining { - let flush = d.params.flush; - match flush_block(d, callback, flush) { - Err(_) => { - d.params.prev_return_status = TDEFLStatus::PutBufFailed; - return ( - d.params.prev_return_status, - d.params.src_pos, - d.params.out_buf_ofs, - ); - } - Ok(x) if x < 0 => { - return ( - d.params.prev_return_status, - d.params.src_pos, - d.params.out_buf_ofs, - ) - } - _ => { - d.params.finished = d.params.flush == TDEFLFlush::Finish; - if d.params.flush == TDEFLFlush::Full { - memset(&mut d.dict.b.hash[..], 0); - memset(&mut d.dict.b.next[..], 0); - d.dict.size = 0; - } - } - } - } - - let res = flush_output_buffer(callback, &mut d.params); - d.params.prev_return_status = res.0; - - res -} - -/// Create a set of compression flags using parameters used by zlib and other compressors. -/// Mainly intended for use with transition from c libraries as it deals with raw integers. -/// -/// # Parameters -/// `level` determines compression level. Clamped to maximum of 10. Negative values result in -/// `CompressionLevel::DefaultLevel`. -/// `window_bits`: Above 0, wraps the stream in a zlib wrapper, 0 or negative for a raw deflate -/// stream. -/// `strategy`: Sets the strategy if this conforms to any of the values in `CompressionStrategy`. -/// -/// # Notes -/// This function may be removed or moved to the `miniz_oxide_c_api` in the future. -pub fn create_comp_flags_from_zip_params(level: i32, window_bits: i32, strategy: i32) -> u32 { - let num_probes = (if level >= 0 { - cmp::min(10, level) - } else { - CompressionLevel::DefaultLevel as i32 - }) as usize; - let greedy = if level <= 3 { - TDEFL_GREEDY_PARSING_FLAG - } else { - 0 - }; - let mut comp_flags = NUM_PROBES[num_probes] | greedy; - - if window_bits > 0 { - comp_flags |= TDEFL_WRITE_ZLIB_HEADER; - } - - if level == 0 { - comp_flags |= TDEFL_FORCE_ALL_RAW_BLOCKS; - } else if strategy == CompressionStrategy::Filtered as i32 { - comp_flags |= TDEFL_FILTER_MATCHES; - } else if strategy == CompressionStrategy::HuffmanOnly as i32 { - comp_flags &= !MAX_PROBES_MASK as u32; - } else if strategy == CompressionStrategy::Fixed as i32 { - comp_flags |= TDEFL_FORCE_ALL_STATIC_BLOCKS; - } else if strategy == CompressionStrategy::RLE as i32 { - comp_flags |= TDEFL_RLE_MATCHES; - } - - comp_flags -} - -#[cfg(test)] -mod test { - use super::{ - compress_to_output, create_comp_flags_from_zip_params, read_u16_le, write_u16_le, - CompressionStrategy, CompressorOxide, TDEFLFlush, TDEFLStatus, DEFAULT_FLAGS, - MZ_DEFAULT_WINDOW_BITS, - }; - use crate::inflate::decompress_to_vec; - use alloc::vec; - - #[test] - fn u16_to_slice() { - let mut slice = [0, 0]; - write_u16_le(2000, &mut slice, 0); - assert_eq!(slice, [208, 7]); - } - - #[test] - fn u16_from_slice() { - let mut slice = [208, 7]; - assert_eq!(read_u16_le(&mut slice, 0), 2000); - } - - #[test] - fn compress_output() { - assert_eq!( - DEFAULT_FLAGS, - create_comp_flags_from_zip_params( - 4, - MZ_DEFAULT_WINDOW_BITS, - CompressionStrategy::Default as i32 - ) - ); - - let slice = [ - 1, 2, 3, 4, 1, 2, 3, 1, 2, 3, 1, 2, 6, 1, 2, 3, 1, 2, 3, 2, 3, 1, 2, 3, - ]; - let mut encoded = vec![]; - let flags = create_comp_flags_from_zip_params(6, 0, 0); - let mut d = CompressorOxide::new(flags); - let (status, in_consumed) = - compress_to_output(&mut d, &slice, TDEFLFlush::Finish, |out: &[u8]| { - encoded.extend_from_slice(out); - true - }); - - assert_eq!(status, TDEFLStatus::Done); - assert_eq!(in_consumed, slice.len()); - - let decoded = decompress_to_vec(&encoded[..]).unwrap(); - assert_eq!(&decoded[..], &slice[..]); - } - - #[test] - /// Check fast compress mode - fn compress_fast() { - let slice = [ - 1, 2, 3, 4, 1, 2, 3, 1, 2, 3, 1, 2, 6, 1, 2, 3, 1, 2, 3, 2, 3, 1, 2, 3, - ]; - let mut encoded = vec![]; - let flags = create_comp_flags_from_zip_params(1, 0, 0); - let mut d = CompressorOxide::new(flags); - let (status, in_consumed) = - compress_to_output(&mut d, &slice, TDEFLFlush::Finish, |out: &[u8]| { - encoded.extend_from_slice(out); - true - }); - - assert_eq!(status, TDEFLStatus::Done); - assert_eq!(in_consumed, slice.len()); - - // Needs to be altered if algorithm improves. - assert_eq!( - &encoded[..], - [99, 100, 98, 102, 1, 98, 48, 98, 3, 147, 204, 76, 204, 140, 76, 204, 0] - ); - - let decoded = decompress_to_vec(&encoded[..]).unwrap(); - assert_eq!(&decoded[..], &slice[..]); - } -} diff --git a/vendor/miniz_oxide/src/deflate/mod.rs b/vendor/miniz_oxide/src/deflate/mod.rs deleted file mode 100644 index 471b94b..0000000 --- a/vendor/miniz_oxide/src/deflate/mod.rs +++ /dev/null @@ -1,227 +0,0 @@ -//! This module contains functionality for compression. - -use crate::alloc::vec; -use crate::alloc::vec::Vec; - -mod buffer; -pub mod core; -pub mod stream; -use self::core::*; - -/// How much processing the compressor should do to compress the data. -/// `NoCompression` and `Bestspeed` have special meanings, the other levels determine the number -/// of checks for matches in the hash chains and whether to use lazy or greedy parsing. -#[repr(i32)] -#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] -pub enum CompressionLevel { - /// Don't do any compression, only output uncompressed blocks. - NoCompression = 0, - /// Fast compression. Uses a special compression routine that is optimized for speed. - BestSpeed = 1, - /// Slow/high compression. Do a lot of checks to try to find good matches. - BestCompression = 9, - /// Even more checks, can be very slow. - UberCompression = 10, - /// Default compromise between speed and compression. - DefaultLevel = 6, - /// Use the default compression level. - DefaultCompression = -1, -} - -// Missing safe rust analogue (this and mem-to-mem are quite similar) -/* -fn tdefl_compress( - d: Option<&mut CompressorOxide>, - in_buf: *const c_void, - in_size: Option<&mut usize>, - out_buf: *mut c_void, - out_size: Option<&mut usize>, - flush: TDEFLFlush, -) -> TDEFLStatus { - let res = match d { - None => { - in_size.map(|size| *size = 0); - out_size.map(|size| *size = 0); - (TDEFLStatus::BadParam, 0, 0) - }, - Some(compressor) => { - let callback_res = CallbackOxide::new( - compressor.callback_func.clone(), - in_buf, - in_size, - out_buf, - out_size, - ); - - if let Ok(mut callback) = callback_res { - let res = compress(compressor, &mut callback, flush); - callback.update_size(Some(res.1), Some(res.2)); - res - } else { - (TDEFLStatus::BadParam, 0, 0) - } - } - }; - res.0 -}*/ - -// Missing safe rust analogue -/* -fn tdefl_init( - d: Option<&mut CompressorOxide>, - put_buf_func: PutBufFuncPtr, - put_buf_user: *mut c_void, - flags: c_int, -) -> TDEFLStatus { - if let Some(d) = d { - *d = CompressorOxide::new( - put_buf_func.map(|func| - CallbackFunc { put_buf_func: func, put_buf_user: put_buf_user } - ), - flags as u32, - ); - TDEFLStatus::Okay - } else { - TDEFLStatus::BadParam - } -}*/ - -// Missing safe rust analogue (though maybe best served by flate2 front-end instead) -/* -fn tdefl_compress_mem_to_output( - buf: *const c_void, - buf_len: usize, - put_buf_func: PutBufFuncPtr, - put_buf_user: *mut c_void, - flags: c_int, -) -> bool*/ - -// Missing safe Rust analogue -/* -fn tdefl_compress_mem_to_mem( - out_buf: *mut c_void, - out_buf_len: usize, - src_buf: *const c_void, - src_buf_len: usize, - flags: c_int, -) -> usize*/ - -/// Compress the input data to a vector, using the specified compression level (0-10). -pub fn compress_to_vec(input: &[u8], level: u8) -> Vec { - compress_to_vec_inner(input, level, 0, 0) -} - -/// Compress the input data to a vector, using the specified compression level (0-10), and with a -/// zlib wrapper. -pub fn compress_to_vec_zlib(input: &[u8], level: u8) -> Vec { - compress_to_vec_inner(input, level, 1, 0) -} - -/// Simple function to compress data to a vec. -fn compress_to_vec_inner(input: &[u8], level: u8, window_bits: i32, strategy: i32) -> Vec { - // The comp flags function sets the zlib flag if the window_bits parameter is > 0. - let flags = create_comp_flags_from_zip_params(level.into(), window_bits, strategy); - let mut compressor = CompressorOxide::new(flags); - let mut output = vec![0; ::core::cmp::max(input.len() / 2, 2)]; - - let mut in_pos = 0; - let mut out_pos = 0; - loop { - let (status, bytes_in, bytes_out) = compress( - &mut compressor, - &input[in_pos..], - &mut output[out_pos..], - TDEFLFlush::Finish, - ); - - out_pos += bytes_out; - in_pos += bytes_in; - - match status { - TDEFLStatus::Done => { - output.truncate(out_pos); - break; - } - TDEFLStatus::Okay => { - // We need more space, so resize the vector. - if output.len().saturating_sub(out_pos) < 30 { - output.resize(output.len() * 2, 0) - } - } - // Not supposed to happen unless there is a bug. - _ => panic!("Bug! Unexpectedly failed to compress!"), - } - } - - output -} - -#[cfg(test)] -mod test { - use super::{compress_to_vec, compress_to_vec_inner, CompressionStrategy}; - use crate::inflate::decompress_to_vec; - use alloc::vec; - - /// Test deflate example. - /// - /// Check if the encoder produces the same code as the example given by Mark Adler here: - /// https://stackoverflow.com/questions/17398931/deflate-encoding-with-static-huffman-codes/17415203 - #[test] - fn compress_small() { - let test_data = b"Deflate late"; - let check = [ - 0x73, 0x49, 0x4d, 0xcb, 0x49, 0x2c, 0x49, 0x55, 0x00, 0x11, 0x00, - ]; - - let res = compress_to_vec(test_data, 1); - assert_eq!(&check[..], res.as_slice()); - - let res = compress_to_vec(test_data, 9); - assert_eq!(&check[..], res.as_slice()); - } - - #[test] - fn compress_huff_only() { - let test_data = b"Deflate late"; - - let res = compress_to_vec_inner(test_data, 1, 0, CompressionStrategy::HuffmanOnly as i32); - let d = decompress_to_vec(res.as_slice()).expect("Failed to decompress!"); - assert_eq!(test_data, d.as_slice()); - } - - /// Test that a raw block compresses fine. - #[test] - fn compress_raw() { - let text = b"Hello, zlib!"; - let encoded = { - let len = text.len(); - let notlen = !len; - let mut encoded = vec![ - 1, - len as u8, - (len >> 8) as u8, - notlen as u8, - (notlen >> 8) as u8, - ]; - encoded.extend_from_slice(&text[..]); - encoded - }; - - let res = compress_to_vec(text, 0); - assert_eq!(encoded, res.as_slice()); - } - - #[test] - fn short() { - let test_data = [10, 10, 10, 10, 10, 55]; - let c = compress_to_vec(&test_data, 9); - - let d = decompress_to_vec(c.as_slice()).expect("Failed to decompress!"); - assert_eq!(&test_data, d.as_slice()); - // Check that a static block is used here, rather than a raw block - // , so the data is actually compressed. - // (The optimal compressed length would be 5, but neither miniz nor zlib manages that either - // as neither checks matches against the byte at index 0.) - assert!(c.len() <= 6); - } -} diff --git a/vendor/miniz_oxide/src/deflate/stream.rs b/vendor/miniz_oxide/src/deflate/stream.rs deleted file mode 100644 index 39aa82d..0000000 --- a/vendor/miniz_oxide/src/deflate/stream.rs +++ /dev/null @@ -1,121 +0,0 @@ -//! Extra streaming compression functionality. -//! -//! As of now this is mainly intended for use to build a higher-level wrapper. -//! -//! There is no DeflateState as the needed state is contained in the compressor struct itself. - -use crate::deflate::core::{compress, CompressorOxide, TDEFLFlush, TDEFLStatus}; -use crate::{MZError, MZFlush, MZStatus, StreamResult}; - -/// Try to compress from input to output with the given [`CompressorOxide`]. -/// -/// # Errors -/// -/// Returns [`MZError::Buf`] If the size of the `output` slice is empty or no progress was made due -/// to lack of expected input data, or if called without [`MZFlush::Finish`] after the compression -/// was already finished. -/// -/// Returns [`MZError::Param`] if the compressor parameters are set wrong. -/// -/// Returns [`MZError::Stream`] when lower-level decompressor returns a -/// [`TDEFLStatus::PutBufFailed`]; may not actually be possible. -pub fn deflate( - compressor: &mut CompressorOxide, - input: &[u8], - output: &mut [u8], - flush: MZFlush, -) -> StreamResult { - if output.is_empty() { - return StreamResult::error(MZError::Buf); - } - - if compressor.prev_return_status() == TDEFLStatus::Done { - return if flush == MZFlush::Finish { - StreamResult { - bytes_written: 0, - bytes_consumed: 0, - status: Ok(MZStatus::StreamEnd), - } - } else { - StreamResult::error(MZError::Buf) - }; - } - - let mut bytes_written = 0; - let mut bytes_consumed = 0; - - let mut next_in = input; - let mut next_out = output; - - let status = loop { - let in_bytes; - let out_bytes; - let defl_status = { - let res = compress(compressor, next_in, next_out, TDEFLFlush::from(flush)); - in_bytes = res.1; - out_bytes = res.2; - res.0 - }; - - next_in = &next_in[in_bytes..]; - next_out = &mut next_out[out_bytes..]; - bytes_consumed += in_bytes; - bytes_written += out_bytes; - - // Check if we are done, or compression failed. - match defl_status { - TDEFLStatus::BadParam => break Err(MZError::Param), - // Don't think this can happen as we're not using a custom callback. - TDEFLStatus::PutBufFailed => break Err(MZError::Stream), - TDEFLStatus::Done => break Ok(MZStatus::StreamEnd), - _ => (), - }; - - // All the output space was used, so wait for more. - if next_out.is_empty() { - break Ok(MZStatus::Ok); - } - - if next_in.is_empty() && (flush != MZFlush::Finish) { - let total_changed = bytes_written > 0 || bytes_consumed > 0; - - break if (flush != MZFlush::None) || total_changed { - // We wrote or consumed something, and/or did a flush (sync/partial etc.). - Ok(MZStatus::Ok) - } else { - // No more input data, not flushing, and nothing was consumed or written, - // so couldn't make any progress. - Err(MZError::Buf) - }; - } - }; - StreamResult { - bytes_consumed, - bytes_written, - status, - } -} - -#[cfg(test)] -mod test { - use super::deflate; - use crate::deflate::CompressorOxide; - use crate::inflate::decompress_to_vec_zlib; - use crate::{MZFlush, MZStatus}; - use alloc::boxed::Box; - use alloc::vec; - - #[test] - fn test_state() { - let data = b"Hello zlib!"; - let mut compressed = vec![0; 50]; - let mut compressor = Box::::default(); - let res = deflate(&mut compressor, data, &mut compressed, MZFlush::Finish); - let status = res.status.expect("Failed to compress!"); - let decomp = - decompress_to_vec_zlib(&compressed).expect("Failed to decompress compressed data"); - assert_eq!(status, MZStatus::StreamEnd); - assert_eq!(decomp[..], data[..]); - assert_eq!(res.bytes_consumed, data.len()); - } -} diff --git a/vendor/miniz_oxide/src/inflate/core.rs b/vendor/miniz_oxide/src/inflate/core.rs deleted file mode 100644 index 6db2449..0000000 --- a/vendor/miniz_oxide/src/inflate/core.rs +++ /dev/null @@ -1,1992 +0,0 @@ -//! Streaming decompression functionality. - -use super::*; -use crate::shared::{update_adler32, HUFFMAN_LENGTH_ORDER}; - -use ::core::convert::TryInto; -use ::core::{cmp, slice}; - -use self::output_buffer::OutputBuffer; - -pub const TINFL_LZ_DICT_SIZE: usize = 32_768; - -/// A struct containing huffman code lengths and the huffman code tree used by the decompressor. -struct HuffmanTable { - /// Length of the code at each index. - pub code_size: [u8; MAX_HUFF_SYMBOLS_0], - /// Fast lookup table for shorter huffman codes. - /// - /// See `HuffmanTable::fast_lookup`. - pub look_up: [i16; FAST_LOOKUP_SIZE as usize], - /// Full huffman tree. - /// - /// Positive values are edge nodes/symbols, negative values are - /// parent nodes/references to other nodes. - pub tree: [i16; MAX_HUFF_TREE_SIZE], -} - -impl HuffmanTable { - const fn new() -> HuffmanTable { - HuffmanTable { - code_size: [0; MAX_HUFF_SYMBOLS_0], - look_up: [0; FAST_LOOKUP_SIZE as usize], - tree: [0; MAX_HUFF_TREE_SIZE], - } - } - - /// Look for a symbol in the fast lookup table. - /// The symbol is stored in the lower 9 bits, the length in the next 6. - /// If the returned value is negative, the code wasn't found in the - /// fast lookup table and the full tree has to be traversed to find the code. - #[inline] - fn fast_lookup(&self, bit_buf: BitBuffer) -> i16 { - self.look_up[(bit_buf & BitBuffer::from(FAST_LOOKUP_SIZE - 1)) as usize] - } - - /// Get the symbol and the code length from the huffman tree. - #[inline] - fn tree_lookup(&self, fast_symbol: i32, bit_buf: BitBuffer, mut code_len: u32) -> (i32, u32) { - let mut symbol = fast_symbol; - // We step through the tree until we encounter a positive value, which indicates a - // symbol. - loop { - // symbol here indicates the position of the left (0) node, if the next bit is 1 - // we add 1 to the lookup position to get the right node. - symbol = i32::from(self.tree[(!symbol + ((bit_buf >> code_len) & 1) as i32) as usize]); - code_len += 1; - if symbol >= 0 { - break; - } - } - (symbol, code_len) - } - - #[inline] - /// Look up a symbol and code length from the bits in the provided bit buffer. - /// - /// Returns Some(symbol, length) on success, - /// None if the length is 0. - /// - /// It's possible we could avoid checking for 0 if we can guarantee a sane table. - /// TODO: Check if a smaller type for code_len helps performance. - fn lookup(&self, bit_buf: BitBuffer) -> Option<(i32, u32)> { - let symbol = self.fast_lookup(bit_buf).into(); - if symbol >= 0 { - if (symbol >> 9) as u32 != 0 { - Some((symbol, (symbol >> 9) as u32)) - } else { - // Zero-length code. - None - } - } else { - // We didn't get a symbol from the fast lookup table, so check the tree instead. - Some(self.tree_lookup(symbol, bit_buf, FAST_LOOKUP_BITS.into())) - } - } -} - -/// The number of huffman tables used. -const MAX_HUFF_TABLES: usize = 3; -/// The length of the first (literal/length) huffman table. -const MAX_HUFF_SYMBOLS_0: usize = 288; -/// The length of the second (distance) huffman table. -const MAX_HUFF_SYMBOLS_1: usize = 32; -/// The length of the last (huffman code length) huffman table. -const _MAX_HUFF_SYMBOLS_2: usize = 19; -/// The maximum length of a code that can be looked up in the fast lookup table. -const FAST_LOOKUP_BITS: u8 = 10; -/// The size of the fast lookup table. -const FAST_LOOKUP_SIZE: u32 = 1 << FAST_LOOKUP_BITS; -const MAX_HUFF_TREE_SIZE: usize = MAX_HUFF_SYMBOLS_0 * 2; -const LITLEN_TABLE: usize = 0; -const DIST_TABLE: usize = 1; -const HUFFLEN_TABLE: usize = 2; - -/// Flags to [`decompress()`] to control how inflation works. -/// -/// These define bits for a bitmask argument. -pub mod inflate_flags { - /// Should we try to parse a zlib header? - /// - /// If unset, the function will expect an RFC1951 deflate stream. If set, it will expect a - /// RFC1950 zlib wrapper around the deflate stream. - pub const TINFL_FLAG_PARSE_ZLIB_HEADER: u32 = 1; - - /// There will be more input that hasn't been given to the decompressor yet. - /// - /// This is useful when you want to decompress what you have so far, - /// even if you know there is probably more input that hasn't gotten here yet (_e.g._, over a - /// network connection). When [`decompress()`][super::decompress] reaches the end of the input - /// without finding the end of the compressed stream, it will return - /// [`TINFLStatus::NeedsMoreInput`][super::TINFLStatus::NeedsMoreInput] if this is set, - /// indicating that you should get more data before calling again. If not set, it will return - /// [`TINFLStatus::FailedCannotMakeProgress`][super::TINFLStatus::FailedCannotMakeProgress] - /// suggesting the stream is corrupt, since you claimed it was all there. - pub const TINFL_FLAG_HAS_MORE_INPUT: u32 = 2; - - /// The output buffer should not wrap around. - pub const TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF: u32 = 4; - - /// Calculate the adler32 checksum of the output data even if we're not inflating a zlib stream. - /// - /// If [`TINFL_FLAG_IGNORE_ADLER32`] is specified, it will override this. - /// - /// NOTE: Enabling/disabling this between calls to decompress will result in an incorrect - /// checksum. - pub const TINFL_FLAG_COMPUTE_ADLER32: u32 = 8; - - /// Ignore adler32 checksum even if we are inflating a zlib stream. - /// - /// Overrides [`TINFL_FLAG_COMPUTE_ADLER32`] if both are enabled. - /// - /// NOTE: This flag does not exist in miniz as it does not support this and is a - /// custom addition for miniz_oxide. - /// - /// NOTE: Should not be changed from enabled to disabled after decompression has started, - /// this will result in checksum failure (outside the unlikely event where the checksum happens - /// to match anyway). - pub const TINFL_FLAG_IGNORE_ADLER32: u32 = 64; -} - -use self::inflate_flags::*; - -const MIN_TABLE_SIZES: [u16; 3] = [257, 1, 4]; - -#[cfg(target_pointer_width = "64")] -type BitBuffer = u64; - -#[cfg(not(target_pointer_width = "64"))] -type BitBuffer = u32; - -/// Main decompression struct. -/// -pub struct DecompressorOxide { - /// Current state of the decompressor. - state: core::State, - /// Number of bits in the bit buffer. - num_bits: u32, - /// Zlib CMF - z_header0: u32, - /// Zlib FLG - z_header1: u32, - /// Adler32 checksum from the zlib header. - z_adler32: u32, - /// 1 if the current block is the last block, 0 otherwise. - finish: u32, - /// The type of the current block. - block_type: u32, - /// 1 if the adler32 value should be checked. - check_adler32: u32, - /// Last match distance. - dist: u32, - /// Variable used for match length, symbols, and a number of other things. - counter: u32, - /// Number of extra bits for the last length or distance code. - num_extra: u32, - /// Number of entries in each huffman table. - table_sizes: [u32; MAX_HUFF_TABLES], - /// Buffer of input data. - bit_buf: BitBuffer, - /// Huffman tables. - tables: [HuffmanTable; MAX_HUFF_TABLES], - /// Raw block header. - raw_header: [u8; 4], - /// Huffman length codes. - len_codes: [u8; MAX_HUFF_SYMBOLS_0 + MAX_HUFF_SYMBOLS_1 + 137], -} - -impl DecompressorOxide { - /// Create a new tinfl_decompressor with all fields set to 0. - pub fn new() -> DecompressorOxide { - DecompressorOxide::default() - } - - /// Set the current state to `Start`. - #[inline] - pub fn init(&mut self) { - // The rest of the data is reset or overwritten when used. - self.state = core::State::Start; - } - - /// Returns the adler32 checksum of the currently decompressed data. - /// Note: Will return Some(1) if decompressing zlib but ignoring adler32. - #[inline] - pub fn adler32(&self) -> Option { - if self.state != State::Start && !self.state.is_failure() && self.z_header0 != 0 { - Some(self.check_adler32) - } else { - None - } - } - - /// Returns the adler32 that was read from the zlib header if it exists. - #[inline] - pub fn adler32_header(&self) -> Option { - if self.state != State::Start && self.state != State::BadZlibHeader && self.z_header0 != 0 { - Some(self.z_adler32) - } else { - None - } - } -} - -impl Default for DecompressorOxide { - /// Create a new tinfl_decompressor with all fields set to 0. - #[inline(always)] - fn default() -> Self { - DecompressorOxide { - state: core::State::Start, - num_bits: 0, - z_header0: 0, - z_header1: 0, - z_adler32: 0, - finish: 0, - block_type: 0, - check_adler32: 0, - dist: 0, - counter: 0, - num_extra: 0, - table_sizes: [0; MAX_HUFF_TABLES], - bit_buf: 0, - // TODO:(oyvindln) Check that copies here are optimized out in release mode. - tables: [ - HuffmanTable::new(), - HuffmanTable::new(), - HuffmanTable::new(), - ], - raw_header: [0; 4], - len_codes: [0; MAX_HUFF_SYMBOLS_0 + MAX_HUFF_SYMBOLS_1 + 137], - } - } -} - -#[derive(Copy, Clone, PartialEq, Eq, Debug)] -#[non_exhaustive] -enum State { - Start = 0, - ReadZlibCmf, - ReadZlibFlg, - ReadBlockHeader, - BlockTypeNoCompression, - RawHeader, - RawMemcpy1, - RawMemcpy2, - ReadTableSizes, - ReadHufflenTableCodeSize, - ReadLitlenDistTablesCodeSize, - ReadExtraBitsCodeSize, - DecodeLitlen, - WriteSymbol, - ReadExtraBitsLitlen, - DecodeDistance, - ReadExtraBitsDistance, - RawReadFirstByte, - RawStoreFirstByte, - WriteLenBytesToEnd, - BlockDone, - HuffDecodeOuterLoop1, - HuffDecodeOuterLoop2, - ReadAdler32, - - DoneForever, - - // Failure states. - BlockTypeUnexpected, - BadCodeSizeSum, - BadDistOrLiteralTableLength, - BadTotalSymbols, - BadZlibHeader, - DistanceOutOfBounds, - BadRawLength, - BadCodeSizeDistPrevLookup, - InvalidLitlen, - InvalidDist, - InvalidCodeLen, -} - -impl State { - fn is_failure(self) -> bool { - match self { - BlockTypeUnexpected => true, - BadCodeSizeSum => true, - BadDistOrLiteralTableLength => true, - BadTotalSymbols => true, - BadZlibHeader => true, - DistanceOutOfBounds => true, - BadRawLength => true, - BadCodeSizeDistPrevLookup => true, - InvalidLitlen => true, - InvalidDist => true, - _ => false, - } - } - - #[inline] - fn begin(&mut self, new_state: State) { - *self = new_state; - } -} - -use self::State::*; - -// Not sure why miniz uses 32-bit values for these, maybe alignment/cache again? -// # Optimization -// We add a extra value at the end and make the tables 32 elements long -// so we can use a mask to avoid bounds checks. -// The invalid values are set to something high enough to avoid underflowing -// the match length. -/// Base length for each length code. -/// -/// The base is used together with the value of the extra bits to decode the actual -/// length/distance values in a match. -#[rustfmt::skip] -const LENGTH_BASE: [u16; 32] = [ - 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, 512, 512, 512 -]; - -/// Number of extra bits for each length code. -#[rustfmt::skip] -const LENGTH_EXTRA: [u8; 32] = [ - 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, 0, 0, 0 -]; - -/// Base length for each distance code. -#[rustfmt::skip] -const DIST_BASE: [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, 12_289, 16_385, 24_577, 32_768, 32_768 -]; - -/// Number of extra bits for each distance code. -#[rustfmt::skip] -const DIST_EXTRA: [u8; 32] = [ - 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, 13, 13 -]; - -/// The mask used when indexing the base/extra arrays. -const BASE_EXTRA_MASK: usize = 32 - 1; - -/// Sets the value of all the elements of the slice to `val`. -#[inline] -fn memset(slice: &mut [T], val: T) { - for x in slice { - *x = val - } -} - -/// Read an le u16 value from the slice iterator. -/// -/// # Panics -/// Panics if there are less than two bytes left. -#[inline] -fn read_u16_le(iter: &mut slice::Iter) -> u16 { - let ret = { - let two_bytes = iter.as_ref()[..2].try_into().unwrap(); - u16::from_le_bytes(two_bytes) - }; - iter.nth(1); - ret -} - -/// Read an le u32 value from the slice iterator. -/// -/// # Panics -/// Panics if there are less than four bytes left. -#[inline(always)] -#[cfg(target_pointer_width = "64")] -fn read_u32_le(iter: &mut slice::Iter) -> u32 { - let ret = { - let four_bytes: [u8; 4] = iter.as_ref()[..4].try_into().unwrap(); - u32::from_le_bytes(four_bytes) - }; - iter.nth(3); - ret -} - -/// Ensure that there is data in the bit buffer. -/// -/// On 64-bit platform, we use a 64-bit value so this will -/// result in there being at least 32 bits in the bit buffer. -/// This function assumes that there is at least 4 bytes left in the input buffer. -#[inline(always)] -#[cfg(target_pointer_width = "64")] -fn fill_bit_buffer(l: &mut LocalVars, in_iter: &mut slice::Iter) { - // Read four bytes into the buffer at once. - if l.num_bits < 30 { - l.bit_buf |= BitBuffer::from(read_u32_le(in_iter)) << l.num_bits; - l.num_bits += 32; - } -} - -/// Same as previous, but for non-64-bit platforms. -/// Ensures at least 16 bits are present, requires at least 2 bytes in the in buffer. -#[inline(always)] -#[cfg(not(target_pointer_width = "64"))] -fn fill_bit_buffer(l: &mut LocalVars, in_iter: &mut slice::Iter) { - // If the buffer is 32-bit wide, read 2 bytes instead. - if l.num_bits < 15 { - l.bit_buf |= BitBuffer::from(read_u16_le(in_iter)) << l.num_bits; - l.num_bits += 16; - } -} - -/// Check that the zlib header is correct and that there is enough space in the buffer -/// for the window size specified in the header. -/// -/// See https://tools.ietf.org/html/rfc1950 -#[inline] -fn validate_zlib_header(cmf: u32, flg: u32, flags: u32, mask: usize) -> Action { - let mut failed = - // cmf + flg should be divisible by 31. - (((cmf * 256) + flg) % 31 != 0) || - // If this flag is set, a dictionary was used for this zlib compressed data. - // This is currently not supported by miniz or miniz-oxide - ((flg & 0b0010_0000) != 0) || - // Compression method. Only 8(DEFLATE) is defined by the standard. - ((cmf & 15) != 8); - - let window_size = 1 << ((cmf >> 4) + 8); - if (flags & TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF) == 0 { - // Bail if the buffer is wrapping and the window size is larger than the buffer. - failed |= (mask + 1) < window_size; - } - - // Zlib doesn't allow window sizes above 32 * 1024. - failed |= window_size > 32_768; - - if failed { - Action::Jump(BadZlibHeader) - } else { - Action::Jump(ReadBlockHeader) - } -} - -enum Action { - None, - Jump(State), - End(TINFLStatus), -} - -/// Try to decode the next huffman code, and puts it in the counter field of the decompressor -/// if successful. -/// -/// # Returns -/// The specified action returned from `f` on success, -/// `Action::End` if there are not enough data left to decode a symbol. -fn decode_huffman_code( - r: &mut DecompressorOxide, - l: &mut LocalVars, - table: usize, - flags: u32, - in_iter: &mut slice::Iter, - f: F, -) -> Action -where - F: FnOnce(&mut DecompressorOxide, &mut LocalVars, i32) -> Action, -{ - // As the huffman codes can be up to 15 bits long we need at least 15 bits - // ready in the bit buffer to start decoding the next huffman code. - if l.num_bits < 15 { - // First, make sure there is enough data in the bit buffer to decode a huffman code. - if in_iter.len() < 2 { - // If there is less than 2 bytes left in the input buffer, we try to look up - // the huffman code with what's available, and return if that doesn't succeed. - // Original explanation in miniz: - // /* TINFL_HUFF_BITBUF_FILL() is only used rarely, when the number of bytes - // * remaining in the input buffer falls below 2. */ - // /* It reads just enough bytes from the input stream that are needed to decode - // * the next Huffman code (and absolutely no more). It works by trying to fully - // * decode a */ - // /* Huffman code by using whatever bits are currently present in the bit buffer. - // * If this fails, it reads another byte, and tries again until it succeeds or - // * until the */ - // /* bit buffer contains >=15 bits (deflate's max. Huffman code size). */ - loop { - let mut temp = i32::from(r.tables[table].fast_lookup(l.bit_buf)); - - if temp >= 0 { - let code_len = (temp >> 9) as u32; - if (code_len != 0) && (l.num_bits >= code_len) { - break; - } - } else if l.num_bits > FAST_LOOKUP_BITS.into() { - let mut code_len = u32::from(FAST_LOOKUP_BITS); - loop { - temp = i32::from( - r.tables[table].tree - [(!temp + ((l.bit_buf >> code_len) & 1) as i32) as usize], - ); - code_len += 1; - if temp >= 0 || l.num_bits < code_len + 1 { - break; - } - } - if temp >= 0 { - break; - } - } - - // TODO: miniz jumps straight to here after getting here again after failing to read - // a byte. - // Doing that lets miniz avoid re-doing the lookup that that was done in the - // previous call. - let mut byte = 0; - if let a @ Action::End(_) = read_byte(in_iter, flags, |b| { - byte = b; - Action::None - }) { - return a; - }; - - // Do this outside closure for now to avoid borrowing r. - l.bit_buf |= BitBuffer::from(byte) << l.num_bits; - l.num_bits += 8; - - if l.num_bits >= 15 { - break; - } - } - } else { - // There is enough data in the input buffer, so read the next two bytes - // and add them to the bit buffer. - // Unwrapping here is fine since we just checked that there are at least two - // bytes left. - l.bit_buf |= BitBuffer::from(read_u16_le(in_iter)) << l.num_bits; - l.num_bits += 16; - } - } - - // We now have at least 15 bits in the input buffer. - let mut symbol = i32::from(r.tables[table].fast_lookup(l.bit_buf)); - let code_len; - // If the symbol was found in the fast lookup table. - if symbol >= 0 { - // Get the length value from the top bits. - // As we shift down the sign bit, converting to an unsigned value - // shouldn't overflow. - code_len = (symbol >> 9) as u32; - // Mask out the length value. - symbol &= 511; - } else { - let res = r.tables[table].tree_lookup(symbol, l.bit_buf, u32::from(FAST_LOOKUP_BITS)); - symbol = res.0; - code_len = res.1 as u32; - }; - - if code_len == 0 { - return Action::Jump(InvalidCodeLen); - } - - l.bit_buf >>= code_len as u32; - l.num_bits -= code_len; - f(r, l, symbol) -} - -/// Try to read one byte from `in_iter` and call `f` with the read byte as an argument, -/// returning the result. -/// If reading fails, `Action::End is returned` -#[inline] -fn read_byte(in_iter: &mut slice::Iter, flags: u32, f: F) -> Action -where - F: FnOnce(u8) -> Action, -{ - match in_iter.next() { - None => end_of_input(flags), - Some(&byte) => f(byte), - } -} - -// TODO: `l: &mut LocalVars` may be slow similar to decompress_fast (even with inline(always)) -/// Try to read `amount` number of bits from `in_iter` and call the function `f` with the bits as an -/// an argument after reading, returning the result of that function, or `Action::End` if there are -/// not enough bytes left. -#[inline] -#[allow(clippy::while_immutable_condition)] -fn read_bits( - l: &mut LocalVars, - amount: u32, - in_iter: &mut slice::Iter, - flags: u32, - f: F, -) -> Action -where - F: FnOnce(&mut LocalVars, BitBuffer) -> Action, -{ - // Clippy gives a false positive warning here due to the closure. - // Read enough bytes from the input iterator to cover the number of bits we want. - while l.num_bits < amount { - match read_byte(in_iter, flags, |byte| { - l.bit_buf |= BitBuffer::from(byte) << l.num_bits; - l.num_bits += 8; - Action::None - }) { - Action::None => (), - // If there are not enough bytes in the input iterator, return and signal that we need - // more. - action => return action, - } - } - - let bits = l.bit_buf & ((1 << amount) - 1); - l.bit_buf >>= amount; - l.num_bits -= amount; - f(l, bits) -} - -#[inline] -fn pad_to_bytes(l: &mut LocalVars, in_iter: &mut slice::Iter, flags: u32, f: F) -> Action -where - F: FnOnce(&mut LocalVars) -> Action, -{ - let num_bits = l.num_bits & 7; - read_bits(l, num_bits, in_iter, flags, |l, _| f(l)) -} - -#[inline] -fn end_of_input(flags: u32) -> Action { - Action::End(if flags & TINFL_FLAG_HAS_MORE_INPUT != 0 { - TINFLStatus::NeedsMoreInput - } else { - TINFLStatus::FailedCannotMakeProgress - }) -} - -#[inline] -fn undo_bytes(l: &mut LocalVars, max: u32) -> u32 { - let res = cmp::min(l.num_bits >> 3, max); - l.num_bits -= res << 3; - res -} - -fn start_static_table(r: &mut DecompressorOxide) { - r.table_sizes[LITLEN_TABLE] = 288; - r.table_sizes[DIST_TABLE] = 32; - memset(&mut r.tables[LITLEN_TABLE].code_size[0..144], 8); - memset(&mut r.tables[LITLEN_TABLE].code_size[144..256], 9); - memset(&mut r.tables[LITLEN_TABLE].code_size[256..280], 7); - memset(&mut r.tables[LITLEN_TABLE].code_size[280..288], 8); - memset(&mut r.tables[DIST_TABLE].code_size[0..32], 5); -} - -static REVERSED_BITS_LOOKUP: [u32; 1024] = { - let mut table = [0; 1024]; - - let mut i = 0; - while i < 1024 { - table[i] = (i as u32).reverse_bits(); - i += 1; - } - - table -}; - -fn init_tree(r: &mut DecompressorOxide, l: &mut LocalVars) -> Action { - loop { - let table = &mut r.tables[r.block_type as usize]; - let table_size = r.table_sizes[r.block_type as usize] as usize; - let mut total_symbols = [0u32; 16]; - let mut next_code = [0u32; 17]; - memset(&mut table.look_up[..], 0); - memset(&mut table.tree[..], 0); - - for &code_size in &table.code_size[..table_size] { - total_symbols[code_size as usize] += 1; - } - - let mut used_symbols = 0; - let mut total = 0; - for i in 1..16 { - used_symbols += total_symbols[i]; - total += total_symbols[i]; - total <<= 1; - next_code[i + 1] = total; - } - - if total != 65_536 && used_symbols > 1 { - return Action::Jump(BadTotalSymbols); - } - - let mut tree_next = -1; - for symbol_index in 0..table_size { - let mut rev_code = 0; - let code_size = table.code_size[symbol_index]; - if code_size == 0 { - continue; - } - - let mut cur_code = next_code[code_size as usize]; - next_code[code_size as usize] += 1; - - let n = cur_code & (u32::MAX >> (32 - code_size)); - - let mut rev_code = if n < 1024 { - REVERSED_BITS_LOOKUP[n as usize] >> (32 - code_size) - } else { - for _ in 0..code_size { - rev_code = (rev_code << 1) | (cur_code & 1); - cur_code >>= 1; - } - rev_code - }; - - if code_size <= FAST_LOOKUP_BITS { - let k = (i16::from(code_size) << 9) | symbol_index as i16; - while rev_code < FAST_LOOKUP_SIZE { - table.look_up[rev_code as usize] = k; - rev_code += 1 << code_size; - } - continue; - } - - let mut tree_cur = table.look_up[(rev_code & (FAST_LOOKUP_SIZE - 1)) as usize]; - if tree_cur == 0 { - table.look_up[(rev_code & (FAST_LOOKUP_SIZE - 1)) as usize] = tree_next as i16; - tree_cur = tree_next; - tree_next -= 2; - } - - rev_code >>= FAST_LOOKUP_BITS - 1; - for _ in FAST_LOOKUP_BITS + 1..code_size { - rev_code >>= 1; - tree_cur -= (rev_code & 1) as i16; - if table.tree[(-tree_cur - 1) as usize] == 0 { - table.tree[(-tree_cur - 1) as usize] = tree_next as i16; - tree_cur = tree_next; - tree_next -= 2; - } else { - tree_cur = table.tree[(-tree_cur - 1) as usize]; - } - } - - rev_code >>= 1; - tree_cur -= (rev_code & 1) as i16; - table.tree[(-tree_cur - 1) as usize] = symbol_index as i16; - } - - if r.block_type == 2 { - l.counter = 0; - return Action::Jump(ReadLitlenDistTablesCodeSize); - } - - if r.block_type == 0 { - break; - } - r.block_type -= 1; - } - - l.counter = 0; - Action::Jump(DecodeLitlen) -} - -// A helper macro for generating the state machine. -// -// As Rust doesn't have fallthrough on matches, we have to return to the match statement -// and jump for each state change. (Which would ideally be optimized away, but often isn't.) -macro_rules! generate_state { - ($state: ident, $state_machine: tt, $f: expr) => { - loop { - match $f { - Action::None => continue, - Action::Jump(new_state) => { - $state = new_state; - continue $state_machine; - }, - Action::End(result) => break $state_machine result, - } - } - }; -} - -#[derive(Copy, Clone)] -struct LocalVars { - pub bit_buf: BitBuffer, - pub num_bits: u32, - pub dist: u32, - pub counter: u32, - pub num_extra: u32, -} - -#[inline] -fn transfer( - out_slice: &mut [u8], - mut source_pos: usize, - mut out_pos: usize, - match_len: usize, - out_buf_size_mask: usize, -) { - // special case that comes up surprisingly often. in the case that `source_pos` - // is 1 less than `out_pos`, we can say that the entire range will be the same - // value and optimize this to be a simple `memset` - let source_diff = if source_pos > out_pos { - source_pos - out_pos - } else { - out_pos - source_pos - }; - if out_buf_size_mask == usize::MAX && source_diff == 1 && out_pos > source_pos { - let init = out_slice[out_pos - 1]; - let end = (match_len >> 2) * 4 + out_pos; - - out_slice[out_pos..end].fill(init); - out_pos = end; - source_pos = end - 1; - // if the difference between `source_pos` and `out_pos` is greater than 3, we - // can do slightly better than the naive case by copying everything at once - } else if out_buf_size_mask == usize::MAX && source_diff >= 4 && out_pos > source_pos { - for _ in 0..match_len >> 2 { - out_slice.copy_within(source_pos..=source_pos + 3, out_pos); - source_pos += 4; - out_pos += 4; - } - } else { - for _ in 0..match_len >> 2 { - out_slice[out_pos] = out_slice[source_pos & out_buf_size_mask]; - out_slice[out_pos + 1] = out_slice[(source_pos + 1) & out_buf_size_mask]; - out_slice[out_pos + 2] = out_slice[(source_pos + 2) & out_buf_size_mask]; - out_slice[out_pos + 3] = out_slice[(source_pos + 3) & out_buf_size_mask]; - source_pos += 4; - out_pos += 4; - } - } - - match match_len & 3 { - 0 => (), - 1 => out_slice[out_pos] = out_slice[source_pos & out_buf_size_mask], - 2 => { - out_slice[out_pos] = out_slice[source_pos & out_buf_size_mask]; - out_slice[out_pos + 1] = out_slice[(source_pos + 1) & out_buf_size_mask]; - } - 3 => { - out_slice[out_pos] = out_slice[source_pos & out_buf_size_mask]; - out_slice[out_pos + 1] = out_slice[(source_pos + 1) & out_buf_size_mask]; - out_slice[out_pos + 2] = out_slice[(source_pos + 2) & out_buf_size_mask]; - } - _ => unreachable!(), - } -} - -/// Presumes that there is at least match_len bytes in output left. -#[inline] -fn apply_match( - out_slice: &mut [u8], - out_pos: usize, - dist: usize, - match_len: usize, - out_buf_size_mask: usize, -) { - debug_assert!(out_pos + match_len <= out_slice.len()); - - let source_pos = out_pos.wrapping_sub(dist) & out_buf_size_mask; - - if match_len == 3 { - // Fast path for match len 3. - out_slice[out_pos] = out_slice[source_pos]; - out_slice[out_pos + 1] = out_slice[(source_pos + 1) & out_buf_size_mask]; - out_slice[out_pos + 2] = out_slice[(source_pos + 2) & out_buf_size_mask]; - return; - } - - if cfg!(not(any(target_arch = "x86", target_arch = "x86_64"))) { - // We are not on x86 so copy manually. - transfer(out_slice, source_pos, out_pos, match_len, out_buf_size_mask); - return; - } - - if source_pos >= out_pos && (source_pos - out_pos) < match_len { - transfer(out_slice, source_pos, out_pos, match_len, out_buf_size_mask); - } else if match_len <= dist && source_pos + match_len < out_slice.len() { - // Destination and source segments does not intersect and source does not wrap. - if source_pos < out_pos { - let (from_slice, to_slice) = out_slice.split_at_mut(out_pos); - to_slice[..match_len].copy_from_slice(&from_slice[source_pos..source_pos + match_len]); - } else { - let (to_slice, from_slice) = out_slice.split_at_mut(source_pos); - to_slice[out_pos..out_pos + match_len].copy_from_slice(&from_slice[..match_len]); - } - } else { - transfer(out_slice, source_pos, out_pos, match_len, out_buf_size_mask); - } -} - -/// Fast inner decompression loop which is run while there is at least -/// 259 bytes left in the output buffer, and at least 6 bytes left in the input buffer -/// (The maximum one match would need + 1). -/// -/// This was inspired by a similar optimization in zlib, which uses this info to do -/// faster unchecked copies of multiple bytes at a time. -/// Currently we don't do this here, but this function does avoid having to jump through the -/// big match loop on each state change(as rust does not have fallthrough or gotos at the moment), -/// and already improves decompression speed a fair bit. -fn decompress_fast( - r: &mut DecompressorOxide, - in_iter: &mut slice::Iter, - out_buf: &mut OutputBuffer, - flags: u32, - local_vars: &mut LocalVars, - out_buf_size_mask: usize, -) -> (TINFLStatus, State) { - // Make a local copy of the most used variables, to avoid having to update and read from values - // in a random memory location and to encourage more register use. - let mut l = *local_vars; - let mut state; - - let status: TINFLStatus = 'o: loop { - state = State::DecodeLitlen; - loop { - // This function assumes that there is at least 259 bytes left in the output buffer, - // and that there is at least 14 bytes left in the input buffer. 14 input bytes: - // 15 (prev lit) + 15 (length) + 5 (length extra) + 15 (dist) - // + 29 + 32 (left in bit buf, including last 13 dist extra) = 111 bits < 14 bytes - // We need the one extra byte as we may write one length and one full match - // before checking again. - if out_buf.bytes_left() < 259 || in_iter.len() < 14 { - state = State::DecodeLitlen; - break 'o TINFLStatus::Done; - } - - fill_bit_buffer(&mut l, in_iter); - - if let Some((symbol, code_len)) = r.tables[LITLEN_TABLE].lookup(l.bit_buf) { - l.counter = symbol as u32; - l.bit_buf >>= code_len; - l.num_bits -= code_len; - - if (l.counter & 256) != 0 { - // The symbol is not a literal. - break; - } else { - // If we have a 32-bit buffer we need to read another two bytes now - // to have enough bits to keep going. - if cfg!(not(target_pointer_width = "64")) { - fill_bit_buffer(&mut l, in_iter); - } - - if let Some((symbol, code_len)) = r.tables[LITLEN_TABLE].lookup(l.bit_buf) { - l.bit_buf >>= code_len; - l.num_bits -= code_len; - // The previous symbol was a literal, so write it directly and check - // the next one. - out_buf.write_byte(l.counter as u8); - if (symbol & 256) != 0 { - l.counter = symbol as u32; - // The symbol is a length value. - break; - } else { - // The symbol is a literal, so write it directly and continue. - out_buf.write_byte(symbol as u8); - } - } else { - state.begin(InvalidCodeLen); - break 'o TINFLStatus::Failed; - } - } - } else { - state.begin(InvalidCodeLen); - break 'o TINFLStatus::Failed; - } - } - - // Mask the top bits since they may contain length info. - l.counter &= 511; - if l.counter == 256 { - // We hit the end of block symbol. - state.begin(BlockDone); - break 'o TINFLStatus::Done; - } else if l.counter > 285 { - // Invalid code. - // We already verified earlier that the code is > 256. - state.begin(InvalidLitlen); - break 'o TINFLStatus::Failed; - } else { - // The symbol was a length code. - // # Optimization - // Mask the value to avoid bounds checks - // We could use get_unchecked later if can statically verify that - // this will never go out of bounds. - l.num_extra = u32::from(LENGTH_EXTRA[(l.counter - 257) as usize & BASE_EXTRA_MASK]); - l.counter = u32::from(LENGTH_BASE[(l.counter - 257) as usize & BASE_EXTRA_MASK]); - // Length and distance codes have a number of extra bits depending on - // the base, which together with the base gives us the exact value. - - fill_bit_buffer(&mut l, in_iter); - if l.num_extra != 0 { - let extra_bits = l.bit_buf & ((1 << l.num_extra) - 1); - l.bit_buf >>= l.num_extra; - l.num_bits -= l.num_extra; - l.counter += extra_bits as u32; - } - - // We found a length code, so a distance code should follow. - - if cfg!(not(target_pointer_width = "64")) { - fill_bit_buffer(&mut l, in_iter); - } - - if let Some((mut symbol, code_len)) = r.tables[DIST_TABLE].lookup(l.bit_buf) { - symbol &= 511; - l.bit_buf >>= code_len; - l.num_bits -= code_len; - if symbol > 29 { - state.begin(InvalidDist); - break 'o TINFLStatus::Failed; - } - - l.num_extra = u32::from(DIST_EXTRA[symbol as usize]); - l.dist = u32::from(DIST_BASE[symbol as usize]); - } else { - state.begin(InvalidCodeLen); - break 'o TINFLStatus::Failed; - } - - if l.num_extra != 0 { - fill_bit_buffer(&mut l, in_iter); - let extra_bits = l.bit_buf & ((1 << l.num_extra) - 1); - l.bit_buf >>= l.num_extra; - l.num_bits -= l.num_extra; - l.dist += extra_bits as u32; - } - - let position = out_buf.position(); - if l.dist as usize > out_buf.position() - && (flags & TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF != 0) - { - // We encountered a distance that refers a position before - // the start of the decoded data, so we can't continue. - state.begin(DistanceOutOfBounds); - break TINFLStatus::Failed; - } - - apply_match( - out_buf.get_mut(), - position, - l.dist as usize, - l.counter as usize, - out_buf_size_mask, - ); - - out_buf.set_position(position + l.counter as usize); - } - }; - - *local_vars = l; - (status, state) -} - -/// Main decompression function. Keeps decompressing data from `in_buf` until the `in_buf` is -/// empty, `out` is full, the end of the deflate stream is hit, or there is an error in the -/// deflate stream. -/// -/// # Arguments -/// -/// `r` is a [`DecompressorOxide`] struct with the state of this stream. -/// -/// `in_buf` is a reference to the compressed data that is to be decompressed. The decompressor will -/// start at the first byte of this buffer. -/// -/// `out` is a reference to the buffer that will store the decompressed data, and that -/// stores previously decompressed data if any. -/// -/// * The offset given by `out_pos` indicates where in the output buffer slice writing should start. -/// * If [`TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF`] is not set, the output buffer is used in a -/// wrapping manner, and it's size is required to be a power of 2. -/// * The decompression function normally needs access to 32KiB of the previously decompressed data -///(or to the beginning of the decompressed data if less than 32KiB has been decompressed.) -/// - If this data is not available, decompression may fail. -/// - Some deflate compressors allow specifying a window size which limits match distances to -/// less than this, or alternatively an RLE mode where matches will only refer to the previous byte -/// and thus allows a smaller output buffer. The window size can be specified in the zlib -/// header structure, however, the header data should not be relied on to be correct. -/// -/// `flags` indicates settings and status to the decompression function. -/// * The [`TINFL_FLAG_HAS_MORE_INPUT`] has to be specified if more compressed data is to be provided -/// in a subsequent call to this function. -/// * See the the [`inflate_flags`] module for details on other flags. -/// -/// # Returns -/// -/// Returns a tuple containing the status of the compressor, the number of input bytes read, and the -/// number of bytes output to `out`. -/// -/// This function shouldn't panic pending any bugs. -pub fn decompress( - r: &mut DecompressorOxide, - in_buf: &[u8], - out: &mut [u8], - out_pos: usize, - flags: u32, -) -> (TINFLStatus, usize, usize) { - let out_buf_size_mask = if flags & TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF != 0 { - usize::max_value() - } else { - // In the case of zero len, any attempt to write would produce HasMoreOutput, - // so to gracefully process the case of there really being no output, - // set the mask to all zeros. - out.len().saturating_sub(1) - }; - - // Ensure the output buffer's size is a power of 2, unless the output buffer - // is large enough to hold the entire output file (in which case it doesn't - // matter). - // Also make sure that the output buffer position is not past the end of the output buffer. - if (out_buf_size_mask.wrapping_add(1) & out_buf_size_mask) != 0 || out_pos > out.len() { - return (TINFLStatus::BadParam, 0, 0); - } - - let mut in_iter = in_buf.iter(); - - let mut state = r.state; - - let mut out_buf = OutputBuffer::from_slice_and_pos(out, out_pos); - - // Make a local copy of the important variables here so we can work with them on the stack. - let mut l = LocalVars { - bit_buf: r.bit_buf, - num_bits: r.num_bits, - dist: r.dist, - counter: r.counter, - num_extra: r.num_extra, - }; - - let mut status = 'state_machine: loop { - match state { - Start => generate_state!(state, 'state_machine, { - l.bit_buf = 0; - l.num_bits = 0; - l.dist = 0; - l.counter = 0; - l.num_extra = 0; - r.z_header0 = 0; - r.z_header1 = 0; - r.z_adler32 = 1; - r.check_adler32 = 1; - if flags & TINFL_FLAG_PARSE_ZLIB_HEADER != 0 { - Action::Jump(State::ReadZlibCmf) - } else { - Action::Jump(State::ReadBlockHeader) - } - }), - - ReadZlibCmf => generate_state!(state, 'state_machine, { - read_byte(&mut in_iter, flags, |cmf| { - r.z_header0 = u32::from(cmf); - Action::Jump(State::ReadZlibFlg) - }) - }), - - ReadZlibFlg => generate_state!(state, 'state_machine, { - read_byte(&mut in_iter, flags, |flg| { - r.z_header1 = u32::from(flg); - validate_zlib_header(r.z_header0, r.z_header1, flags, out_buf_size_mask) - }) - }), - - // Read the block header and jump to the relevant section depending on the block type. - ReadBlockHeader => generate_state!(state, 'state_machine, { - read_bits(&mut l, 3, &mut in_iter, flags, |l, bits| { - r.finish = (bits & 1) as u32; - r.block_type = (bits >> 1) as u32 & 3; - match r.block_type { - 0 => Action::Jump(BlockTypeNoCompression), - 1 => { - start_static_table(r); - init_tree(r, l) - }, - 2 => { - l.counter = 0; - Action::Jump(ReadTableSizes) - }, - 3 => Action::Jump(BlockTypeUnexpected), - _ => unreachable!() - } - }) - }), - - // Raw/Stored/uncompressed block. - BlockTypeNoCompression => generate_state!(state, 'state_machine, { - pad_to_bytes(&mut l, &mut in_iter, flags, |l| { - l.counter = 0; - Action::Jump(RawHeader) - }) - }), - - // Check that the raw block header is correct. - RawHeader => generate_state!(state, 'state_machine, { - if l.counter < 4 { - // Read block length and block length check. - if l.num_bits != 0 { - read_bits(&mut l, 8, &mut in_iter, flags, |l, bits| { - r.raw_header[l.counter as usize] = bits as u8; - l.counter += 1; - Action::None - }) - } else { - read_byte(&mut in_iter, flags, |byte| { - r.raw_header[l.counter as usize] = byte; - l.counter += 1; - Action::None - }) - } - } else { - // Check if the length value of a raw block is correct. - // The 2 first (2-byte) words in a raw header are the length and the - // ones complement of the length. - let length = u16::from(r.raw_header[0]) | (u16::from(r.raw_header[1]) << 8); - let check = u16::from(r.raw_header[2]) | (u16::from(r.raw_header[3]) << 8); - let valid = length == !check; - l.counter = length.into(); - - if !valid { - Action::Jump(BadRawLength) - } else if l.counter == 0 { - // Empty raw block. Sometimes used for synchronization. - Action::Jump(BlockDone) - } else if l.num_bits != 0 { - // There is some data in the bit buffer, so we need to write that first. - Action::Jump(RawReadFirstByte) - } else { - // The bit buffer is empty, so memcpy the rest of the uncompressed data from - // the block. - Action::Jump(RawMemcpy1) - } - } - }), - - // Read the byte from the bit buffer. - RawReadFirstByte => generate_state!(state, 'state_machine, { - read_bits(&mut l, 8, &mut in_iter, flags, |l, bits| { - l.dist = bits as u32; - Action::Jump(RawStoreFirstByte) - }) - }), - - // Write the byte we just read to the output buffer. - RawStoreFirstByte => generate_state!(state, 'state_machine, { - if out_buf.bytes_left() == 0 { - Action::End(TINFLStatus::HasMoreOutput) - } else { - out_buf.write_byte(l.dist as u8); - l.counter -= 1; - if l.counter == 0 || l.num_bits == 0 { - Action::Jump(RawMemcpy1) - } else { - // There is still some data left in the bit buffer that needs to be output. - // TODO: Changed this to jump to `RawReadfirstbyte` rather than - // `RawStoreFirstByte` as that seemed to be the correct path, but this - // needs testing. - Action::Jump(RawReadFirstByte) - } - } - }), - - RawMemcpy1 => generate_state!(state, 'state_machine, { - if l.counter == 0 { - Action::Jump(BlockDone) - } else if out_buf.bytes_left() == 0 { - Action::End(TINFLStatus::HasMoreOutput) - } else { - Action::Jump(RawMemcpy2) - } - }), - - RawMemcpy2 => generate_state!(state, 'state_machine, { - if in_iter.len() > 0 { - // Copy as many raw bytes as possible from the input to the output using memcpy. - // Raw block lengths are limited to 64 * 1024, so casting through usize and u32 - // is not an issue. - let space_left = out_buf.bytes_left(); - let bytes_to_copy = cmp::min(cmp::min( - space_left, - in_iter.len()), - l.counter as usize - ); - - out_buf.write_slice(&in_iter.as_slice()[..bytes_to_copy]); - - (&mut in_iter).nth(bytes_to_copy - 1); - l.counter -= bytes_to_copy as u32; - Action::Jump(RawMemcpy1) - } else { - end_of_input(flags) - } - }), - - // Read how many huffman codes/symbols are used for each table. - ReadTableSizes => generate_state!(state, 'state_machine, { - if l.counter < 3 { - let num_bits = [5, 5, 4][l.counter as usize]; - read_bits(&mut l, num_bits, &mut in_iter, flags, |l, bits| { - r.table_sizes[l.counter as usize] = - bits as u32 + u32::from(MIN_TABLE_SIZES[l.counter as usize]); - l.counter += 1; - Action::None - }) - } else { - memset(&mut r.tables[HUFFLEN_TABLE].code_size[..], 0); - l.counter = 0; - // Check that the litlen and distance are within spec. - // litlen table should be <=286 acc to the RFC and - // additionally zlib rejects dist table sizes larger than 30. - // NOTE this the final sizes after adding back predefined values, not - // raw value in the data. - // See miniz_oxide issue #130 and https://github.com/madler/zlib/issues/82. - if r.table_sizes[LITLEN_TABLE] <= 286 && r.table_sizes[DIST_TABLE] <= 30 { - Action::Jump(ReadHufflenTableCodeSize) - } - else { - Action::Jump(BadDistOrLiteralTableLength) - } - } - }), - - // Read the 3-bit lengths of the huffman codes describing the huffman code lengths used - // to decode the lengths of the main tables. - ReadHufflenTableCodeSize => generate_state!(state, 'state_machine, { - if l.counter < r.table_sizes[HUFFLEN_TABLE] { - read_bits(&mut l, 3, &mut in_iter, flags, |l, bits| { - // These lengths are not stored in a normal ascending order, but rather one - // specified by the deflate specification intended to put the most used - // values at the front as trailing zero lengths do not have to be stored. - r.tables[HUFFLEN_TABLE] - .code_size[HUFFMAN_LENGTH_ORDER[l.counter as usize] as usize] = - bits as u8; - l.counter += 1; - Action::None - }) - } else { - r.table_sizes[HUFFLEN_TABLE] = 19; - init_tree(r, &mut l) - } - }), - - ReadLitlenDistTablesCodeSize => generate_state!(state, 'state_machine, { - if l.counter < r.table_sizes[LITLEN_TABLE] + r.table_sizes[DIST_TABLE] { - decode_huffman_code( - r, &mut l, HUFFLEN_TABLE, - flags, &mut in_iter, |r, l, symbol| { - l.dist = symbol as u32; - if l.dist < 16 { - r.len_codes[l.counter as usize] = l.dist as u8; - l.counter += 1; - Action::None - } else if l.dist == 16 && l.counter == 0 { - Action::Jump(BadCodeSizeDistPrevLookup) - } else { - l.num_extra = [2, 3, 7][l.dist as usize - 16]; - Action::Jump(ReadExtraBitsCodeSize) - } - } - ) - } else if l.counter != r.table_sizes[LITLEN_TABLE] + r.table_sizes[DIST_TABLE] { - Action::Jump(BadCodeSizeSum) - } else { - r.tables[LITLEN_TABLE].code_size[..r.table_sizes[LITLEN_TABLE] as usize] - .copy_from_slice(&r.len_codes[..r.table_sizes[LITLEN_TABLE] as usize]); - - let dist_table_start = r.table_sizes[LITLEN_TABLE] as usize; - let dist_table_end = (r.table_sizes[LITLEN_TABLE] + - r.table_sizes[DIST_TABLE]) as usize; - r.tables[DIST_TABLE].code_size[..r.table_sizes[DIST_TABLE] as usize] - .copy_from_slice(&r.len_codes[dist_table_start..dist_table_end]); - - r.block_type -= 1; - init_tree(r, &mut l) - } - }), - - ReadExtraBitsCodeSize => generate_state!(state, 'state_machine, { - let num_extra = l.num_extra; - read_bits(&mut l, num_extra, &mut in_iter, flags, |l, mut extra_bits| { - // Mask to avoid a bounds check. - extra_bits += [3, 3, 11][(l.dist as usize - 16) & 3]; - let val = if l.dist == 16 { - r.len_codes[l.counter as usize - 1] - } else { - 0 - }; - - memset( - &mut r.len_codes[ - l.counter as usize..l.counter as usize + extra_bits as usize - ], - val, - ); - l.counter += extra_bits as u32; - Action::Jump(ReadLitlenDistTablesCodeSize) - }) - }), - - DecodeLitlen => generate_state!(state, 'state_machine, { - if in_iter.len() < 4 || out_buf.bytes_left() < 2 { - // See if we can decode a literal with the data we have left. - // Jumps to next state (WriteSymbol) if successful. - decode_huffman_code( - r, - &mut l, - LITLEN_TABLE, - flags, - &mut in_iter, - |_r, l, symbol| { - l.counter = symbol as u32; - Action::Jump(WriteSymbol) - }, - ) - } else if - // If there is enough space, use the fast inner decompression - // function. - out_buf.bytes_left() >= 259 && - in_iter.len() >= 14 - { - let (status, new_state) = decompress_fast( - r, - &mut in_iter, - &mut out_buf, - flags, - &mut l, - out_buf_size_mask, - ); - - state = new_state; - if status == TINFLStatus::Done { - Action::Jump(new_state) - } else { - Action::End(status) - } - } else { - fill_bit_buffer(&mut l, &mut in_iter); - - if let Some((symbol, code_len)) = r.tables[LITLEN_TABLE].lookup(l.bit_buf) { - - l.counter = symbol as u32; - l.bit_buf >>= code_len; - l.num_bits -= code_len; - - if (l.counter & 256) != 0 { - // The symbol is not a literal. - Action::Jump(HuffDecodeOuterLoop1) - } else { - // If we have a 32-bit buffer we need to read another two bytes now - // to have enough bits to keep going. - if cfg!(not(target_pointer_width = "64")) { - fill_bit_buffer(&mut l, &mut in_iter); - } - - if let Some((symbol, code_len)) = r.tables[LITLEN_TABLE].lookup(l.bit_buf) { - - l.bit_buf >>= code_len; - l.num_bits -= code_len; - // The previous symbol was a literal, so write it directly and check - // the next one. - out_buf.write_byte(l.counter as u8); - if (symbol & 256) != 0 { - l.counter = symbol as u32; - // The symbol is a length value. - Action::Jump(HuffDecodeOuterLoop1) - } else { - // The symbol is a literal, so write it directly and continue. - out_buf.write_byte(symbol as u8); - Action::None - } - } else { - Action::Jump(InvalidCodeLen) - } - } - } else { - Action::Jump(InvalidCodeLen) - } - } - }), - - WriteSymbol => generate_state!(state, 'state_machine, { - if l.counter >= 256 { - Action::Jump(HuffDecodeOuterLoop1) - } else if out_buf.bytes_left() > 0 { - out_buf.write_byte(l.counter as u8); - Action::Jump(DecodeLitlen) - } else { - Action::End(TINFLStatus::HasMoreOutput) - } - }), - - HuffDecodeOuterLoop1 => generate_state!(state, 'state_machine, { - // Mask the top bits since they may contain length info. - l.counter &= 511; - - if l.counter - == 256 { - // We hit the end of block symbol. - Action::Jump(BlockDone) - } else if l.counter > 285 { - // Invalid code. - // We already verified earlier that the code is > 256. - Action::Jump(InvalidLitlen) - } else { - // # Optimization - // Mask the value to avoid bounds checks - // We could use get_unchecked later if can statically verify that - // this will never go out of bounds. - l.num_extra = - u32::from(LENGTH_EXTRA[(l.counter - 257) as usize & BASE_EXTRA_MASK]); - l.counter = u32::from(LENGTH_BASE[(l.counter - 257) as usize & BASE_EXTRA_MASK]); - // Length and distance codes have a number of extra bits depending on - // the base, which together with the base gives us the exact value. - if l.num_extra != 0 { - Action::Jump(ReadExtraBitsLitlen) - } else { - Action::Jump(DecodeDistance) - } - } - }), - - ReadExtraBitsLitlen => generate_state!(state, 'state_machine, { - let num_extra = l.num_extra; - read_bits(&mut l, num_extra, &mut in_iter, flags, |l, extra_bits| { - l.counter += extra_bits as u32; - Action::Jump(DecodeDistance) - }) - }), - - DecodeDistance => generate_state!(state, 'state_machine, { - // Try to read a huffman code from the input buffer and look up what - // length code the decoded symbol refers to. - decode_huffman_code(r, &mut l, DIST_TABLE, flags, &mut in_iter, |_r, l, symbol| { - if symbol > 29 { - // Invalid distance code. - return Action::Jump(InvalidDist) - } - // # Optimization - // Mask the value to avoid bounds checks - // We could use get_unchecked later if can statically verify that - // this will never go out of bounds. - l.num_extra = u32::from(DIST_EXTRA[symbol as usize & BASE_EXTRA_MASK]); - l.dist = u32::from(DIST_BASE[symbol as usize & BASE_EXTRA_MASK]); - if l.num_extra != 0 { - // ReadEXTRA_BITS_DISTACNE - Action::Jump(ReadExtraBitsDistance) - } else { - Action::Jump(HuffDecodeOuterLoop2) - } - }) - }), - - ReadExtraBitsDistance => generate_state!(state, 'state_machine, { - let num_extra = l.num_extra; - read_bits(&mut l, num_extra, &mut in_iter, flags, |l, extra_bits| { - l.dist += extra_bits as u32; - Action::Jump(HuffDecodeOuterLoop2) - }) - }), - - HuffDecodeOuterLoop2 => generate_state!(state, 'state_machine, { - if l.dist as usize > out_buf.position() && - (flags & TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF != 0) - { - // We encountered a distance that refers a position before - // the start of the decoded data, so we can't continue. - Action::Jump(DistanceOutOfBounds) - } else { - let out_pos = out_buf.position(); - let source_pos = out_buf.position() - .wrapping_sub(l.dist as usize) & out_buf_size_mask; - - let out_len = out_buf.get_ref().len() as usize; - let match_end_pos = out_buf.position() + l.counter as usize; - - if match_end_pos > out_len || - // miniz doesn't do this check here. Not sure how it makes sure - // that this case doesn't happen. - (source_pos >= out_pos && (source_pos - out_pos) < l.counter as usize) - { - // Not enough space for all of the data in the output buffer, - // so copy what we have space for. - if l.counter == 0 { - Action::Jump(DecodeLitlen) - } else { - Action::Jump(WriteLenBytesToEnd) - } - } else { - apply_match( - out_buf.get_mut(), - out_pos, - l.dist as usize, - l.counter as usize, - out_buf_size_mask - ); - out_buf.set_position(out_pos + l.counter as usize); - Action::Jump(DecodeLitlen) - } - } - }), - - WriteLenBytesToEnd => generate_state!(state, 'state_machine, { - if out_buf.bytes_left() > 0 { - let out_pos = out_buf.position(); - let source_pos = out_buf.position() - .wrapping_sub(l.dist as usize) & out_buf_size_mask; - - - let len = cmp::min(out_buf.bytes_left(), l.counter as usize); - - transfer(out_buf.get_mut(), source_pos, out_pos, len, out_buf_size_mask); - - out_buf.set_position(out_pos + len); - l.counter -= len as u32; - if l.counter == 0 { - Action::Jump(DecodeLitlen) - } else { - Action::None - } - } else { - Action::End(TINFLStatus::HasMoreOutput) - } - }), - - BlockDone => generate_state!(state, 'state_machine, { - // End once we've read the last block. - if r.finish != 0 { - pad_to_bytes(&mut l, &mut in_iter, flags, |_| Action::None); - - let in_consumed = in_buf.len() - in_iter.len(); - let undo = undo_bytes(&mut l, in_consumed as u32) as usize; - in_iter = in_buf[in_consumed - undo..].iter(); - - l.bit_buf &= ((1 as BitBuffer) << l.num_bits) - 1; - debug_assert_eq!(l.num_bits, 0); - - if flags & TINFL_FLAG_PARSE_ZLIB_HEADER != 0 { - l.counter = 0; - Action::Jump(ReadAdler32) - } else { - Action::Jump(DoneForever) - } - } else { - Action::Jump(ReadBlockHeader) - } - }), - - ReadAdler32 => generate_state!(state, 'state_machine, { - if l.counter < 4 { - if l.num_bits != 0 { - read_bits(&mut l, 8, &mut in_iter, flags, |l, bits| { - r.z_adler32 <<= 8; - r.z_adler32 |= bits as u32; - l.counter += 1; - Action::None - }) - } else { - read_byte(&mut in_iter, flags, |byte| { - r.z_adler32 <<= 8; - r.z_adler32 |= u32::from(byte); - l.counter += 1; - Action::None - }) - } - } else { - Action::Jump(DoneForever) - } - }), - - // We are done. - DoneForever => break TINFLStatus::Done, - - // Anything else indicates failure. - // BadZlibHeader | BadRawLength | BadDistOrLiteralTableLength | BlockTypeUnexpected | - // DistanceOutOfBounds | - // BadTotalSymbols | BadCodeSizeDistPrevLookup | BadCodeSizeSum | InvalidLitlen | - // InvalidDist | InvalidCodeLen - _ => break TINFLStatus::Failed, - }; - }; - - let in_undo = if status != TINFLStatus::NeedsMoreInput - && status != TINFLStatus::FailedCannotMakeProgress - { - undo_bytes(&mut l, (in_buf.len() - in_iter.len()) as u32) as usize - } else { - 0 - }; - - // Make sure HasMoreOutput overrides NeedsMoreInput if the output buffer is full. - // (Unless the missing input is the adler32 value in which case we don't need to write anything.) - // TODO: May want to see if we can do this in a better way. - if status == TINFLStatus::NeedsMoreInput - && out_buf.bytes_left() == 0 - && state != State::ReadAdler32 - { - status = TINFLStatus::HasMoreOutput - } - - r.state = state; - r.bit_buf = l.bit_buf; - r.num_bits = l.num_bits; - r.dist = l.dist; - r.counter = l.counter; - r.num_extra = l.num_extra; - - r.bit_buf &= ((1 as BitBuffer) << r.num_bits) - 1; - - // If this is a zlib stream, and update the adler32 checksum with the decompressed bytes if - // requested. - let need_adler = if (flags & TINFL_FLAG_IGNORE_ADLER32) == 0 { - flags & (TINFL_FLAG_PARSE_ZLIB_HEADER | TINFL_FLAG_COMPUTE_ADLER32) != 0 - } else { - // If TINFL_FLAG_IGNORE_ADLER32 is enabled, ignore the checksum. - false - }; - if need_adler && status as i32 >= 0 { - let out_buf_pos = out_buf.position(); - r.check_adler32 = update_adler32(r.check_adler32, &out_buf.get_ref()[out_pos..out_buf_pos]); - - // disabled so that random input from fuzzer would not be rejected early, - // before it has a chance to reach interesting parts of code - if !cfg!(fuzzing) { - // Once we are done, check if the checksum matches with the one provided in the zlib header. - if status == TINFLStatus::Done - && flags & TINFL_FLAG_PARSE_ZLIB_HEADER != 0 - && r.check_adler32 != r.z_adler32 - { - status = TINFLStatus::Adler32Mismatch; - } - } - } - - ( - status, - in_buf.len() - in_iter.len() - in_undo, - out_buf.position() - out_pos, - ) -} - -#[cfg(test)] -mod test { - use super::*; - - //TODO: Fix these. - - fn tinfl_decompress_oxide<'i>( - r: &mut DecompressorOxide, - input_buffer: &'i [u8], - output_buffer: &mut [u8], - flags: u32, - ) -> (TINFLStatus, &'i [u8], usize) { - let (status, in_pos, out_pos) = decompress(r, input_buffer, output_buffer, 0, flags); - (status, &input_buffer[in_pos..], out_pos) - } - - #[test] - fn decompress_zlib() { - let encoded = [ - 120, 156, 243, 72, 205, 201, 201, 215, 81, 168, 202, 201, 76, 82, 4, 0, 27, 101, 4, 19, - ]; - let flags = TINFL_FLAG_COMPUTE_ADLER32 | TINFL_FLAG_PARSE_ZLIB_HEADER; - - let mut b = DecompressorOxide::new(); - const LEN: usize = 32; - let mut b_buf = vec![0; LEN]; - - // This should fail with the out buffer being to small. - let b_status = tinfl_decompress_oxide(&mut b, &encoded[..], b_buf.as_mut_slice(), flags); - - assert_eq!(b_status.0, TINFLStatus::Failed); - - let flags = flags | TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF; - - b = DecompressorOxide::new(); - - // With TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF set this should no longer fail. - let b_status = tinfl_decompress_oxide(&mut b, &encoded[..], b_buf.as_mut_slice(), flags); - - assert_eq!(b_buf[..b_status.2], b"Hello, zlib!"[..]); - assert_eq!(b_status.0, TINFLStatus::Done); - } - - #[test] - fn raw_block() { - const LEN: usize = 64; - - let text = b"Hello, zlib!"; - let encoded = { - let len = text.len(); - let notlen = !len; - let mut encoded = vec![ - 1, - len as u8, - (len >> 8) as u8, - notlen as u8, - (notlen >> 8) as u8, - ]; - encoded.extend_from_slice(&text[..]); - encoded - }; - - //let flags = TINFL_FLAG_COMPUTE_ADLER32 | TINFL_FLAG_PARSE_ZLIB_HEADER | - let flags = TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF; - - let mut b = DecompressorOxide::new(); - - let mut b_buf = vec![0; LEN]; - - let b_status = tinfl_decompress_oxide(&mut b, &encoded[..], b_buf.as_mut_slice(), flags); - assert_eq!(b_buf[..b_status.2], text[..]); - assert_eq!(b_status.0, TINFLStatus::Done); - } - - fn masked_lookup(table: &HuffmanTable, bit_buf: BitBuffer) -> (i32, u32) { - let ret = table.lookup(bit_buf).unwrap(); - (ret.0 & 511, ret.1) - } - - #[test] - fn fixed_table_lookup() { - let mut d = DecompressorOxide::new(); - d.block_type = 1; - start_static_table(&mut d); - let mut l = LocalVars { - bit_buf: d.bit_buf, - num_bits: d.num_bits, - dist: d.dist, - counter: d.counter, - num_extra: d.num_extra, - }; - init_tree(&mut d, &mut l); - let llt = &d.tables[LITLEN_TABLE]; - let dt = &d.tables[DIST_TABLE]; - assert_eq!(masked_lookup(llt, 0b00001100), (0, 8)); - assert_eq!(masked_lookup(llt, 0b00011110), (72, 8)); - assert_eq!(masked_lookup(llt, 0b01011110), (74, 8)); - assert_eq!(masked_lookup(llt, 0b11111101), (143, 8)); - assert_eq!(masked_lookup(llt, 0b000010011), (144, 9)); - assert_eq!(masked_lookup(llt, 0b111111111), (255, 9)); - assert_eq!(masked_lookup(llt, 0b00000000), (256, 7)); - assert_eq!(masked_lookup(llt, 0b1110100), (279, 7)); - assert_eq!(masked_lookup(llt, 0b00000011), (280, 8)); - assert_eq!(masked_lookup(llt, 0b11100011), (287, 8)); - - assert_eq!(masked_lookup(dt, 0), (0, 5)); - assert_eq!(masked_lookup(dt, 20), (5, 5)); - } - - fn check_result(input: &[u8], expected_status: TINFLStatus, expected_state: State, zlib: bool) { - let mut r = DecompressorOxide::default(); - let mut output_buf = vec![0; 1024 * 32]; - let flags = if zlib { - inflate_flags::TINFL_FLAG_PARSE_ZLIB_HEADER - } else { - 0 - } | TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF - | TINFL_FLAG_HAS_MORE_INPUT; - let (d_status, _in_bytes, _out_bytes) = - decompress(&mut r, input, &mut output_buf, 0, flags); - assert_eq!(expected_status, d_status); - assert_eq!(expected_state, r.state); - } - - #[test] - fn bogus_input() { - use self::check_result as cr; - const F: TINFLStatus = TINFLStatus::Failed; - const OK: TINFLStatus = TINFLStatus::Done; - // Bad CM. - cr(&[0x77, 0x85], F, State::BadZlibHeader, true); - // Bad window size (but check is correct). - cr(&[0x88, 0x98], F, State::BadZlibHeader, true); - // Bad check bits. - cr(&[0x78, 0x98], F, State::BadZlibHeader, true); - - // Too many code lengths. (From inflate library issues) - cr( - b"M\xff\xffM*\xad\xad\xad\xad\xad\xad\xad\xcd\xcd\xcdM", - F, - State::BadDistOrLiteralTableLength, - false, - ); - - // Bad CLEN (also from inflate library issues) - cr( - b"\xdd\xff\xff*M\x94ffffffffff", - F, - State::BadDistOrLiteralTableLength, - false, - ); - - // Port of inflate coverage tests from zlib-ng - // https://github.com/Dead2/zlib-ng/blob/develop/test/infcover.c - let c = |a, b, c| cr(a, b, c, false); - - // Invalid uncompressed/raw block length. - c(&[0, 0, 0, 0, 0], F, State::BadRawLength); - // Ok empty uncompressed block. - c(&[3, 0], OK, State::DoneForever); - // Invalid block type. - c(&[6], F, State::BlockTypeUnexpected); - // Ok uncompressed block. - c(&[1, 1, 0, 0xfe, 0xff, 0], OK, State::DoneForever); - // Too many litlens, we handle this later than zlib, so this test won't - // give the same result. - // c(&[0xfc, 0, 0], F, State::BadTotalSymbols); - // Invalid set of code lengths - TODO Check if this is the correct error for this. - c(&[4, 0, 0xfe, 0xff], F, State::BadTotalSymbols); - // Invalid repeat in list of code lengths. - // (Try to repeat a non-existent code.) - c(&[4, 0, 0x24, 0x49, 0], F, State::BadCodeSizeDistPrevLookup); - // Missing end of block code (should we have a separate error for this?) - fails on further input - // c(&[4, 0, 0x24, 0xe9, 0xff, 0x6d], F, State::BadTotalSymbols); - // Invalid set of literals/lengths - c( - &[ - 4, 0x80, 0x49, 0x92, 0x24, 0x49, 0x92, 0x24, 0x71, 0xff, 0xff, 0x93, 0x11, 0, - ], - F, - State::BadTotalSymbols, - ); - // Invalid set of distances _ needsmoreinput - // c(&[4, 0x80, 0x49, 0x92, 0x24, 0x49, 0x92, 0x24, 0x0f, 0xb4, 0xff, 0xff, 0xc3, 0x84], F, State::BadTotalSymbols); - // Invalid distance code - c(&[2, 0x7e, 0xff, 0xff], F, State::InvalidDist); - - // Distance refers to position before the start - c( - &[0x0c, 0xc0, 0x81, 0, 0, 0, 0, 0, 0x90, 0xff, 0x6b, 0x4, 0], - F, - State::DistanceOutOfBounds, - ); - - // Trailer - // Bad gzip trailer checksum GZip header not handled by miniz_oxide - //cr(&[0x1f, 0x8b, 0x08 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0x03, 0, 0, 0, 0, 0x01], F, State::BadCRC, false) - // Bad gzip trailer length - //cr(&[0x1f, 0x8b, 0x08 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0x03, 0, 0, 0, 0, 0, 0, 0, 0, 0x01], F, State::BadCRC, false) - } - - #[test] - fn empty_output_buffer_non_wrapping() { - let encoded = [ - 120, 156, 243, 72, 205, 201, 201, 215, 81, 168, 202, 201, 76, 82, 4, 0, 27, 101, 4, 19, - ]; - let flags = TINFL_FLAG_COMPUTE_ADLER32 - | TINFL_FLAG_PARSE_ZLIB_HEADER - | TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF; - let mut r = DecompressorOxide::new(); - let mut output_buf = vec![]; - // Check that we handle an empty buffer properly and not panicking. - // https://github.com/Frommi/miniz_oxide/issues/23 - let res = decompress(&mut r, &encoded, &mut output_buf, 0, flags); - assert_eq!(res, (TINFLStatus::HasMoreOutput, 4, 0)); - } - - #[test] - fn empty_output_buffer_wrapping() { - let encoded = [ - 0x73, 0x49, 0x4d, 0xcb, 0x49, 0x2c, 0x49, 0x55, 0x00, 0x11, 0x00, - ]; - let flags = TINFL_FLAG_COMPUTE_ADLER32; - let mut r = DecompressorOxide::new(); - let mut output_buf = vec![]; - // Check that we handle an empty buffer properly and not panicking. - // https://github.com/Frommi/miniz_oxide/issues/23 - let res = decompress(&mut r, &encoded, &mut output_buf, 0, flags); - assert_eq!(res, (TINFLStatus::HasMoreOutput, 2, 0)); - } -} diff --git a/vendor/miniz_oxide/src/inflate/mod.rs b/vendor/miniz_oxide/src/inflate/mod.rs deleted file mode 100644 index bb19e37..0000000 --- a/vendor/miniz_oxide/src/inflate/mod.rs +++ /dev/null @@ -1,337 +0,0 @@ -//! This module contains functionality for decompression. - -#[cfg(feature = "with-alloc")] -use crate::alloc::{boxed::Box, vec, vec::Vec}; -use ::core::usize; -#[cfg(all(feature = "std", feature = "with-alloc"))] -use std::error::Error; - -pub mod core; -mod output_buffer; -pub mod stream; -use self::core::*; - -const TINFL_STATUS_FAILED_CANNOT_MAKE_PROGRESS: i32 = -4; -const TINFL_STATUS_BAD_PARAM: i32 = -3; -const TINFL_STATUS_ADLER32_MISMATCH: i32 = -2; -const TINFL_STATUS_FAILED: i32 = -1; -const TINFL_STATUS_DONE: i32 = 0; -const TINFL_STATUS_NEEDS_MORE_INPUT: i32 = 1; -const TINFL_STATUS_HAS_MORE_OUTPUT: i32 = 2; - -/// Return status codes. -#[repr(i8)] -#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] -pub enum TINFLStatus { - /// More input data was expected, but the caller indicated that there was no more data, so the - /// input stream is likely truncated. - /// - /// This can't happen if you have provided the - /// [`TINFL_FLAG_HAS_MORE_INPUT`][core::inflate_flags::TINFL_FLAG_HAS_MORE_INPUT] flag to the - /// decompression. By setting that flag, you indicate more input exists but is not provided, - /// and so reaching the end of the input data without finding the end of the compressed stream - /// would instead return a [`NeedsMoreInput`][Self::NeedsMoreInput] status. - FailedCannotMakeProgress = TINFL_STATUS_FAILED_CANNOT_MAKE_PROGRESS as i8, - - /// The output buffer is an invalid size; consider the `flags` parameter. - BadParam = TINFL_STATUS_BAD_PARAM as i8, - - /// The decompression went fine, but the adler32 checksum did not match the one - /// provided in the header. - Adler32Mismatch = TINFL_STATUS_ADLER32_MISMATCH as i8, - - /// Failed to decompress due to invalid data. - Failed = TINFL_STATUS_FAILED as i8, - - /// Finished decompression without issues. - /// - /// This indicates the end of the compressed stream has been reached. - Done = TINFL_STATUS_DONE as i8, - - /// The decompressor needs more input data to continue decompressing. - /// - /// This occurs when there's no more consumable input, but the end of the stream hasn't been - /// reached, and you have supplied the - /// [`TINFL_FLAG_HAS_MORE_INPUT`][core::inflate_flags::TINFL_FLAG_HAS_MORE_INPUT] flag to the - /// decompressor. Had you not supplied that flag (which would mean you were asserting that you - /// believed all the data was available) you would have gotten a - /// [`FailedCannotMakeProcess`][Self::FailedCannotMakeProgress] instead. - NeedsMoreInput = TINFL_STATUS_NEEDS_MORE_INPUT as i8, - - /// There is still pending data that didn't fit in the output buffer. - HasMoreOutput = TINFL_STATUS_HAS_MORE_OUTPUT as i8, -} - -impl TINFLStatus { - pub fn from_i32(value: i32) -> Option { - use self::TINFLStatus::*; - match value { - TINFL_STATUS_FAILED_CANNOT_MAKE_PROGRESS => Some(FailedCannotMakeProgress), - TINFL_STATUS_BAD_PARAM => Some(BadParam), - TINFL_STATUS_ADLER32_MISMATCH => Some(Adler32Mismatch), - TINFL_STATUS_FAILED => Some(Failed), - TINFL_STATUS_DONE => Some(Done), - TINFL_STATUS_NEEDS_MORE_INPUT => Some(NeedsMoreInput), - TINFL_STATUS_HAS_MORE_OUTPUT => Some(HasMoreOutput), - _ => None, - } - } -} - -/// Struct return when decompress_to_vec functions fail. -#[cfg(feature = "with-alloc")] -#[derive(Debug)] -pub struct DecompressError { - /// Decompressor status on failure. See [TINFLStatus] for details. - pub status: TINFLStatus, - /// The currently decompressed data if any. - pub output: Vec, -} - -#[cfg(feature = "with-alloc")] -impl alloc::fmt::Display for DecompressError { - fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { - f.write_str(match self.status { - TINFLStatus::FailedCannotMakeProgress => "Truncated input stream", - TINFLStatus::BadParam => "Invalid output buffer size", - TINFLStatus::Adler32Mismatch => "Adler32 checksum mismatch", - TINFLStatus::Failed => "Invalid input data", - TINFLStatus::Done => unreachable!(), - TINFLStatus::NeedsMoreInput => "Truncated input stream", - TINFLStatus::HasMoreOutput => "Output size exceeded the specified limit", - }) - } -} - -/// Implement Error trait only if std feature is requested as it requires std. -#[cfg(all(feature = "std", feature = "with-alloc"))] -impl Error for DecompressError {} - -#[cfg(feature = "with-alloc")] -fn decompress_error(status: TINFLStatus, output: Vec) -> Result, DecompressError> { - Err(DecompressError { status, output }) -} - -/// Decompress the deflate-encoded data in `input` to a vector. -/// -/// NOTE: This function will not bound the output, so if the output is large enough it can result in an out of memory error. -/// It is therefore suggested to not use this for anything other than test programs, use the functions with a specified limit, or -/// ideally streaming decompression via the [flate2](https://github.com/alexcrichton/flate2-rs) library instead. -/// -/// Returns a [`Result`] containing the [`Vec`] of decompressed data on success, and a [struct][DecompressError] containing the status and so far decompressed data if any on failure. -#[inline] -#[cfg(feature = "with-alloc")] -pub fn decompress_to_vec(input: &[u8]) -> Result, DecompressError> { - decompress_to_vec_inner(input, 0, usize::max_value()) -} - -/// Decompress the deflate-encoded data (with a zlib wrapper) in `input` to a vector. -/// -/// NOTE: This function will not bound the output, so if the output is large enough it can result in an out of memory error. -/// It is therefore suggested to not use this for anything other than test programs, use the functions with a specified limit, or -/// ideally streaming decompression via the [flate2](https://github.com/alexcrichton/flate2-rs) library instead. -/// -/// Returns a [`Result`] containing the [`Vec`] of decompressed data on success, and a [struct][DecompressError] containing the status and so far decompressed data if any on failure. -#[inline] -#[cfg(feature = "with-alloc")] -pub fn decompress_to_vec_zlib(input: &[u8]) -> Result, DecompressError> { - decompress_to_vec_inner( - input, - inflate_flags::TINFL_FLAG_PARSE_ZLIB_HEADER, - usize::max_value(), - ) -} - -/// Decompress the deflate-encoded data in `input` to a vector. -/// -/// The vector is grown to at most `max_size` bytes; if the data does not fit in that size, -/// the error [struct][DecompressError] will contain the status [`TINFLStatus::HasMoreOutput`] and the data that was decompressed on failure. -/// -/// As this function tries to decompress everything in one go, it's not ideal for general use outside of tests or where the output size is expected to be small. -/// It is suggested to use streaming decompression via the [flate2](https://github.com/alexcrichton/flate2-rs) library instead. -/// -/// Returns a [`Result`] containing the [`Vec`] of decompressed data on success, and a [struct][DecompressError] on failure. -#[inline] -#[cfg(feature = "with-alloc")] -pub fn decompress_to_vec_with_limit( - input: &[u8], - max_size: usize, -) -> Result, DecompressError> { - decompress_to_vec_inner(input, 0, max_size) -} - -/// Decompress the deflate-encoded data (with a zlib wrapper) in `input` to a vector. -/// The vector is grown to at most `max_size` bytes; if the data does not fit in that size, -/// the error [struct][DecompressError] will contain the status [`TINFLStatus::HasMoreOutput`] and the data that was decompressed on failure. -/// -/// As this function tries to decompress everything in one go, it's not ideal for general use outside of tests or where the output size is expected to be small. -/// It is suggested to use streaming decompression via the [flate2](https://github.com/alexcrichton/flate2-rs) library instead. -/// -/// Returns a [`Result`] containing the [`Vec`] of decompressed data on success, and a [struct][DecompressError] on failure. -#[inline] -#[cfg(feature = "with-alloc")] -pub fn decompress_to_vec_zlib_with_limit( - input: &[u8], - max_size: usize, -) -> Result, DecompressError> { - decompress_to_vec_inner(input, inflate_flags::TINFL_FLAG_PARSE_ZLIB_HEADER, max_size) -} - -/// Backend of various to-[`Vec`] decompressions. -/// -/// Returns [`Vec`] of decompressed data on success and the [error struct][DecompressError] with details on failure. -#[cfg(feature = "with-alloc")] -fn decompress_to_vec_inner( - input: &[u8], - flags: u32, - max_output_size: usize, -) -> Result, DecompressError> { - let flags = flags | inflate_flags::TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF; - let mut ret: Vec = vec![0; input.len().saturating_mul(2).min(max_output_size)]; - - let mut decomp = Box::::default(); - - let mut in_pos = 0; - let mut out_pos = 0; - loop { - // Wrap the whole output slice so we know we have enough of the - // decompressed data for matches. - let (status, in_consumed, out_consumed) = - decompress(&mut decomp, &input[in_pos..], &mut ret, out_pos, flags); - in_pos += in_consumed; - out_pos += out_consumed; - - match status { - TINFLStatus::Done => { - ret.truncate(out_pos); - return Ok(ret); - } - - TINFLStatus::HasMoreOutput => { - // if the buffer has already reached the size limit, return an error - if ret.len() >= max_output_size { - return decompress_error(TINFLStatus::HasMoreOutput, ret); - } - // calculate the new length, capped at `max_output_size` - let new_len = ret.len().saturating_mul(2).min(max_output_size); - ret.resize(new_len, 0); - } - - _ => return decompress_error(status, ret), - } - } -} - -/// Decompress one or more source slices from an iterator into the output slice. -/// -/// * On success, returns the number of bytes that were written. -/// * On failure, returns the failure status code. -/// -/// This will fail if the output buffer is not large enough, but in that case -/// the output buffer will still contain the partial decompression. -/// -/// * `out` the output buffer. -/// * `it` the iterator of input slices. -/// * `zlib_header` if the first slice out of the iterator is expected to have a -/// Zlib header. Otherwise the slices are assumed to be the deflate data only. -/// * `ignore_adler32` if the adler32 checksum should be calculated or not. -pub fn decompress_slice_iter_to_slice<'out, 'inp>( - out: &'out mut [u8], - it: impl Iterator, - zlib_header: bool, - ignore_adler32: bool, -) -> Result { - use self::core::inflate_flags::*; - - let mut it = it.peekable(); - let r = &mut DecompressorOxide::new(); - let mut out_pos = 0; - while let Some(in_buf) = it.next() { - let has_more = it.peek().is_some(); - let flags = { - let mut f = TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF; - if zlib_header { - f |= TINFL_FLAG_PARSE_ZLIB_HEADER; - } - if ignore_adler32 { - f |= TINFL_FLAG_IGNORE_ADLER32; - } - if has_more { - f |= TINFL_FLAG_HAS_MORE_INPUT; - } - f - }; - let (status, _input_read, bytes_written) = decompress(r, in_buf, out, out_pos, flags); - out_pos += bytes_written; - match status { - TINFLStatus::NeedsMoreInput => continue, - TINFLStatus::Done => return Ok(out_pos), - e => return Err(e), - } - } - // If we ran out of source slices without getting a `Done` from the - // decompression we can call it a failure. - Err(TINFLStatus::FailedCannotMakeProgress) -} - -#[cfg(test)] -mod test { - use super::{ - decompress_slice_iter_to_slice, decompress_to_vec_zlib, decompress_to_vec_zlib_with_limit, - DecompressError, TINFLStatus, - }; - const ENCODED: [u8; 20] = [ - 120, 156, 243, 72, 205, 201, 201, 215, 81, 168, 202, 201, 76, 82, 4, 0, 27, 101, 4, 19, - ]; - - #[test] - fn decompress_vec() { - let res = decompress_to_vec_zlib(&ENCODED[..]).unwrap(); - assert_eq!(res.as_slice(), &b"Hello, zlib!"[..]); - } - - #[test] - fn decompress_vec_with_high_limit() { - let res = decompress_to_vec_zlib_with_limit(&ENCODED[..], 100_000).unwrap(); - assert_eq!(res.as_slice(), &b"Hello, zlib!"[..]); - } - - #[test] - fn fail_to_decompress_with_limit() { - let res = decompress_to_vec_zlib_with_limit(&ENCODED[..], 8); - match res { - Err(DecompressError { - status: TINFLStatus::HasMoreOutput, - .. - }) => (), // expected result - _ => panic!("Decompression output size limit was not enforced"), - } - } - - #[test] - fn test_decompress_slice_iter_to_slice() { - // one slice - let mut out = [0_u8; 12_usize]; - let r = - decompress_slice_iter_to_slice(&mut out, Some(&ENCODED[..]).into_iter(), true, false); - assert_eq!(r, Ok(12)); - assert_eq!(&out[..12], &b"Hello, zlib!"[..]); - - // some chunks at a time - for chunk_size in 1..13 { - // Note: because of https://github.com/Frommi/miniz_oxide/issues/110 our - // out buffer needs to have +1 byte available when the chunk size cuts - // the adler32 data off from the last actual data. - let mut out = [0_u8; 12_usize + 1]; - let r = - decompress_slice_iter_to_slice(&mut out, ENCODED.chunks(chunk_size), true, false); - assert_eq!(r, Ok(12)); - assert_eq!(&out[..12], &b"Hello, zlib!"[..]); - } - - // output buffer too small - let mut out = [0_u8; 3_usize]; - let r = decompress_slice_iter_to_slice(&mut out, ENCODED.chunks(7), true, false); - assert!(r.is_err()); - } -} diff --git a/vendor/miniz_oxide/src/inflate/output_buffer.rs b/vendor/miniz_oxide/src/inflate/output_buffer.rs deleted file mode 100644 index 5218a80..0000000 --- a/vendor/miniz_oxide/src/inflate/output_buffer.rs +++ /dev/null @@ -1,60 +0,0 @@ -/// A wrapper for the output slice used when decompressing. -/// -/// Using this rather than `Cursor` lets us implement the writing methods directly on -/// the buffer and lets us use a usize rather than u64 for the position which helps with -/// performance on 32-bit systems. -pub struct OutputBuffer<'a> { - slice: &'a mut [u8], - position: usize, -} - -impl<'a> OutputBuffer<'a> { - #[inline] - pub fn from_slice_and_pos(slice: &'a mut [u8], position: usize) -> OutputBuffer<'a> { - OutputBuffer { slice, position } - } - - #[inline] - pub const fn position(&self) -> usize { - self.position - } - - #[inline] - pub fn set_position(&mut self, position: usize) { - self.position = position; - } - - /// Write a byte to the current position and increment - /// - /// Assumes that there is space. - #[inline] - pub fn write_byte(&mut self, byte: u8) { - self.slice[self.position] = byte; - self.position += 1; - } - - /// Write a slice to the current position and increment - /// - /// Assumes that there is space. - #[inline] - pub fn write_slice(&mut self, data: &[u8]) { - let len = data.len(); - self.slice[self.position..self.position + len].copy_from_slice(data); - self.position += data.len(); - } - - #[inline] - pub const fn bytes_left(&self) -> usize { - self.slice.len() - self.position - } - - #[inline] - pub const fn get_ref(&self) -> &[u8] { - self.slice - } - - #[inline] - pub fn get_mut(&mut self) -> &mut [u8] { - self.slice - } -} diff --git a/vendor/miniz_oxide/src/inflate/stream.rs b/vendor/miniz_oxide/src/inflate/stream.rs deleted file mode 100644 index ee681b6..0000000 --- a/vendor/miniz_oxide/src/inflate/stream.rs +++ /dev/null @@ -1,418 +0,0 @@ -//! Extra streaming decompression functionality. -//! -//! As of now this is mainly intended for use to build a higher-level wrapper. -#[cfg(feature = "with-alloc")] -use crate::alloc::boxed::Box; -use core::{cmp, mem}; - -use crate::inflate::core::{decompress, inflate_flags, DecompressorOxide, TINFL_LZ_DICT_SIZE}; -use crate::inflate::TINFLStatus; -use crate::{DataFormat, MZError, MZFlush, MZResult, MZStatus, StreamResult}; - -/// Tag that determines reset policy of [InflateState](struct.InflateState.html) -pub trait ResetPolicy { - /// Performs reset - fn reset(&self, state: &mut InflateState); -} - -/// Resets state, without performing expensive ops (e.g. zeroing buffer) -/// -/// Note that not zeroing buffer can lead to security issues when dealing with untrusted input. -pub struct MinReset; - -impl ResetPolicy for MinReset { - fn reset(&self, state: &mut InflateState) { - state.decompressor().init(); - state.dict_ofs = 0; - state.dict_avail = 0; - state.first_call = true; - state.has_flushed = false; - state.last_status = TINFLStatus::NeedsMoreInput; - } -} - -/// Resets state and zero memory, continuing to use the same data format. -pub struct ZeroReset; - -impl ResetPolicy for ZeroReset { - #[inline] - fn reset(&self, state: &mut InflateState) { - MinReset.reset(state); - state.dict = [0; TINFL_LZ_DICT_SIZE]; - } -} - -/// Full reset of the state, including zeroing memory. -/// -/// Requires to provide new data format. -pub struct FullReset(pub DataFormat); - -impl ResetPolicy for FullReset { - #[inline] - fn reset(&self, state: &mut InflateState) { - ZeroReset.reset(state); - state.data_format = self.0; - } -} - -/// A struct that compbines a decompressor with extra data for streaming decompression. -/// -pub struct InflateState { - /// Inner decompressor struct - decomp: DecompressorOxide, - - /// Buffer of input bytes for matches. - /// TODO: Could probably do this a bit cleaner with some - /// Cursor-like class. - /// We may also look into whether we need to keep a buffer here, or just one in the - /// decompressor struct. - dict: [u8; TINFL_LZ_DICT_SIZE], - /// Where in the buffer are we currently at? - dict_ofs: usize, - /// How many bytes of data to be flushed is there currently in the buffer? - dict_avail: usize, - - first_call: bool, - has_flushed: bool, - - /// Whether the input data is wrapped in a zlib header and checksum. - /// TODO: This should be stored in the decompressor. - data_format: DataFormat, - last_status: TINFLStatus, -} - -impl Default for InflateState { - fn default() -> Self { - InflateState { - decomp: DecompressorOxide::default(), - dict: [0; TINFL_LZ_DICT_SIZE], - dict_ofs: 0, - dict_avail: 0, - first_call: true, - has_flushed: false, - data_format: DataFormat::Raw, - last_status: TINFLStatus::NeedsMoreInput, - } - } -} -impl InflateState { - /// Create a new state. - /// - /// Note that this struct is quite large due to internal buffers, and as such storing it on - /// the stack is not recommended. - /// - /// # Parameters - /// `data_format`: Determines whether the compressed data is assumed to wrapped with zlib - /// metadata. - pub fn new(data_format: DataFormat) -> InflateState { - InflateState { - data_format, - ..Default::default() - } - } - - /// Create a new state on the heap. - /// - /// # Parameters - /// `data_format`: Determines whether the compressed data is assumed to wrapped with zlib - /// metadata. - #[cfg(feature = "with-alloc")] - pub fn new_boxed(data_format: DataFormat) -> Box { - let mut b: Box = Box::default(); - b.data_format = data_format; - b - } - - /// Access the innner decompressor. - pub fn decompressor(&mut self) -> &mut DecompressorOxide { - &mut self.decomp - } - - /// Return the status of the last call to `inflate` with this `InflateState`. - pub const fn last_status(&self) -> TINFLStatus { - self.last_status - } - - /// Create a new state using miniz/zlib style window bits parameter. - /// - /// The decompressor does not support different window sizes. As such, - /// any positive (>0) value will set the zlib header flag, while a negative one - /// will not. - #[cfg(feature = "with-alloc")] - pub fn new_boxed_with_window_bits(window_bits: i32) -> Box { - let mut b: Box = Box::default(); - b.data_format = DataFormat::from_window_bits(window_bits); - b - } - - #[inline] - /// Reset the decompressor without re-allocating memory, using the given - /// data format. - pub fn reset(&mut self, data_format: DataFormat) { - self.reset_as(FullReset(data_format)); - } - - #[inline] - /// Resets the state according to specified policy. - pub fn reset_as(&mut self, policy: T) { - policy.reset(self) - } -} - -/// Try to decompress from `input` to `output` with the given [`InflateState`] -/// -/// # `flush` -/// -/// Generally, the various [`MZFlush`] flags have meaning only on the compression side. They can be -/// supplied here, but the only one that has any semantic meaning is [`MZFlush::Finish`], which is a -/// signal that the stream is expected to finish, and failing to do so is an error. It isn't -/// necessary to specify it when the stream ends; you'll still get returned a -/// [`MZStatus::StreamEnd`] anyway. Other values either have no effect or cause errors. It's -/// likely that you'll almost always just want to use [`MZFlush::None`]. -/// -/// # Errors -/// -/// Returns [`MZError::Buf`] if the size of the `output` slice is empty or no progress was made due -/// to lack of expected input data, or if called with [`MZFlush::Finish`] and input wasn't all -/// consumed. -/// -/// Returns [`MZError::Data`] if this or a a previous call failed with an error return from -/// [`TINFLStatus`]; probably indicates corrupted data. -/// -/// Returns [`MZError::Stream`] when called with [`MZFlush::Full`] (meaningless on -/// decompression), or when called without [`MZFlush::Finish`] after an earlier call with -/// [`MZFlush::Finish`] has been made. -pub fn inflate( - state: &mut InflateState, - input: &[u8], - output: &mut [u8], - flush: MZFlush, -) -> StreamResult { - let mut bytes_consumed = 0; - let mut bytes_written = 0; - let mut next_in = input; - let mut next_out = output; - - if flush == MZFlush::Full { - return StreamResult::error(MZError::Stream); - } - - let mut decomp_flags = if state.data_format == DataFormat::Zlib { - inflate_flags::TINFL_FLAG_COMPUTE_ADLER32 - } else { - inflate_flags::TINFL_FLAG_IGNORE_ADLER32 - }; - - if (state.data_format == DataFormat::Zlib) - | (state.data_format == DataFormat::ZLibIgnoreChecksum) - { - decomp_flags |= inflate_flags::TINFL_FLAG_PARSE_ZLIB_HEADER; - } - - let first_call = state.first_call; - state.first_call = false; - if (state.last_status as i32) < 0 { - return StreamResult::error(MZError::Data); - } - - if state.has_flushed && (flush != MZFlush::Finish) { - return StreamResult::error(MZError::Stream); - } - state.has_flushed |= flush == MZFlush::Finish; - - if (flush == MZFlush::Finish) && first_call { - decomp_flags |= inflate_flags::TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF; - - let status = decompress(&mut state.decomp, next_in, next_out, 0, decomp_flags); - let in_bytes = status.1; - let out_bytes = status.2; - let status = status.0; - - state.last_status = status; - - bytes_consumed += in_bytes; - bytes_written += out_bytes; - - let ret_status = { - if (status as i32) < 0 { - Err(MZError::Data) - } else if status != TINFLStatus::Done { - state.last_status = TINFLStatus::Failed; - Err(MZError::Buf) - } else { - Ok(MZStatus::StreamEnd) - } - }; - return StreamResult { - bytes_consumed, - bytes_written, - status: ret_status, - }; - } - - if flush != MZFlush::Finish { - decomp_flags |= inflate_flags::TINFL_FLAG_HAS_MORE_INPUT; - } - - if state.dict_avail != 0 { - bytes_written += push_dict_out(state, &mut next_out); - return StreamResult { - bytes_consumed, - bytes_written, - status: Ok( - if (state.last_status == TINFLStatus::Done) && (state.dict_avail == 0) { - MZStatus::StreamEnd - } else { - MZStatus::Ok - }, - ), - }; - } - - let status = inflate_loop( - state, - &mut next_in, - &mut next_out, - &mut bytes_consumed, - &mut bytes_written, - decomp_flags, - flush, - ); - StreamResult { - bytes_consumed, - bytes_written, - status, - } -} - -fn inflate_loop( - state: &mut InflateState, - next_in: &mut &[u8], - next_out: &mut &mut [u8], - total_in: &mut usize, - total_out: &mut usize, - decomp_flags: u32, - flush: MZFlush, -) -> MZResult { - let orig_in_len = next_in.len(); - loop { - let status = decompress( - &mut state.decomp, - *next_in, - &mut state.dict, - state.dict_ofs, - decomp_flags, - ); - - let in_bytes = status.1; - let out_bytes = status.2; - let status = status.0; - - state.last_status = status; - - *next_in = &next_in[in_bytes..]; - *total_in += in_bytes; - - state.dict_avail = out_bytes; - *total_out += push_dict_out(state, next_out); - - // The stream was corrupted, and decompression failed. - if (status as i32) < 0 { - return Err(MZError::Data); - } - - // The decompressor has flushed all it's data and is waiting for more input, but - // there was no more input provided. - if (status == TINFLStatus::NeedsMoreInput) && orig_in_len == 0 { - return Err(MZError::Buf); - } - - if flush == MZFlush::Finish { - if status == TINFLStatus::Done { - // There is not enough space in the output buffer to flush the remaining - // decompressed data in the internal buffer. - return if state.dict_avail != 0 { - Err(MZError::Buf) - } else { - Ok(MZStatus::StreamEnd) - }; - // No more space in the output buffer, but we're not done. - } else if next_out.is_empty() { - return Err(MZError::Buf); - } - } else { - // We're not expected to finish, so it's fine if we can't flush everything yet. - let empty_buf = next_in.is_empty() || next_out.is_empty(); - if (status == TINFLStatus::Done) || empty_buf || (state.dict_avail != 0) { - return if (status == TINFLStatus::Done) && (state.dict_avail == 0) { - // No more data left, we're done. - Ok(MZStatus::StreamEnd) - } else { - // Ok for now, still waiting for more input data or output space. - Ok(MZStatus::Ok) - }; - } - } - } -} - -fn push_dict_out(state: &mut InflateState, next_out: &mut &mut [u8]) -> usize { - let n = cmp::min(state.dict_avail as usize, next_out.len()); - (next_out[..n]).copy_from_slice(&state.dict[state.dict_ofs..state.dict_ofs + n]); - *next_out = &mut mem::take(next_out)[n..]; - state.dict_avail -= n; - state.dict_ofs = (state.dict_ofs + (n)) & (TINFL_LZ_DICT_SIZE - 1); - n -} - -#[cfg(test)] -mod test { - use super::{inflate, InflateState}; - use crate::{DataFormat, MZFlush, MZStatus}; - use alloc::vec; - - #[test] - fn test_state() { - let encoded = [ - 120u8, 156, 243, 72, 205, 201, 201, 215, 81, 168, 202, 201, 76, 82, 4, 0, 27, 101, 4, - 19, - ]; - let mut out = vec![0; 50]; - let mut state = InflateState::new_boxed(DataFormat::Zlib); - let res = inflate(&mut state, &encoded, &mut out, MZFlush::Finish); - let status = res.status.expect("Failed to decompress!"); - assert_eq!(status, MZStatus::StreamEnd); - assert_eq!(out[..res.bytes_written as usize], b"Hello, zlib!"[..]); - assert_eq!(res.bytes_consumed, encoded.len()); - - state.reset_as(super::ZeroReset); - out.iter_mut().map(|x| *x = 0).count(); - let res = inflate(&mut state, &encoded, &mut out, MZFlush::Finish); - let status = res.status.expect("Failed to decompress!"); - assert_eq!(status, MZStatus::StreamEnd); - assert_eq!(out[..res.bytes_written as usize], b"Hello, zlib!"[..]); - assert_eq!(res.bytes_consumed, encoded.len()); - - state.reset_as(super::MinReset); - out.iter_mut().map(|x| *x = 0).count(); - let res = inflate(&mut state, &encoded, &mut out, MZFlush::Finish); - let status = res.status.expect("Failed to decompress!"); - assert_eq!(status, MZStatus::StreamEnd); - assert_eq!(out[..res.bytes_written as usize], b"Hello, zlib!"[..]); - assert_eq!(res.bytes_consumed, encoded.len()); - assert_eq!(state.decompressor().adler32(), Some(459605011)); - - // Test state when not computing adler. - state = InflateState::new_boxed(DataFormat::ZLibIgnoreChecksum); - out.iter_mut().map(|x| *x = 0).count(); - let res = inflate(&mut state, &encoded, &mut out, MZFlush::Finish); - let status = res.status.expect("Failed to decompress!"); - assert_eq!(status, MZStatus::StreamEnd); - assert_eq!(out[..res.bytes_written as usize], b"Hello, zlib!"[..]); - assert_eq!(res.bytes_consumed, encoded.len()); - // Not computed, so should be Some(1) - assert_eq!(state.decompressor().adler32(), Some(1)); - // Should still have the checksum read from the header file. - assert_eq!(state.decompressor().adler32_header(), Some(459605011)) - } -} diff --git a/vendor/miniz_oxide/src/lib.rs b/vendor/miniz_oxide/src/lib.rs deleted file mode 100644 index 0e30dc0..0000000 --- a/vendor/miniz_oxide/src/lib.rs +++ /dev/null @@ -1,209 +0,0 @@ -//! A pure rust replacement for the [miniz](https://github.com/richgel999/miniz) -//! DEFLATE/zlib encoder/decoder. -//! Used a rust back-end for the -//! [flate2](https://github.com/alexcrichton/flate2-rs) crate. -//! -//! # Usage -//! ## Simple compression/decompression: -//! ``` rust -//! -//! use miniz_oxide::inflate::decompress_to_vec; -//! use miniz_oxide::deflate::compress_to_vec; -//! -//! fn roundtrip(data: &[u8]) { -//! let compressed = compress_to_vec(data, 6); -//! let decompressed = decompress_to_vec(compressed.as_slice()).expect("Failed to decompress!"); -//! # let _ = decompressed; -//! } -//! -//! # roundtrip(b"Test_data test data lalalal blabla"); -//! -//! ``` - -#![forbid(unsafe_code)] -#![cfg_attr(not(feature = "std"), no_std)] - -#[cfg(feature = "with-alloc")] -extern crate alloc; - -#[cfg(feature = "with-alloc")] -pub mod deflate; -pub mod inflate; -mod shared; - -pub use crate::shared::update_adler32 as mz_adler32_oxide; -pub use crate::shared::{MZ_ADLER32_INIT, MZ_DEFAULT_WINDOW_BITS}; - -/// A list of flush types. -/// -/// See for more in-depth info. -#[repr(i32)] -#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] -pub enum MZFlush { - /// Don't force any flushing. - /// Used when more input data is expected. - None = 0, - /// Zlib partial flush. - /// Currently treated as [`Sync`]. - Partial = 1, - /// Finish compressing the currently buffered data, and output an empty raw block. - /// Has no use in decompression. - Sync = 2, - /// Same as [`Sync`], but resets the compression dictionary so that further compressed - /// data does not depend on data compressed before the flush. - /// - /// Has no use in decompression, and is an error to supply in that case. - Full = 3, - /// Attempt to flush the remaining data and end the stream. - Finish = 4, - /// Not implemented. - Block = 5, -} - -impl MZFlush { - /// Create an MZFlush value from an integer value. - /// - /// Returns `MZError::Param` on invalid values. - pub fn new(flush: i32) -> Result { - match flush { - 0 => Ok(MZFlush::None), - 1 | 2 => Ok(MZFlush::Sync), - 3 => Ok(MZFlush::Full), - 4 => Ok(MZFlush::Finish), - _ => Err(MZError::Param), - } - } -} - -/// A list of miniz successful status codes. -/// -/// These are emitted as the [`Ok`] side of a [`MZResult`] in the [`StreamResult`] returned from -/// [`deflate::stream::deflate()`] or [`inflate::stream::inflate()`]. -#[repr(i32)] -#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] -pub enum MZStatus { - /// Operation succeeded. - /// - /// Some data was decompressed or compressed; see the byte counters in the [`StreamResult`] for - /// details. - Ok = 0, - - /// Operation succeeded and end of deflate stream was found. - /// - /// X-ref [`TINFLStatus::Done`][inflate::TINFLStatus::Done] or - /// [`TDEFLStatus::Done`][deflate::core::TDEFLStatus::Done] for `inflate` or `deflate` - /// respectively. - StreamEnd = 1, - - /// Unused - NeedDict = 2, -} - -/// A list of miniz failed status codes. -/// -/// These are emitted as the [`Err`] side of a [`MZResult`] in the [`StreamResult`] returned from -/// [`deflate::stream::deflate()`] or [`inflate::stream::inflate()`]. -#[repr(i32)] -#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] -pub enum MZError { - /// Unused - ErrNo = -1, - - /// General stream error. - /// - /// See [`inflate::stream::inflate()`] docs for details of how it can occur there. - /// - /// See [`deflate::stream::deflate()`] docs for how it can in principle occur there, though it's - /// believed impossible in practice. - Stream = -2, - - /// Error in inflation; see [`inflate::stream::inflate()`] for details. - /// - /// Not returned from [`deflate::stream::deflate()`]. - Data = -3, - - /// Unused - Mem = -4, - - /// Buffer-related error. - /// - /// See the docs of [`deflate::stream::deflate()`] or [`inflate::stream::inflate()`] for details - /// of when it would trigger in the one you're using. - Buf = -5, - - /// Unused - Version = -6, - - /// Bad parameters. - /// - /// This can be returned from [`deflate::stream::deflate()`] in the case of bad parameters. See - /// [`TDEFLStatus::BadParam`][deflate::core::TDEFLStatus::BadParam]. - Param = -10_000, -} - -/// How compressed data is wrapped. -#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] -#[non_exhaustive] -pub enum DataFormat { - /// Wrapped using the [zlib](http://www.zlib.org/rfc-zlib.html) format. - Zlib, - /// Zlib wrapped but ignore and don't compute the adler32 checksum. - /// Currently only used for inflate, behaves the same as Zlib for compression. - ZLibIgnoreChecksum, - /// Raw DEFLATE. - Raw, -} - -impl DataFormat { - pub fn from_window_bits(window_bits: i32) -> DataFormat { - if window_bits > 0 { - DataFormat::Zlib - } else { - DataFormat::Raw - } - } - - pub fn to_window_bits(self) -> i32 { - match self { - DataFormat::Zlib | DataFormat::ZLibIgnoreChecksum => shared::MZ_DEFAULT_WINDOW_BITS, - DataFormat::Raw => -shared::MZ_DEFAULT_WINDOW_BITS, - } - } -} - -/// `Result` alias for all miniz status codes both successful and failed. -pub type MZResult = Result; - -/// A structure containing the result of a call to the inflate or deflate streaming functions. -#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] -pub struct StreamResult { - /// The number of bytes consumed from the input slice. - pub bytes_consumed: usize, - /// The number of bytes written to the output slice. - pub bytes_written: usize, - /// The return status of the call. - pub status: MZResult, -} - -impl StreamResult { - #[inline] - pub const fn error(error: MZError) -> StreamResult { - StreamResult { - bytes_consumed: 0, - bytes_written: 0, - status: Err(error), - } - } -} - -impl core::convert::From for MZResult { - fn from(res: StreamResult) -> Self { - res.status - } -} - -impl core::convert::From<&StreamResult> for MZResult { - fn from(res: &StreamResult) -> Self { - res.status - } -} diff --git a/vendor/miniz_oxide/src/shared.rs b/vendor/miniz_oxide/src/shared.rs deleted file mode 100644 index 8b81fb1..0000000 --- a/vendor/miniz_oxide/src/shared.rs +++ /dev/null @@ -1,25 +0,0 @@ -#[doc(hidden)] -pub const MZ_ADLER32_INIT: u32 = 1; - -#[doc(hidden)] -pub const MZ_DEFAULT_WINDOW_BITS: i32 = 15; - -pub const HUFFMAN_LENGTH_ORDER: [u8; 19] = [ - 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15, -]; - -#[doc(hidden)] -#[cfg(not(feature = "simd"))] -pub fn update_adler32(adler: u32, data: &[u8]) -> u32 { - let mut hash = adler::Adler32::from_checksum(adler); - hash.write_slice(data); - hash.checksum() -} - -#[doc(hidden)] -#[cfg(feature = "simd")] -pub fn update_adler32(adler: u32, data: &[u8]) -> u32 { - let mut hash = simd_adler32::Adler32::from_checksum(adler); - hash.write(data); - hash.finish() -} -- cgit v1.2.3