deflate64-0.1.8/.cargo_vcs_info.json0000644000000001360000000000100126200ustar { "git": { "sha1": "81344c48297b24c77917dc34b7cb49ed2850264a" }, "path_in_vcs": "" }deflate64-0.1.8/.git-blame-ignore-revs000064400000000000000000000000651046102023000155110ustar 00000000000000# cargo fmt 766b6d314e3c1208f8275d7c83c1deab0030d857 deflate64-0.1.8/.gitignore000064400000000000000000000000221046102023000133720ustar 00000000000000Cargo.lock target deflate64-0.1.8/CHANGELOG.md000064400000000000000000000037051046102023000132260ustar 00000000000000# Changelog All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog]. [Keep a Changelog]: https://keepachangelog.com/en/1.1.0/ ## [Unreleased] ### Added ### Changed ### Deprecated ### Removed ### Fixed ### Security ## [0.1.8] - 2024-03-11 ### Fixed - Panic with Invalid Data [`#26`](https://github.com/anatawa12/deflate64-rs/pull/26) [`#24`](https://github.com/anatawa12/deflate64-rs/pull/24) ## [0.1.7] - 2024-01-27 ## [0.1.6] - 2023-10-15 ### Fixed - Overflow substract with some archive [`#14`](https://github.com/anatawa12/deflate64-rs/pull/14) ## [0.1.5] - 2023-08-19 ### Added - test: 7zip compatibility test - Changelog file ### Changed - Remove `unsafe` code ## [0.1.4] ### Added - `Deflate64Decoder`, Streaming `Read` decoder implementation ### Fixed - Overflow error in debug build ## [0.1.3] ### Added - Many documentation comment - `InflaterManaged.errored()` ### Changed - Remove Box usage in `InflaterManaged` ## [0.1.2] - 2023-01-16 ### Fixed - Release build will cause compilation error ### Fixed - Several bugs ## [0.1.1] - 2023-01-15 ### Added - Implement Debug in many struct ## [0.1.0] - 2023-07-29 ### Added - Initial Deflate64 implementation [Unreleased]: https://github.com/anatawa12/deflate64-rs/compare/v0.1.8...HEAD [0.1.8]: https://github.com/anatawa12/deflate64-rs/compare/v0.1.7...v0.1.8 [0.1.7]: https://github.com/anatawa12/deflate64-rs/compare/v0.1.6...v0.1.7 [0.1.6]: https://github.com/anatawa12/deflate64-rs/compare/v0.1.5...v0.1.6 [0.1.5]: https://github.com/anatawa12/deflate64-rs/compare/v0.1.4...v0.1.5 [0.1.4]: https://github.com/anatawa12/deflate64-rs/compare/v0.1.3...v0.1.4 [0.1.3]: https://github.com/anatawa12/deflate64-rs/compare/v0.1.2...v0.1.3 [0.1.2]: https://github.com/anatawa12/deflate64-rs/compare/v0.1.1...v0.1.2 [0.1.1]: https://github.com/anatawa12/deflate64-rs/compare/v0.1.0...v0.1.1 [0.1.0]: https://github.com/anatawa12/deflate64-rs/releases/tag/v0.1.0 deflate64-0.1.8/Cargo.toml0000644000000021770000000000100106250ustar # THIS FILE IS AUTOMATICALLY GENERATED BY CARGO # # When uploading crates to the registry Cargo will automatically # "normalize" Cargo.toml files for maximal compatibility # with all versions of Cargo and also rewrite `path` dependencies # to registry (e.g., crates.io) dependencies. # # If you are reading this file be aware that the original Cargo.toml # will likely look very different (and much more reasonable). # See Cargo.toml.orig for the original contents. [package] edition = "2021" name = "deflate64" version = "0.1.8" authors = ["anatawa12 "] exclude = [ ".github/**", "tests/**", "test-assets/**", ] description = "Deflate64 implementation based on .NET's implementation" homepage = "https://github.com/anatawa12/deflate64-rs#readme" readme = "README.md" keywords = [ "deflate", "deflate64", "compression", ] categories = ["compression"] license = "MIT" repository = "https://github.com/anatawa12/deflate64-rs" [dependencies] [dev-dependencies.bytemuck] version = "1.13.1" features = ["derive"] [dev-dependencies.proptest] version = "1.2.0" [dev-dependencies.tempfile] version = "3.7.1" deflate64-0.1.8/Cargo.toml.orig000064400000000000000000000011561046102023000143020ustar 00000000000000[package] name = "deflate64" version = "0.1.8" edition = "2021" license = "MIT" authors = ["anatawa12 "] description = "Deflate64 implementation based on .NET's implementation" homepage = "https://github.com/anatawa12/deflate64-rs#readme" repository = "https://github.com/anatawa12/deflate64-rs" readme = "README.md" keywords = ["deflate", "deflate64", "compression"] categories = ["compression"] exclude = [ ".github/**", "tests/**", "test-assets/**", ] [dependencies] [dev-dependencies] bytemuck = { version = "1.13.1", features = ["derive"] } proptest = "1.2.0" tempfile = "3.7.1" deflate64-0.1.8/LICENSE000064400000000000000000000021711046102023000124160ustar 00000000000000The MIT License (MIT) Copyright (c) .NET Foundation and Contributors Copyright (c) anatawa12 2023 All rights reserved. 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. deflate64-0.1.8/README.md000064400000000000000000000004711046102023000126710ustar 00000000000000Deflate64 implementation based on [.NET's implementation][dotnet-impl] This is made to unzip zip file with deflate64 made with windows 11. [dotnet-impl]: https://github.com/dotnet/runtime/tree/e5efd8010e19593298dc2c3ee15106d5aec5a924/src/libraries/System.IO.Compression/src/System/IO/Compression/DeflateManaged deflate64-0.1.8/src/huffman_tree.rs000064400000000000000000000277251046102023000152250ustar 00000000000000use crate::input_buffer::InputBuffer; use crate::InternalErr; #[derive(Debug)] pub(crate) struct HuffmanTree { code_lengths_length: u16, table: [i16; 1 << Self::TABLE_BITS], left: [i16; Self::MAX_CODE_LENGTHS * 2], right: [i16; Self::MAX_CODE_LENGTHS * 2], code_length_array: [u8; Self::MAX_CODE_LENGTHS], } // because of lifetime conflict, we cannot use simple accessor method. macro_rules! get { ($self: ident.table) => { $self.table[..] }; ($self: ident.left) => { $self.left[..2 * $self.code_lengths_length as usize] }; ($self: ident.right) => { $self.right[..2 * $self.code_lengths_length as usize] }; ($self: ident.code_length_array) => { $self.code_length_array[..$self.code_lengths_length as usize] }; } impl HuffmanTree { pub(crate) const MAX_CODE_LENGTHS: usize = 288; pub(crate) const TABLE_BITS: u8 = 9; pub(crate) const TABLE_BITS_MASK: usize = (1 << Self::TABLE_BITS) - 1; pub(crate) const MAX_LITERAL_TREE_ELEMENTS: usize = 288; pub(crate) const MAX_DIST_TREE_ELEMENTS: usize = 32; pub(crate) const END_OF_BLOCK_CODE: usize = 256; pub(crate) const NUMBER_OF_CODE_LENGTH_TREE_ELEMENTS: usize = 19; pub fn invalid() -> Self { HuffmanTree { code_lengths_length: Default::default(), table: [0i16; 1 << Self::TABLE_BITS], left: [0i16; Self::MAX_CODE_LENGTHS * 2], right: [0i16; Self::MAX_CODE_LENGTHS * 2], code_length_array: [0u8; Self::MAX_CODE_LENGTHS], } } pub fn static_literal_length_tree() -> Self { HuffmanTree::new(&Self::get_static_literal_tree_length()).unwrap() } pub fn static_distance_tree() -> Self { HuffmanTree::new(&Self::get_static_distance_tree_length()).unwrap() } fn assert_code_lengths_len(len: usize) { debug_assert!( len == Self::MAX_LITERAL_TREE_ELEMENTS || len == Self::MAX_DIST_TREE_ELEMENTS || len == Self::NUMBER_OF_CODE_LENGTH_TREE_ELEMENTS, "we only expect three kinds of Length here" ); } pub fn new(code_lengths: &[u8]) -> Result { Self::assert_code_lengths_len(code_lengths.len()); let code_lengths_length = code_lengths.len(); // I need to find proof that left and right array will always be // enough. I think they are. let mut instance = Self { table: [0; 1 << Self::TABLE_BITS], left: [0; Self::MAX_CODE_LENGTHS * 2], right: [0; Self::MAX_CODE_LENGTHS * 2], code_lengths_length: code_lengths_length as u16, code_length_array: { let mut buffer = [0u8; Self::MAX_CODE_LENGTHS]; buffer[..code_lengths.len()].copy_from_slice(code_lengths); buffer }, }; instance.create_table()?; Ok(instance) } pub fn new_in_place(&mut self, code_lengths: &[u8]) -> Result<(), InternalErr> { Self::assert_code_lengths_len(code_lengths.len()); self.table.fill(0); self.left.fill(0); self.right.fill(0); self.code_lengths_length = code_lengths.len() as u16; self.code_length_array[..code_lengths.len()].copy_from_slice(code_lengths); self.code_length_array[code_lengths.len()..].fill(0); self.create_table() } // Generate the array contains huffman codes lengths for static huffman tree. // The data is in RFC 1951. fn get_static_literal_tree_length() -> [u8; Self::MAX_LITERAL_TREE_ELEMENTS] { let mut literal_tree_length = [0u8; Self::MAX_LITERAL_TREE_ELEMENTS]; literal_tree_length[0..][..144].fill(8); literal_tree_length[144..][..112].fill(9); literal_tree_length[256..][..24].fill(7); literal_tree_length[280..][..8].fill(8); literal_tree_length } const fn get_static_distance_tree_length() -> [u8; Self::MAX_DIST_TREE_ELEMENTS] { [5u8; Self::MAX_DIST_TREE_ELEMENTS] } fn bit_reverse(mut code: u32, mut length: usize) -> u32 { let mut new_code = 0; debug_assert!(length > 0 && length <= 16, "Invalid len"); while { new_code |= code & 1; new_code <<= 1; code >>= 1; length -= 1; length > 0 } {} new_code >> 1 } fn calculate_huffman_code(&self) -> [u32; Self::MAX_LITERAL_TREE_ELEMENTS] { let mut bit_length_count = [0u32; 17]; for &code_length in get!(self.code_length_array).iter() { bit_length_count[code_length as usize] += 1; } bit_length_count[0] = 0; // clear count for length 0 let mut next_code = [0u32; 17]; let mut temp_code = 0u32; for bits in 1..=16 { temp_code = (temp_code + bit_length_count[bits - 1]) << 1; next_code[bits] = temp_code; } let mut code = [0u32; Self::MAX_LITERAL_TREE_ELEMENTS]; for (i, &len) in get!(self.code_length_array).iter().enumerate() { if len > 0 { code[i] = Self::bit_reverse(next_code[len as usize], len as usize); next_code[len as usize] += 1; } } code } fn create_table(&mut self) -> Result<(), InternalErr> { let code_array = self.calculate_huffman_code(); let mut avail = get!(self.code_length_array).len() as i16; for (ch, &len) in get!(self.code_length_array).iter().enumerate() { if len > 0 { // start value (bit reversed) let mut start = code_array[ch] as usize; if len <= Self::TABLE_BITS { // If a particular symbol is shorter than nine bits, // then that symbol's translation is duplicated // in all those entries that start with that symbol's bits. // For example, if the symbol is four bits, then it's duplicated // 32 times in a nine-bit table. If a symbol is nine bits long, // it appears in the table once. // // Make sure that in the loop below, code is always // less than table_size. // // On last iteration we store at array index: // initial_start_at + (locs-1)*increment // = initial_start_at + locs*increment - increment // = initial_start_at + (1 << tableBits) - increment // = initial_start_at + table_size - increment // // Therefore we must ensure: // initial_start_at + table_size - increment < table_size // or: initial_start_at < increment // let increment = 1 << len; if start >= increment { return Err(InternalErr::DataError); // InvalidHuffmanData } // Note the bits in the table are reverted. let locs = 1 << (Self::TABLE_BITS - len); for _ in 0..locs { get!(self.table)[start] = ch as i16; start += increment; } } else { // For any code which has length longer than num_elements, // build a binary tree. let mut overflow_bits = len - Self::TABLE_BITS; // the nodes we need to represent the data. let mut code_bit_mask = 1 << Self::TABLE_BITS; // mask to get current bit (the bits can't fit in the table) // the left, right table is used to represent the // the rest bits. When we got the first part (number bits.) and look at // tbe table, we will need to follow the tree to find the real character. // This is in place to avoid bloating the table if there are // a few ones with long code. let mut index = start & ((1 << Self::TABLE_BITS) - 1); let mut array = &mut get!(self.table); while { let mut value = array[index]; if value == 0 { // set up next pointer if this node is not used before. array[index] = -avail; // use next available slot. value = -avail; avail += 1; } if value > 0 { // prevent an IndexOutOfRangeException from array[index] return Err(InternalErr::DataError); // InvalidHuffmanData } debug_assert!( value < 0, "create_table: Only negative numbers are used for tree pointers!" ); if (start & code_bit_mask) == 0 { // if current bit is 0, go change the left array array = &mut get!(self.left); } else { // if current bit is 1, set value in the right array array = &mut get!(self.right); } index = -value as usize; // go to next node if index >= array.len() { // prevent an IndexOutOfRangeException from array[index] return Err(InternalErr::DataError); // InvalidHuffmanData } code_bit_mask <<= 1; overflow_bits -= 1; overflow_bits != 0 } {} array[index] = ch as i16; } } } Ok(()) } pub fn get_next_symbol(&self, input: &mut InputBuffer<'_>) -> Result { assert_ne!(self.code_lengths_length, 0, "invalid table"); // Try to load 16 bits into input buffer if possible and get the bit_buffer value. // If there aren't 16 bits available we will return all we have in the // input buffer. let bit_buffer = input.try_load_16bits(); if input.available_bits() == 0 { // running out of input. return Err(InternalErr::DataNeeded); } // decode an element let mut symbol = self.table[bit_buffer as usize & Self::TABLE_BITS_MASK]; if symbol < 0 { // this will be the start of the binary tree // navigate the tree let mut mask = 1 << Self::TABLE_BITS; while { symbol = -symbol; if (bit_buffer & mask) == 0 { symbol = get!(self.left)[symbol as usize]; } else { symbol = get!(self.right)[symbol as usize]; } mask <<= 1; symbol < 0 } {} } debug_assert!(symbol >= 0); let code_length = get!(self.code_length_array)[symbol as usize] as i32; // huffman code lengths must be at least 1 bit long if code_length <= 0 { return Err(InternalErr::DataError); // InvalidHuffmanData } // // If this code is longer than the # bits we had in the bit buffer (i.e. // we read only part of the code), we can hit the entry in the table or the tree // for another symbol. However the length of another symbol will not match the // available bits count. if code_length > input.available_bits() { // We already tried to load 16 bits and maximum length is 15, // so this means we are running out of input. return Err(InternalErr::DataNeeded); } input.skip_bits(code_length); Ok(symbol as u16) } } deflate64-0.1.8/src/inflater_managed.rs000064400000000000000000000651741046102023000160420ustar 00000000000000use crate::huffman_tree::HuffmanTree; use crate::input_buffer::{BitsBuffer, InputBuffer}; use crate::output_window::OutputWindow; use crate::{array_copy, array_copy1, BlockType, InflateResult, InflaterState, InternalErr}; use std::cmp::min; // Extra bits for length code 257 - 285. static EXTRA_LENGTH_BITS: &[u8] = &[ 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, 16, ]; // The base length for length code 257 - 285. // The formula to get the real length for a length code is lengthBase[code - 257] + (value stored in extraBits) static LENGTH_BASE: &[u8] = &[ 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, 3, ]; // The base distance for distance code 0 - 31 // The real distance for a distance code is distanceBasePosition[code] + (value stored in extraBits) static DISTANCE_BASE_POSITION: &[u16] = &[ 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145, 8193, 12289, 16385, 24577, 32769, 49153, ]; // code lengths for code length alphabet is stored in following order static CODE_ORDER: &[u8] = &[ 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15, ]; static STATIC_DISTANCE_TREE_TABLE: &[u8] = &[ 0x00, 0x10, 0x08, 0x18, 0x04, 0x14, 0x0c, 0x1c, 0x02, 0x12, 0x0a, 0x1a, 0x06, 0x16, 0x0e, 0x1e, 0x01, 0x11, 0x09, 0x19, 0x05, 0x15, 0x0d, 0x1d, 0x03, 0x13, 0x0b, 0x1b, 0x07, 0x17, 0x0f, 0x1f, ]; // source: https://github.com/dotnet/runtime/blob/82dac28143be0740d795f434db9b70f61b3b7a04/src/libraries/System.IO.Compression/src/System/IO/Compression/DeflateManaged/OutputWindow.cs#L17 const TABLE_LOOKUP_LENGTH_MAX: usize = 65536; const TABLE_LOOKUP_DISTANCE_MAX: usize = 65538; /// The streaming Inflater for deflate64 /// /// This struct has big buffer so It's not recommended to move this struct. #[derive(Debug)] pub struct InflaterManaged { output: OutputWindow, bits: BitsBuffer, literal_length_tree: HuffmanTree, distance_tree: HuffmanTree, state: InflaterState, bfinal: bool, block_type: BlockType, // uncompressed block block_length_buffer: [u8; 4], block_length: usize, // compressed block length: usize, distance_code: u16, extra_bits: i32, loop_counter: u32, literal_length_code_count: u32, distance_code_count: u32, code_length_code_count: u32, code_array_size: u32, length_code: u16, code_list: [u8; HuffmanTree::MAX_LITERAL_TREE_ELEMENTS + HuffmanTree::MAX_DIST_TREE_ELEMENTS], // temporary array to store the code length for literal/Length and distance code_length_tree_code_length: [u8; HuffmanTree::NUMBER_OF_CODE_LENGTH_TREE_ELEMENTS], deflate64: bool, code_length_tree: HuffmanTree, uncompressed_size: usize, current_inflated_count: usize, } impl InflaterManaged { /// Initializes Inflater #[allow(clippy::new_without_default)] #[inline] pub fn new() -> Self { Self::with_uncompressed_size(usize::MAX) } /// Initializes Inflater with expected uncompressed size. pub fn with_uncompressed_size(uncompressed_size: usize) -> Self { Self { output: OutputWindow::new(), bits: BitsBuffer::new(), literal_length_tree: HuffmanTree::invalid(), code_list: [0u8; HuffmanTree::MAX_LITERAL_TREE_ELEMENTS + HuffmanTree::MAX_DIST_TREE_ELEMENTS], code_length_tree_code_length: [0u8; HuffmanTree::NUMBER_OF_CODE_LENGTH_TREE_ELEMENTS], deflate64: true, code_length_tree: HuffmanTree::invalid(), uncompressed_size, state: InflaterState::ReadingBFinal, // start by reading BFinal bit bfinal: false, block_type: BlockType::Uncompressed, block_length_buffer: [0u8; 4], block_length: 0, length: 0, distance_code: 0, extra_bits: 0, loop_counter: 0, literal_length_code_count: 0, distance_code_count: 0, code_length_code_count: 0, code_array_size: 0, distance_tree: HuffmanTree::invalid(), length_code: 0, current_inflated_count: 0, } } /// Returns true if deflating finished /// /// This also returns true if this inflater is in error state pub fn finished(&self) -> bool { self.state == InflaterState::Done || self.state == InflaterState::DataErrored } /// Returns true if this inflater is in error state pub fn errored(&self) -> bool { self.state == InflaterState::DataErrored } /// The count of bytes currently inflater has in internal output buffer #[allow(dead_code)] pub fn available_output(&self) -> usize { self.output.available_bytes() } /// Try to decompress from `input` to `output`. /// /// This will decompress data until `output` is full, `input` is empty, /// the end if the deflate64 stream is hit, or there is error data in the deflate64 stream. pub fn inflate(&mut self, input: &[u8], mut output: &mut [u8]) -> InflateResult { // copy bytes from output to outputbytes if we have available bytes // if buffer is not filled up. keep decoding until no input are available // if decodeBlock returns false. Throw an exception. let mut result = InflateResult::new(); let mut input = InputBuffer::new(self.bits, input); while 'while_loop: { let mut copied = 0; if self.uncompressed_size == usize::MAX { copied = self.output.copy_to(output); } else if self.uncompressed_size > self.current_inflated_count { let len = min( output.len(), self.uncompressed_size - self.current_inflated_count, ); output = &mut output[..len]; copied = self.output.copy_to(output); self.current_inflated_count += copied; } else { self.state = InflaterState::Done; self.output.clear_bytes_used(); } if copied > 0 { output = &mut output[copied..]; result.bytes_written += copied; } if output.is_empty() { // filled in the bytes buffer break 'while_loop false; } // decode will return false when more input is needed if self.errored() { result.data_error = true; break 'while_loop false; } else if self.finished() { break 'while_loop false; } match self.decode(&mut input) { Ok(()) => true, Err(InternalErr::DataNeeded) => false, Err(InternalErr::DataError) => { self.state = InflaterState::DataErrored; result.data_error = true; false } } } {} self.bits = input.bits; result.bytes_consumed = input.read_bytes; result } fn decode(&mut self, input: &mut InputBuffer<'_>) -> Result<(), InternalErr> { let mut eob = false; let result; if self.errored() { return Err(InternalErr::DataError); } else if self.finished() { return Ok(()); } if self.state == InflaterState::ReadingBFinal { // reading bfinal bit // Need 1 bit self.bfinal = input.get_bits(1)? != 0; self.state = InflaterState::ReadingBType; } if self.state == InflaterState::ReadingBType { // Need 2 bits self.state = InflaterState::ReadingBType; let bits = input.get_bits(2)?; self.block_type = BlockType::from_int(bits).ok_or(InternalErr::DataError)?; match self.block_type { BlockType::Dynamic => { self.state = InflaterState::ReadingNumLitCodes; } BlockType::Static => { self.literal_length_tree = HuffmanTree::static_literal_length_tree(); self.distance_tree = HuffmanTree::static_distance_tree(); self.state = InflaterState::DecodeTop; } BlockType::Uncompressed => { self.state = InflaterState::UncompressedAligning; } } } if self.block_type == BlockType::Dynamic { if self.state < InflaterState::DecodeTop { // we are reading the header result = self.decode_dynamic_block_header(input); } else { result = self.decode_block(input, &mut eob); // this can returns true when output is full } } else if self.block_type == BlockType::Static { result = self.decode_block(input, &mut eob); } else if self.block_type == BlockType::Uncompressed { result = self.decode_uncompressed_block(input, &mut eob); } else { result = Err(InternalErr::DataError); // UnknownBlockType } // // If we reached the end of the block and the block we were decoding had // bfinal=1 (final block) // if eob && self.bfinal { self.state = InflaterState::Done; } result } fn decode_uncompressed_block( &mut self, input: &mut InputBuffer<'_>, end_of_block: &mut bool, ) -> Result<(), InternalErr> { *end_of_block = false; loop { match self.state { InflaterState::UncompressedAligning => { input.skip_to_byte_boundary(); self.state = InflaterState::UncompressedByte1; continue; //goto case InflaterState.UncompressedByte1; } InflaterState::UncompressedByte1 | InflaterState::UncompressedByte2 | InflaterState::UncompressedByte3 | InflaterState::UncompressedByte4 => { self.block_length_buffer [(self.state - InflaterState::UncompressedByte1) as usize] = input.get_bits(8)? as u8; if self.state == InflaterState::UncompressedByte4 { self.block_length = self.block_length_buffer[0] as usize + (self.block_length_buffer[1] as usize) * 256; let block_length_complement: i32 = self.block_length_buffer[2] as i32 + (self.block_length_buffer[3] as i32) * 256; // make sure complement matches if self.block_length as u16 != !block_length_complement as u16 { return Err(InternalErr::DataError); // InvalidBlockLength } } self.state = match self.state { InflaterState::UncompressedByte1 => InflaterState::UncompressedByte2, InflaterState::UncompressedByte2 => InflaterState::UncompressedByte3, InflaterState::UncompressedByte3 => InflaterState::UncompressedByte4, InflaterState::UncompressedByte4 => InflaterState::DecodingUncompressed, _ => unreachable!(), }; } InflaterState::DecodingUncompressed => { // Directly copy bytes from input to output. let bytes_copied = self.output.copy_from(input, self.block_length); self.block_length -= bytes_copied; if self.block_length == 0 { // Done with this block, need to re-init bit buffer for next block self.state = InflaterState::ReadingBFinal; *end_of_block = true; return Ok(()); } // We can fail to copy all bytes for two reasons: // Running out of Input // running out of free space in output window if self.output.free_bytes() == 0 { return Ok(()); } return Err(InternalErr::DataNeeded); } _ => { panic!("UnknownState"); } } } } fn decode_block( &mut self, input: &mut InputBuffer<'_>, end_of_block_code_seen: &mut bool, ) -> Result<(), InternalErr> { *end_of_block_code_seen = false; let mut free_bytes = self.output.free_bytes(); // it is a little bit faster than frequently accessing the property while free_bytes > TABLE_LOOKUP_LENGTH_MAX { // With Deflate64 we can have up to a 64kb length, so we ensure at least that much space is available // in the OutputWindow to avoid overwriting previous unflushed output data. let mut symbol; match self.state { InflaterState::DecodeTop => { // decode an element from the literal tree // TODO: optimize this!!! symbol = self.literal_length_tree.get_next_symbol(input)?; #[allow(clippy::comparison_chain)] if symbol < 256 { // literal self.output.write(symbol as u8); free_bytes -= 1; } else if symbol == 256 { // end of block *end_of_block_code_seen = true; // Reset state self.state = InflaterState::ReadingBFinal; return Ok(()); } else { // length/distance pair symbol -= 257; // length code started at 257 if symbol < 8 { symbol += 3; // match length = 3,4,5,6,7,8,9,10 self.extra_bits = 0; } else if !self.deflate64 && symbol == 28 { // extra bits for code 285 is 0 symbol = 258; // code 285 means length 258 self.extra_bits = 0; } else { if symbol as usize >= EXTRA_LENGTH_BITS.len() { return Err(InternalErr::DataError); // GenericInvalidData } self.extra_bits = EXTRA_LENGTH_BITS[symbol as usize] as i32; assert_ne!(self.extra_bits, 0, "We handle other cases separately!"); } self.length = symbol as usize; self.state = InflaterState::HaveInitialLength; continue; //goto case InflaterState::HaveInitialLength; } } InflaterState::HaveInitialLength => { if self.extra_bits > 0 { self.state = InflaterState::HaveInitialLength; let bits = input.get_bits(self.extra_bits)?; if self.length >= LENGTH_BASE.len() { return Err(InternalErr::DataError); // GenericInvalidData } self.length = LENGTH_BASE[self.length] as usize + bits as usize; } self.state = InflaterState::HaveFullLength; continue; // goto case InflaterState::HaveFullLength; } InflaterState::HaveFullLength => { if self.block_type == BlockType::Dynamic { let bits = self.distance_tree.get_next_symbol(input)?; self.distance_code = bits; } else { // get distance code directly for static block let bits = input.get_bits(5)?; self.distance_code = STATIC_DISTANCE_TREE_TABLE[bits as usize] as u16; } self.state = InflaterState::HaveDistCode; continue; //goto case InflaterState.HaveDistCode; } InflaterState::HaveDistCode => { // To avoid a table lookup we note that for distanceCode > 3, // extra_bits = (distanceCode-2) >> 1 let offset: usize; if self.distance_code > 3 { self.extra_bits = ((self.distance_code - 2) >> 1) as i32; let bits = input.get_bits(self.extra_bits)?; offset = DISTANCE_BASE_POSITION[self.distance_code as usize] as usize + bits as usize; } else { offset = (self.distance_code + 1) as usize; } if self.length > TABLE_LOOKUP_LENGTH_MAX || offset > TABLE_LOOKUP_DISTANCE_MAX { return Err(InternalErr::DataError); } self.output.write_length_distance(self.length, offset); free_bytes -= self.length; self.state = InflaterState::DecodeTop; } _ => { //Debug.Fail("check why we are here!"); panic!("UnknownState"); } } } Ok(()) } // Format of the dynamic block header: // 5 Bits: HLIT, # of Literal/Length codes - 257 (257 - 286) // 5 Bits: HDIST, # of Distance codes - 1 (1 - 32) // 4 Bits: HCLEN, # of Code Length codes - 4 (4 - 19) // // (HCLEN + 4) x 3 bits: code lengths for the code length // alphabet given just above, in the order: 16, 17, 18, // 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 // // These code lengths are interpreted as 3-bit integers // (0-7); as above, a code length of 0 means the // corresponding symbol (literal/length or distance code // length) is not used. // // HLIT + 257 code lengths for the literal/length alphabet, // encoded using the code length Huffman code // // HDIST + 1 code lengths for the distance alphabet, // encoded using the code length Huffman code // // The code length repeat codes can cross from HLIT + 257 to the // HDIST + 1 code lengths. In other words, all code lengths form // a single sequence of HLIT + HDIST + 258 values. fn decode_dynamic_block_header( &mut self, input: &mut InputBuffer<'_>, ) -> Result<(), InternalErr> { 'switch: loop { match self.state { InflaterState::ReadingNumLitCodes => { let bits = input.get_bits(5)?; self.literal_length_code_count = bits as u32 + 257; self.state = InflaterState::ReadingNumDistCodes; continue 'switch; //goto case InflaterState::ReadingNumDistCodes; } InflaterState::ReadingNumDistCodes => { let bits = input.get_bits(5)?; self.distance_code_count = bits as u32 + 1; self.state = InflaterState::ReadingNumCodeLengthCodes; continue 'switch; // goto case InflaterState::ReadingNumCodeLengthCodes; } InflaterState::ReadingNumCodeLengthCodes => { let bits = input.get_bits(4)?; self.code_length_code_count = bits as u32 + 4; self.loop_counter = 0; self.state = InflaterState::ReadingCodeLengthCodes; continue 'switch; // goto case InflaterState::ReadingCodeLengthCodes; } InflaterState::ReadingCodeLengthCodes => { while self.loop_counter < self.code_length_code_count { let bits = input.get_bits(3)?; self.code_length_tree_code_length [CODE_ORDER[self.loop_counter as usize] as usize] = bits as u8; self.loop_counter += 1; } for &code_oder in &CODE_ORDER[self.code_length_code_count as usize..] { self.code_length_tree_code_length[code_oder as usize] = 0; } // create huffman tree for code length self.code_length_tree .new_in_place(&self.code_length_tree_code_length)?; self.code_array_size = self.literal_length_code_count + self.distance_code_count; self.loop_counter = 0; // reset loop count self.state = InflaterState::ReadingTreeCodesBefore; continue 'switch; // goto case InflaterState::ReadingTreeCodesBefore; } InflaterState::ReadingTreeCodesBefore | InflaterState::ReadingTreeCodesAfter => { while self.loop_counter < self.code_array_size { if self.state == InflaterState::ReadingTreeCodesBefore { self.length_code = self.code_length_tree.get_next_symbol(input)?; } // The alphabet for code lengths is as follows: // 0 - 15: Represent code lengths of 0 - 15 // 16: Copy the previous code length 3 - 6 times. // The next 2 bits indicate repeat length // (0 = 3, ... , 3 = 6) // Example: Codes 8, 16 (+2 bits 11), // 16 (+2 bits 10) will expand to // 12 code lengths of 8 (1 + 6 + 5) // 17: Repeat a code length of 0 for 3 - 10 times. // (3 bits of length) // 18: Repeat a code length of 0 for 11 - 138 times // (7 bits of length) if self.length_code <= 15 { self.code_list[self.loop_counter as usize] = self.length_code as u8; self.loop_counter += 1; } else { let repeat_count: u32; if self.length_code == 16 { self.state = InflaterState::ReadingTreeCodesAfter; if self.loop_counter == 0 { // can't have "prev code" on first code return Err(InternalErr::DataError); } let bits = input.get_bits(2)?; let previous_code = self.code_list[self.loop_counter as usize - 1]; repeat_count = (bits + 3) as u32; if self.loop_counter + repeat_count > self.code_array_size { //throw new InvalidDataException(); return Err(InternalErr::DataError); } for _ in 0..repeat_count { self.code_list[self.loop_counter as usize] = previous_code; self.loop_counter += 1; } } else if self.length_code == 17 { self.state = InflaterState::ReadingTreeCodesAfter; let bits = input.get_bits(3)?; repeat_count = (bits + 3) as u32; if self.loop_counter + repeat_count > self.code_array_size { //throw new InvalidDataException(); return Err(InternalErr::DataError); } for _ in 0..repeat_count { self.code_list[self.loop_counter as usize] = 0; self.loop_counter += 1; } } else { // code == 18 self.state = InflaterState::ReadingTreeCodesAfter; let bits = input.get_bits(7)?; repeat_count = (bits + 11) as u32; if self.loop_counter + repeat_count > self.code_array_size { //throw new InvalidDataException(); return Err(InternalErr::DataError); } for _ in 0..repeat_count { self.code_list[self.loop_counter as usize] = 0; self.loop_counter += 1; } } } self.state = InflaterState::ReadingTreeCodesBefore; // we want to read the next code. } break 'switch; } _ => { panic!("InvalidDataException: UnknownState"); } } } let mut literal_tree_code_length = [0u8; HuffmanTree::MAX_LITERAL_TREE_ELEMENTS]; let mut distance_tree_code_length = [0u8; HuffmanTree::MAX_DIST_TREE_ELEMENTS]; // Create literal and distance tables array_copy( &self.code_list, &mut literal_tree_code_length, self.literal_length_code_count as usize, ); array_copy1( &self.code_list, self.literal_length_code_count as usize, &mut distance_tree_code_length, 0, self.distance_code_count as usize, ); // Make sure there is an end-of-block code, otherwise how could we ever end? if literal_tree_code_length[HuffmanTree::END_OF_BLOCK_CODE] == 0 { return Err(InternalErr::DataError); // InvalidDataException } self.literal_length_tree .new_in_place(&literal_tree_code_length)?; self.distance_tree .new_in_place(&distance_tree_code_length)?; self.state = InflaterState::DecodeTop; Ok(()) } } deflate64-0.1.8/src/input_buffer.rs000064400000000000000000000111761046102023000152430ustar 00000000000000use crate::InternalErr; use std::cmp::min; #[derive(Copy, Clone, Debug)] pub(crate) struct BitsBuffer { bit_buffer: u32, bits_in_buffer: i32, } impl BitsBuffer { pub(crate) fn new() -> BitsBuffer { Self { bit_buffer: 0, bits_in_buffer: 0, } } } pub(crate) struct InputBuffer<'a> { pub bits: BitsBuffer, pub buffer: &'a [u8], pub read_bytes: usize, } impl<'a> InputBuffer<'a> { pub fn new(bits: BitsBuffer, buffer: &'a [u8]) -> Self { Self { bits, buffer, read_bytes: 0, } } pub fn available_bits(&self) -> i32 { self.bits.bits_in_buffer } pub fn available_bytes(&self) -> usize { self.buffer.len() + (self.bits.bits_in_buffer / 4) as usize } pub fn ensure_bits_available(&mut self, count: i32) -> bool { debug_assert!(0 < count && count <= 16, "count is invalid."); // manual inlining to improve perf if self.bits.bits_in_buffer < count { if self.needs_input() { return false; } // insert a byte to bitbuffer self.bits.bit_buffer |= (self.buffer[0] as u32) << self.bits.bits_in_buffer; self.advance(1); self.bits.bits_in_buffer += 8; if self.bits.bits_in_buffer < count { if self.needs_input() { return false; } // insert a byte to bitbuffer self.bits.bit_buffer |= (self.buffer[0] as u32) << self.bits.bits_in_buffer; self.advance(1); self.bits.bits_in_buffer += 8; } } true } pub fn try_load_16bits(&mut self) -> u32 { if self.bits.bits_in_buffer < 8 { if self.buffer.len() > 1 { self.bits.bit_buffer |= (self.buffer[0] as u32) << self.bits.bits_in_buffer; self.bits.bit_buffer |= (self.buffer[1] as u32) << (self.bits.bits_in_buffer + 8); self.advance(2); self.bits.bits_in_buffer += 16; } else if !self.buffer.is_empty() { self.bits.bit_buffer |= (self.buffer[0] as u32) << self.bits.bits_in_buffer; self.advance(1); self.bits.bits_in_buffer += 8; } } else if self.bits.bits_in_buffer < 16 && !self.buffer.is_empty() { self.bits.bit_buffer |= (self.buffer[0] as u32) << self.bits.bits_in_buffer; self.advance(1); self.bits.bits_in_buffer += 8; } self.bits.bit_buffer } fn get_bit_mask(&self, count: i32) -> u32 { (1 << count) - 1 } pub fn get_bits(&mut self, count: i32) -> Result { debug_assert!(0 < count && count <= 16, "count is invalid."); if !self.ensure_bits_available(count) { return Err(InternalErr::DataNeeded); } let result = (self.bits.bit_buffer & self.get_bit_mask(count)) as u16; self.bits.bit_buffer >>= count; self.bits.bits_in_buffer -= count; Ok(result) } pub fn copy_to(&mut self, mut output: &mut [u8]) -> usize { debug_assert!(self.bits.bits_in_buffer % 8 == 0); // Copy the bytes in bitBuffer first. let mut bytes_from_bit_buffer = 0; while self.bits.bits_in_buffer > 0 && !output.is_empty() { output[0] = self.bits.bit_buffer as u8; output = &mut output[1..]; self.bits.bit_buffer >>= 8; self.bits.bits_in_buffer -= 8; bytes_from_bit_buffer += 1; } if output.is_empty() { return bytes_from_bit_buffer; } let length = min(output.len(), self.buffer.len()); output[..length].copy_from_slice(&self.buffer[..length]); self.advance(length); bytes_from_bit_buffer + length } pub fn needs_input(&self) -> bool { self.buffer.is_empty() } /// Skip n bits in the buffer. pub fn skip_bits(&mut self, n: i32) { debug_assert!( self.bits.bits_in_buffer >= n, "No enough bits in the buffer, Did you call ensure_bits_available?" ); self.bits.bit_buffer >>= n; self.bits.bits_in_buffer -= n; } /// Skips to the next byte boundary. pub fn skip_to_byte_boundary(&mut self) { self.bits.bit_buffer >>= self.bits.bits_in_buffer % 8; self.bits.bits_in_buffer -= self.bits.bits_in_buffer % 8; } fn advance(&mut self, buf: usize) { self.buffer = &self.buffer[buf..]; self.read_bytes += buf; } } deflate64-0.1.8/src/lib.rs000064400000000000000000000071401046102023000133150ustar 00000000000000//! Deflate64 implementation based on [.NET System.IO.Compression][dotnet]. //! //! This is made to unzip zip file with deflate64 made with windows 11. //! //! [dotnet]: https://github.com/dotnet/runtime/tree/e5efd8010e19593298dc2c3ee15106d5aec5a924/src/libraries/System.IO.Compression/src/System/IO/Compression/DeflateManaged #![forbid(unsafe_code)] #![deny(rust_2018_idioms, nonstandard_style, future_incompatible)] mod huffman_tree; mod inflater_managed; mod input_buffer; mod output_window; mod stream; pub use inflater_managed::InflaterManaged; pub use stream::Deflate64Decoder; #[derive(Debug, Copy, Clone, Eq, PartialEq)] enum BlockType { Uncompressed = 0, Static = 1, Dynamic = 2, } impl BlockType { pub fn from_int(int: u16) -> Option { match int { 0 => Some(Self::Uncompressed), 1 => Some(Self::Static), 2 => Some(Self::Dynamic), _ => None, } } } #[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd)] enum InflaterState { //ReadingHeader = 0, // Only applies to GZIP ReadingBFinal = 2, // About to read bfinal bit ReadingBType = 3, // About to read blockType bits ReadingNumLitCodes = 4, // About to read # literal codes ReadingNumDistCodes = 5, // About to read # dist codes ReadingNumCodeLengthCodes = 6, // About to read # code length codes ReadingCodeLengthCodes = 7, // In the middle of reading the code length codes ReadingTreeCodesBefore = 8, // In the middle of reading tree codes (loop top) ReadingTreeCodesAfter = 9, // In the middle of reading tree codes (extension; code > 15) DecodeTop = 10, // About to decode a literal (char/match) in a compressed block HaveInitialLength = 11, // Decoding a match, have the literal code (base length) HaveFullLength = 12, // Ditto, now have the full match length (incl. extra length bits) HaveDistCode = 13, // Ditto, now have the distance code also, need extra dist bits /* uncompressed blocks */ UncompressedAligning = 15, UncompressedByte1 = 16, UncompressedByte2 = 17, UncompressedByte3 = 18, UncompressedByte4 = 19, DecodingUncompressed = 20, // These three apply only to GZIP //StartReadingFooter = 21, // (Initialisation for reading footer) //ReadingFooter = 22, //VerifyingFooter = 23, Done = 24, // Finished DataErrored = 100, } impl std::ops::Sub for InflaterState { type Output = u8; fn sub(self, rhs: Self) -> Self::Output { self as u8 - rhs as u8 } } fn array_copy(source: &[T], dst: &mut [T], length: usize) { dst[..length].copy_from_slice(&source[..length]); } fn array_copy1( source: &[T], source_index: usize, dst: &mut [T], dst_index: usize, length: usize, ) { dst[dst_index..][..length].copy_from_slice(&source[source_index..][..length]); } /// A structure containing result of streaming inflate. #[derive(Debug)] pub struct InflateResult { /// 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, /// true if there is error in input buffer pub data_error: bool, } impl InflateResult { /// Creates `InflateResult` with zero bytes consumed and written, and no error. #[allow(clippy::new_without_default)] pub fn new() -> Self { Self { bytes_consumed: 0, bytes_written: 0, data_error: false, } } } #[derive(Debug)] enum InternalErr { DataNeeded, DataError, } deflate64-0.1.8/src/output_window.rs000064400000000000000000000137061046102023000155030ustar 00000000000000use crate::input_buffer::InputBuffer; use std::cmp::min; // With Deflate64 we can have up to a 65536 length as well as up to a 65538 distance. This means we need a Window that is at // least 131074 bytes long so we have space to retrieve up to a full 64kb in look-back and place it in our buffer without // overwriting existing data. OutputWindow requires that the WINDOW_SIZE be an exponent of 2, so we round up to 2^18. const WINDOW_SIZE: usize = 262144; const WINDOW_MASK: usize = 262143; /// /// This class maintains a window for decompressed output. /// We need to keep this because the decompressed information can be /// a literal or a length/distance pair. For length/distance pair, /// we need to look back in the output window and copy bytes from there. /// We use a byte array of WINDOW_SIZE circularly. /// #[derive(Debug)] pub(crate) struct OutputWindow { window: [u8; WINDOW_SIZE], end: usize, bytes_used: usize, } impl OutputWindow { pub fn new() -> Self { Self { window: [0; WINDOW_SIZE], end: 0, bytes_used: 0, } } pub(crate) fn clear_bytes_used(&mut self) { self.bytes_used = 0; } /// Add a byte to output window. pub fn write(&mut self, b: u8) { debug_assert!( self.bytes_used < WINDOW_SIZE, "Can't add byte when window is full!" ); self.window[self.end] = b; self.end += 1; self.end &= WINDOW_MASK; self.bytes_used += 1; } pub fn write_length_distance(&mut self, mut length: usize, distance: usize) { debug_assert!((self.bytes_used + length) <= WINDOW_SIZE, "No Enough space"); // move backwards distance bytes in the output stream, // and copy length bytes from this position to the output stream. self.bytes_used += length; let mut copy_start = (self.end.overflowing_sub(distance).0) & WINDOW_MASK; // start position for coping. let border = WINDOW_SIZE - length; if copy_start <= border && self.end < border { if length <= distance { // src, srcIdx, dst, dstIdx, len // Array.copy(self._window, copy_start, self._window, self._end, length); self.window .copy_within(copy_start..(copy_start + length), self.end); self.end += length; } else { // The referenced string may overlap the current // position; for example, if the last 2 bytes decoded have values // X and Y, a string reference with // adds X,Y,X,Y,X to the output stream. while length > 0 { length -= 1; self.window[self.end] = self.window[copy_start]; self.end += 1; copy_start += 1; } } } else { // copy byte by byte while length > 0 { length -= 1; self.window[self.end] = self.window[copy_start]; self.end += 1; copy_start += 1; self.end &= WINDOW_MASK; copy_start &= WINDOW_MASK; } } } /// /// Copy up to length of bytes from input directly. /// This is used for uncompressed block. /// pub fn copy_from(&mut self, input: &mut InputBuffer<'_>, mut length: usize) -> usize { length = min( min(length, WINDOW_SIZE - self.bytes_used), input.available_bytes(), ); let mut copied: usize; // We might need wrap around to copy all bytes. let tail_len = WINDOW_SIZE - self.end; if length > tail_len { // copy the first part copied = input.copy_to(&mut self.window[self.end..][..tail_len]); if copied == tail_len { // only try to copy the second part if we have enough bytes in input copied += input.copy_to(&mut self.window[..length - tail_len]); } } else { // only one copy is needed if there is no wrap around. copied = input.copy_to(&mut self.window[self.end..][..length]); } self.end = (self.end + copied) & WINDOW_MASK; self.bytes_used += copied; copied } /// Free space in output window. pub fn free_bytes(&self) -> usize { WINDOW_SIZE - self.bytes_used } /// Bytes not consumed in output window. pub fn available_bytes(&self) -> usize { self.bytes_used } /// Copy the decompressed bytes to output buffer. pub fn copy_to(&mut self, mut output: &mut [u8]) -> usize { let copy_end; if output.len() > self.bytes_used { // we can copy all the decompressed bytes out copy_end = self.end; output = &mut output[..self.bytes_used]; } else { #[rustfmt::skip] { copy_end = (self.end .overflowing_sub(self.bytes_used).0 .overflowing_add(output.len()).0) & WINDOW_MASK; }; // copy length of bytes } let copied = output.len(); if output.len() > copy_end { let tail_len = output.len() - copy_end; // this means we need to copy two parts separately // copy the tail_len bytes from the end of the output window output[..tail_len].copy_from_slice(&self.window[WINDOW_SIZE - tail_len..][..tail_len]); output = &mut output[tail_len..][..copy_end]; } output.copy_from_slice(&self.window[copy_end - output.len()..][..output.len()]); self.bytes_used -= copied; //debug_assert!(self.bytes_used >= 0, "check this function and find why we copied more bytes than we have"); copied } } deflate64-0.1.8/src/stream.rs000064400000000000000000000036121046102023000140420ustar 00000000000000// TODO: move this module to deflate64 crate use crate::InflaterManaged; use std::io::{self, BufRead, BufReader, Read}; /// The reader the decompresses deflate64 from another BufRead. pub struct Deflate64Decoder { inner: R, inflater: Box, } impl Deflate64Decoder> { /// Creates Deflate64Decoder with Read pub fn new(inner: R) -> Self { Self::with_buffer(BufReader::new(inner)) } } impl Deflate64Decoder { /// Creates Deflate64Decoder with BufRead pub fn with_buffer(inner: R) -> Self { Self { inner, inflater: Box::new(InflaterManaged::new()), } } } impl Deflate64Decoder { /// Returns inner BufRead instance pub fn into_inner(self) -> R { self.inner } /// Returns reference to innner BufRead instance pub fn get_ref(&self) -> &R { &self.inner } /// Returns mutable reference to innner BufRead instance pub fn get_mut(&mut self) -> &mut R { &mut self.inner } } impl Read for Deflate64Decoder { fn read(&mut self, buf: &mut [u8]) -> io::Result { loop { let input = self.inner.fill_buf()?; let eof = input.is_empty(); let result = self.inflater.inflate(input, buf); self.inner.consume(result.bytes_consumed); if result.data_error { return Err(io::Error::new( io::ErrorKind::InvalidInput, "invalid deflate64", )); } if result.bytes_written == 0 && !eof && !self.inflater.finished() { // if we haven't ready any data and we haven't hit EOF yet, // ask again. We must not return 0 in such case continue; } return Ok(result.bytes_written); } } }