1 //! Streaming compression functionality.
2 
3 use std::convert::TryInto;
4 use std::io::{self, Cursor, Seek, SeekFrom, Write};
5 use std::{cmp, mem};
6 
7 use super::super::*;
8 use super::deflate_flags::*;
9 use super::CompressionLevel;
10 use crate::deflate::buffer::{
11     HashBuffers, LocalBuf, LZ_CODE_BUF_SIZE, LZ_DICT_FULL_SIZE, OUT_BUF_SIZE,
12 };
13 use crate::shared::{update_adler32, HUFFMAN_LENGTH_ORDER, MZ_ADLER32_INIT};
14 use crate::DataFormat;
15 
16 const MAX_PROBES_MASK: i32 = 0xFFF;
17 
18 const MAX_SUPPORTED_HUFF_CODESIZE: usize = 32;
19 
20 /// Length code for length values.
21 #[rustfmt::skip]
22 const LEN_SYM: [u16; 256] = [
23     257, 258, 259, 260, 261, 262, 263, 264, 265, 265, 266, 266, 267, 267, 268, 268,
24     269, 269, 269, 269, 270, 270, 270, 270, 271, 271, 271, 271, 272, 272, 272, 272,
25     273, 273, 273, 273, 273, 273, 273, 273, 274, 274, 274, 274, 274, 274, 274, 274,
26     275, 275, 275, 275, 275, 275, 275, 275, 276, 276, 276, 276, 276, 276, 276, 276,
27     277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277,
28     278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278,
29     279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279,
30     280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280,
31     281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281,
32     281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281,
33     282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282,
34     282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282,
35     283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283,
36     283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283,
37     284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284,
38     284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 285
39 ];
40 
41 /// Number of extra bits for length values.
42 #[rustfmt::skip]
43 const LEN_EXTRA: [u8; 256] = [
44     0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1,
45     2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
46     3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
47     3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
48     4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
49     4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
50     4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
51     4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
52     5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
53     5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
54     5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
55     5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
56     5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
57     5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
58     5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
59     5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 0
60 ];
61 
62 /// Distance codes for distances smaller than 512.
63 #[rustfmt::skip]
64 const SMALL_DIST_SYM: [u8; 512] = [
65      0,  1,  2,  3,  4,  4,  5,  5,  6,  6,  6,  6,  7,  7,  7,  7,
66      8,  8,  8,  8,  8,  8,  8,  8,  9,  9,  9,  9,  9,  9,  9,  9,
67     10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
68     11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
69     12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
70     12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
71     13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
72     13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
73     14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
74     14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
75     14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
76     14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
77     15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
78     15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
79     15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
80     15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
81     16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
82     16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
83     16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
84     16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
85     16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
86     16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
87     16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
88     16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
89     17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
90     17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
91     17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
92     17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
93     17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
94     17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
95     17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
96     17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17
97 ];
98 
99 /// Number of extra bits for distances smaller than 512.
100 #[rustfmt::skip]
101 const SMALL_DIST_EXTRA: [u8; 512] = [
102     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,
103     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,
104     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,
105     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,
106     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,
107     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,
108     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,
109     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,
110     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,
111     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,
112     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,
113     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,
114     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,
115     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,
116     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,
117     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
118 ];
119 
120 /// Base values to calculate distances above 512.
121 #[rustfmt::skip]
122 const LARGE_DIST_SYM: [u8; 128] = [
123      0,  0, 18, 19, 20, 20, 21, 21, 22, 22, 22, 22, 23, 23, 23, 23,
124     24, 24, 24, 24, 24, 24, 24, 24, 25, 25, 25, 25, 25, 25, 25, 25,
125     26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
126     27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27,
127     28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28,
128     28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28,
129     29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29,
130     29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29
131 ];
132 
133 /// Number of extra bits distances above 512.
134 #[rustfmt::skip]
135 const LARGE_DIST_EXTRA: [u8; 128] = [
136      0,  0,  8,  8,  9,  9,  9,  9, 10, 10, 10, 10, 10, 10, 10, 10,
137     11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
138     12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
139     12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
140     13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
141     13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
142     13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
143     13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13
144 ];
145 
146 #[rustfmt::skip]
147 const BITMASKS: [u32; 17] = [
148     0x0000, 0x0001, 0x0003, 0x0007, 0x000F, 0x001F, 0x003F, 0x007F, 0x00FF,
149     0x01FF, 0x03FF, 0x07FF, 0x0FFF, 0x1FFF, 0x3FFF, 0x7FFF, 0xFFFF
150 ];
151 
152 /// The maximum number of checks for matches in the hash table the compressor will make for each
153 /// compression level.
154 const NUM_PROBES: [u32; 11] = [0, 1, 6, 32, 16, 32, 128, 256, 512, 768, 1500];
155 
156 #[derive(Copy, Clone)]
157 struct SymFreq {
158     key: u16,
159     sym_index: u16,
160 }
161 
162 pub mod deflate_flags {
163     /// Whether to use a zlib wrapper.
164     pub const TDEFL_WRITE_ZLIB_HEADER: u32 = 0x0000_1000;
165     /// Should we compute the adler32 checksum.
166     pub const TDEFL_COMPUTE_ADLER32: u32 = 0x0000_2000;
167     /// Should we use greedy parsing (as opposed to lazy parsing where look ahead one or more
168     /// bytes to check for better matches.)
169     pub const TDEFL_GREEDY_PARSING_FLAG: u32 = 0x0000_4000;
170     /// Used in miniz to skip zero-initializing hash and dict. We don't do this here, so
171     /// this flag is ignored.
172     pub const TDEFL_NONDETERMINISTIC_PARSING_FLAG: u32 = 0x0000_8000;
173     /// Only look for matches with a distance of 0.
174     pub const TDEFL_RLE_MATCHES: u32 = 0x0001_0000;
175     /// Only use matches that are at least 6 bytes long.
176     pub const TDEFL_FILTER_MATCHES: u32 = 0x0002_0000;
177     /// Force the compressor to only output static blocks. (Blocks using the default huffman codes
178     /// specified in the deflate specification.)
179     pub const TDEFL_FORCE_ALL_STATIC_BLOCKS: u32 = 0x0004_0000;
180     /// Force the compressor to only output raw/uncompressed blocks.
181     pub const TDEFL_FORCE_ALL_RAW_BLOCKS: u32 = 0x0008_0000;
182 }
183 
184 /// Strategy setting for compression.
185 ///
186 /// The non-default settings offer some special-case compression variants.
187 #[repr(i32)]
188 #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
189 pub enum CompressionStrategy {
190     /// Don't use any of the special strategies.
191     Default = 0,
192     /// Only use matches that are at least 5 bytes long.
193     Filtered = 1,
194     /// Don't look for matches, only huffman encode the literals.
195     HuffmanOnly = 2,
196     /// Only look for matches with a distance of 1, i.e do run-length encoding only.
197     RLE = 3,
198     /// Only use static/fixed blocks. (Blocks using the default huffman codes
199     /// specified in the deflate specification.)
200     Fixed = 4,
201 }
202 
203 /// A list of deflate flush types.
204 #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
205 pub enum TDEFLFlush {
206     /// Compress as much as there is space for, and then return
207     /// waiting for more input.
208     None = 0,
209     /// Try to flush the current data and output an empty raw block.
210     Sync = 2,
211     /// Same as sync, but reset the dictionary so that the following data does not depend
212     /// on previous data.
213     Full = 3,
214     /// Try to flush everything and end the stream.
215     Finish = 4,
216 }
217 
218 impl From<MZFlush> for TDEFLFlush {
from(flush: MZFlush) -> Self219     fn from(flush: MZFlush) -> Self {
220         match flush {
221             MZFlush::None => TDEFLFlush::None,
222             MZFlush::Sync => TDEFLFlush::Sync,
223             MZFlush::Full => TDEFLFlush::Full,
224             MZFlush::Finish => TDEFLFlush::Finish,
225             _ => TDEFLFlush::None, // TODO: ??? What to do ???
226         }
227     }
228 }
229 
230 impl TDEFLFlush {
new(flush: i32) -> Result<Self, MZError>231     pub fn new(flush: i32) -> Result<Self, MZError> {
232         match flush {
233             0 => Ok(TDEFLFlush::None),
234             2 => Ok(TDEFLFlush::Sync),
235             3 => Ok(TDEFLFlush::Full),
236             4 => Ok(TDEFLFlush::Finish),
237             _ => Err(MZError::Param),
238         }
239     }
240 }
241 
242 /// Return status codes.
243 #[repr(i32)]
244 #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
245 pub enum TDEFLStatus {
246     BadParam = -2,
247     PutBufFailed = -1,
248     Okay = 0,
249     Done = 1,
250 }
251 
252 const MAX_HUFF_SYMBOLS: usize = 288;
253 /// Size of hash values in the hash chains.
254 const LZ_HASH_BITS: i32 = 15;
255 /// Size of hash chain for fast compression mode.
256 const LEVEL1_HASH_SIZE_MASK: u32 = 4095;
257 /// How many bits to shift when updating the current hash value.
258 const LZ_HASH_SHIFT: i32 = (LZ_HASH_BITS + 2) / 3;
259 /// Size of the chained hash tables.
260 const LZ_HASH_SIZE: usize = 1 << LZ_HASH_BITS;
261 
262 /// The number of huffman tables used by the compressor.
263 /// Literal/length, Distances and Length of the huffman codes for the other two tables.
264 const MAX_HUFF_TABLES: usize = 3;
265 /// Literal/length codes
266 const MAX_HUFF_SYMBOLS_0: usize = 288;
267 /// Distance codes.
268 const MAX_HUFF_SYMBOLS_1: usize = 32;
269 /// Huffman length values.
270 const MAX_HUFF_SYMBOLS_2: usize = 19;
271 /// Size of the chained hash table.
272 pub(crate) const LZ_DICT_SIZE: usize = 32_768;
273 /// Mask used when stepping through the hash chains.
274 const LZ_DICT_SIZE_MASK: u32 = LZ_DICT_SIZE as u32 - 1;
275 /// The minimum length of a match.
276 const MIN_MATCH_LEN: u32 = 3;
277 /// The maximum length of a match.
278 pub(crate) const MAX_MATCH_LEN: usize = 258;
279 
280 const DEFAULT_FLAGS: u32 = NUM_PROBES[4] | TDEFL_WRITE_ZLIB_HEADER;
281 
memset<T: Copy>(slice: &mut [T], val: T)282 fn memset<T: Copy>(slice: &mut [T], val: T) {
283     for x in slice {
284         *x = val
285     }
286 }
287 
288 #[cfg(test)]
289 #[inline]
write_u16_le(val: u16, slice: &mut [u8], pos: usize)290 fn write_u16_le(val: u16, slice: &mut [u8], pos: usize) {
291     slice[pos] = val as u8;
292     slice[pos + 1] = (val >> 8) as u8;
293 }
294 
295 // Read the two bytes starting at pos and interpret them as an u16.
296 #[inline]
read_u16_le(slice: &[u8], pos: usize) -> u16297 fn read_u16_le(slice: &[u8], pos: usize) -> u16 {
298     // The compiler is smart enough to optimize this into an unaligned load.
299     slice[pos] as u16 | ((slice[pos + 1] as u16) << 8)
300 }
301 
302 /// Main compression struct.
303 pub struct CompressorOxide {
304     lz: LZOxide,
305     params: ParamsOxide,
306     huff: Box<HuffmanOxide>,
307     dict: DictOxide,
308 }
309 
310 impl CompressorOxide {
311     /// Create a new `CompressorOxide` with the given flags.
312     ///
313     /// # Notes
314     /// This function may be changed to take different parameters in the future.
new(flags: u32) -> Self315     pub fn new(flags: u32) -> Self {
316         CompressorOxide {
317             lz: LZOxide::new(),
318             params: ParamsOxide::new(flags),
319             /// Put HuffmanOxide on the heap with default trick to avoid
320             /// excessive stack copies.
321             huff: Box::default(),
322             dict: DictOxide::new(flags),
323         }
324     }
325 
326     /// Get the adler32 checksum of the currently encoded data.
adler32(&self) -> u32327     pub fn adler32(&self) -> u32 {
328         self.params.adler32
329     }
330 
331     /// Get the return status of the previous [`compress`](fn.compress.html)
332     /// call with this compressor.
prev_return_status(&self) -> TDEFLStatus333     pub fn prev_return_status(&self) -> TDEFLStatus {
334         self.params.prev_return_status
335     }
336 
337     /// Get the raw compressor flags.
338     ///
339     /// # Notes
340     /// This function may be deprecated or changed in the future to use more rust-style flags.
flags(&self) -> i32341     pub fn flags(&self) -> i32 {
342         self.params.flags as i32
343     }
344 
345     /// Returns whether the compressor is wrapping the data in a zlib format or not.
data_format(&self) -> DataFormat346     pub fn data_format(&self) -> DataFormat {
347         if (self.params.flags & TDEFL_WRITE_ZLIB_HEADER) != 0 {
348             DataFormat::Zlib
349         } else {
350             DataFormat::Raw
351         }
352     }
353 
354     /// Reset the state of the compressor, keeping the same parameters.
355     ///
356     /// This avoids re-allocating data.
reset(&mut self)357     pub fn reset(&mut self) {
358         // LZ buf and huffman has no settings or dynamic memory
359         // that needs to be saved, so we simply replace them.
360         self.lz = LZOxide::new();
361         self.params.reset();
362         *self.huff = HuffmanOxide::default();
363         self.dict.reset();
364     }
365 
366     /// Set the compression level of the compressor.
367     ///
368     /// Using this to change level after compresson has started is supported.
369     /// # Notes
370     /// The compression strategy will be reset to the default one when this is called.
set_compression_level(&mut self, level: CompressionLevel)371     pub fn set_compression_level(&mut self, level: CompressionLevel) {
372         let format = self.data_format();
373         self.set_format_and_level(format, level as u8);
374     }
375 
376     /// Set the compression level of the compressor using an integer value.
377     ///
378     /// Using this to change level after compresson has started is supported.
379     /// # Notes
380     /// The compression strategy will be reset to the default one when this is called.
set_compression_level_raw(&mut self, level: u8)381     pub fn set_compression_level_raw(&mut self, level: u8) {
382         let format = self.data_format();
383         self.set_format_and_level(format, level);
384     }
385 
386     /// Update the compression settings of the compressor.
387     ///
388     /// Changing the `DataFormat` after compression has started will result in
389     /// a corrupted stream.
390     ///
391     /// # Notes
392     /// This function mainly intented for setting the initial settings after e.g creating with
393     /// `default` or after calling `CompressorOxide::reset()`, and behaviour may be changed
394     /// to disallow calling it after starting compression in the future.
set_format_and_level(&mut self, data_format: DataFormat, level: u8)395     pub fn set_format_and_level(&mut self, data_format: DataFormat, level: u8) {
396         let flags = create_comp_flags_from_zip_params(
397             level.into(),
398             data_format.to_window_bits(),
399             CompressionStrategy::Default as i32,
400         );
401         self.params.update_flags(flags);
402         self.dict.update_flags(flags);
403     }
404 }
405 
406 impl Default for CompressorOxide {
407     /// Initialize the compressor with a level of 4, zlib wrapper and
408     /// the default strategy.
409     #[inline(always)]
default() -> Self410     fn default() -> Self {
411         CompressorOxide {
412             lz: LZOxide::new(),
413             params: ParamsOxide::new(DEFAULT_FLAGS),
414             /// Put HuffmanOxide on the heap with default trick to avoid
415             /// excessive stack copies.
416             huff: Box::default(),
417             dict: DictOxide::new(DEFAULT_FLAGS),
418         }
419     }
420 }
421 
422 /// Callback function and user used in `compress_to_output`.
423 pub struct CallbackFunc<'a> {
424     pub put_buf_func: Box<dyn FnMut(&[u8]) -> bool + 'a>,
425 }
426 
427 impl<'a> CallbackFunc<'a> {
flush_output( &mut self, saved_output: SavedOutputBufferOxide, params: &mut ParamsOxide, ) -> i32428     fn flush_output(
429         &mut self,
430         saved_output: SavedOutputBufferOxide,
431         params: &mut ParamsOxide,
432     ) -> i32 {
433         // TODO: As this could be unsafe since
434         // we can't verify the function pointer
435         // this whole function should maybe be unsafe as well.
436         let call_success = (self.put_buf_func)(&params.local_buf.b[0..saved_output.pos as usize]);
437 
438         if !call_success {
439             params.prev_return_status = TDEFLStatus::PutBufFailed;
440             return params.prev_return_status as i32;
441         }
442 
443         params.flush_remaining as i32
444     }
445 }
446 
447 struct CallbackBuf<'a> {
448     pub out_buf: &'a mut [u8],
449 }
450 
451 impl<'a> CallbackBuf<'a> {
flush_output( &mut self, saved_output: SavedOutputBufferOxide, params: &mut ParamsOxide, ) -> i32452     fn flush_output(
453         &mut self,
454         saved_output: SavedOutputBufferOxide,
455         params: &mut ParamsOxide,
456     ) -> i32 {
457         if saved_output.local {
458             let n = cmp::min(
459                 saved_output.pos as usize,
460                 self.out_buf.len() - params.out_buf_ofs,
461             );
462             (&mut self.out_buf[params.out_buf_ofs..params.out_buf_ofs + n])
463                 .copy_from_slice(&params.local_buf.b[..n]);
464 
465             params.out_buf_ofs += n;
466             if saved_output.pos != n as u64 {
467                 params.flush_ofs = n as u32;
468                 params.flush_remaining = (saved_output.pos - n as u64) as u32;
469             }
470         } else {
471             params.out_buf_ofs += saved_output.pos as usize;
472         }
473 
474         params.flush_remaining as i32
475     }
476 }
477 
478 enum CallbackOut<'a> {
479     Func(CallbackFunc<'a>),
480     Buf(CallbackBuf<'a>),
481 }
482 
483 impl<'a> CallbackOut<'a> {
new_output_buffer<'b>( &'b mut self, local_buf: &'b mut [u8], out_buf_ofs: usize, ) -> OutputBufferOxide<'b>484     fn new_output_buffer<'b>(
485         &'b mut self,
486         local_buf: &'b mut [u8],
487         out_buf_ofs: usize,
488     ) -> OutputBufferOxide<'b> {
489         let is_local;
490         let buf_len = OUT_BUF_SIZE - 16;
491         let chosen_buffer = match *self {
492             CallbackOut::Buf(ref mut cb) if cb.out_buf.len() - out_buf_ofs >= OUT_BUF_SIZE => {
493                 is_local = false;
494                 &mut cb.out_buf[out_buf_ofs..out_buf_ofs + buf_len]
495             }
496             _ => {
497                 is_local = true;
498                 &mut local_buf[..buf_len]
499             }
500         };
501 
502         let cursor = Cursor::new(chosen_buffer);
503         OutputBufferOxide {
504             inner: cursor,
505             local: is_local,
506             bit_buffer: 0,
507             bits_in: 0,
508         }
509     }
510 }
511 
512 struct CallbackOxide<'a> {
513     in_buf: Option<&'a [u8]>,
514     in_buf_size: Option<&'a mut usize>,
515     out_buf_size: Option<&'a mut usize>,
516     out: CallbackOut<'a>,
517 }
518 
519 impl<'a> CallbackOxide<'a> {
new_callback_buf(in_buf: &'a [u8], out_buf: &'a mut [u8]) -> Self520     fn new_callback_buf(in_buf: &'a [u8], out_buf: &'a mut [u8]) -> Self {
521         CallbackOxide {
522             in_buf: Some(in_buf),
523             in_buf_size: None,
524             out_buf_size: None,
525             out: CallbackOut::Buf(CallbackBuf { out_buf }),
526         }
527     }
528 
new_callback_func(in_buf: &'a [u8], callback_func: CallbackFunc<'a>) -> Self529     fn new_callback_func(in_buf: &'a [u8], callback_func: CallbackFunc<'a>) -> Self {
530         CallbackOxide {
531             in_buf: Some(in_buf),
532             in_buf_size: None,
533             out_buf_size: None,
534             out: CallbackOut::Func(callback_func),
535         }
536     }
537 
update_size(&mut self, in_size: Option<usize>, out_size: Option<usize>)538     fn update_size(&mut self, in_size: Option<usize>, out_size: Option<usize>) {
539         if let (Some(in_size), Some(size)) = (in_size, self.in_buf_size.as_mut()) {
540             **size = in_size;
541         }
542 
543         if let (Some(out_size), Some(size)) = (out_size, self.out_buf_size.as_mut()) {
544             **size = out_size
545         }
546     }
547 
flush_output( &mut self, saved_output: SavedOutputBufferOxide, params: &mut ParamsOxide, ) -> i32548     fn flush_output(
549         &mut self,
550         saved_output: SavedOutputBufferOxide,
551         params: &mut ParamsOxide,
552     ) -> i32 {
553         if saved_output.pos == 0 {
554             return params.flush_remaining as i32;
555         }
556 
557         self.update_size(Some(params.src_pos), None);
558         match self.out {
559             CallbackOut::Func(ref mut cf) => cf.flush_output(saved_output, params),
560             CallbackOut::Buf(ref mut cb) => cb.flush_output(saved_output, params),
561         }
562     }
563 }
564 
565 struct OutputBufferOxide<'a> {
566     pub inner: Cursor<&'a mut [u8]>,
567     pub local: bool,
568 
569     pub bit_buffer: u32,
570     pub bits_in: u32,
571 }
572 
573 impl<'a> OutputBufferOxide<'a> {
put_bits(&mut self, bits: u32, len: u32)574     fn put_bits(&mut self, bits: u32, len: u32) {
575         assert!(bits <= ((1u32 << len) - 1u32));
576         self.bit_buffer |= bits << self.bits_in;
577         self.bits_in += len;
578         while self.bits_in >= 8 {
579             let pos = self.inner.position();
580             self.inner.get_mut()[pos as usize] = self.bit_buffer as u8;
581             self.inner.set_position(pos + 1);
582             self.bit_buffer >>= 8;
583             self.bits_in -= 8;
584         }
585     }
586 
save(&self) -> SavedOutputBufferOxide587     fn save(&self) -> SavedOutputBufferOxide {
588         SavedOutputBufferOxide {
589             pos: self.inner.position(),
590             bit_buffer: self.bit_buffer,
591             bits_in: self.bits_in,
592             local: self.local,
593         }
594     }
595 
load(&mut self, saved: SavedOutputBufferOxide)596     fn load(&mut self, saved: SavedOutputBufferOxide) {
597         self.inner.set_position(saved.pos);
598         self.bit_buffer = saved.bit_buffer;
599         self.bits_in = saved.bits_in;
600         self.local = saved.local;
601     }
602 
pad_to_bytes(&mut self)603     fn pad_to_bytes(&mut self) {
604         if self.bits_in != 0 {
605             let len = 8 - self.bits_in;
606             self.put_bits(0, len);
607         }
608     }
609 }
610 
611 struct SavedOutputBufferOxide {
612     pub pos: u64,
613     pub bit_buffer: u32,
614     pub bits_in: u32,
615     pub local: bool,
616 }
617 
618 struct BitBuffer {
619     pub bit_buffer: u64,
620     pub bits_in: u32,
621 }
622 
623 impl BitBuffer {
put_fast(&mut self, bits: u64, len: u32)624     fn put_fast(&mut self, bits: u64, len: u32) {
625         self.bit_buffer |= bits << self.bits_in;
626         self.bits_in += len;
627     }
628 
flush(&mut self, output: &mut OutputBufferOxide) -> io::Result<()>629     fn flush(&mut self, output: &mut OutputBufferOxide) -> io::Result<()> {
630         let pos = output.inner.position() as usize;
631         {
632             // isolation to please borrow checker
633             let inner = &mut (*output.inner.get_mut())[pos..pos + 8];
634             let bytes = u64::to_le_bytes(self.bit_buffer);
635             inner.copy_from_slice(&bytes);
636         }
637         output
638             .inner
639             .seek(SeekFrom::Current(i64::from(self.bits_in >> 3)))?;
640         self.bit_buffer >>= self.bits_in & !7;
641         self.bits_in &= 7;
642         Ok(())
643     }
644 }
645 
646 /// A struct containing data about huffman codes and symbol frequencies.
647 ///
648 /// NOTE: Only the literal/lengths have enough symbols to actually use
649 /// the full array. It's unclear why it's defined like this in miniz,
650 /// it could be for cache/alignment reasons.
651 struct HuffmanOxide {
652     /// Number of occurrences of each symbol.
653     pub count: [[u16; MAX_HUFF_SYMBOLS]; MAX_HUFF_TABLES],
654     /// The bits of the huffman code assigned to the symbol
655     pub codes: [[u16; MAX_HUFF_SYMBOLS]; MAX_HUFF_TABLES],
656     /// The length of the huffman code assigned to the symbol.
657     pub code_sizes: [[u8; MAX_HUFF_SYMBOLS]; MAX_HUFF_TABLES],
658 }
659 
660 /// Tables used for literal/lengths in `HuffmanOxide`.
661 const LITLEN_TABLE: usize = 0;
662 /// Tables for distances.
663 const DIST_TABLE: usize = 1;
664 /// Tables for the run-length encoded huffman lenghts for literals/lengths/distances.
665 const HUFF_CODES_TABLE: usize = 2;
666 
667 /// Status of RLE encoding of huffman code lengths.
668 struct RLE {
669     pub z_count: u32,
670     pub repeat_count: u32,
671     pub prev_code_size: u8,
672 }
673 
674 impl RLE {
prev_code_size( &mut self, packed_code_sizes: &mut Cursor<&mut [u8]>, h: &mut HuffmanOxide, ) -> io::Result<()>675     fn prev_code_size(
676         &mut self,
677         packed_code_sizes: &mut Cursor<&mut [u8]>,
678         h: &mut HuffmanOxide,
679     ) -> io::Result<()> {
680         let counts = &mut h.count[HUFF_CODES_TABLE];
681         if self.repeat_count != 0 {
682             if self.repeat_count < 3 {
683                 counts[self.prev_code_size as usize] =
684                     counts[self.prev_code_size as usize].wrapping_add(self.repeat_count as u16);
685                 let code = self.prev_code_size;
686                 packed_code_sizes.write_all(&[code, code, code][..self.repeat_count as usize])?;
687             } else {
688                 counts[16] = counts[16].wrapping_add(1);
689                 packed_code_sizes.write_all(&[16, (self.repeat_count - 3) as u8][..])?;
690             }
691             self.repeat_count = 0;
692         }
693 
694         Ok(())
695     }
696 
zero_code_size( &mut self, packed_code_sizes: &mut Cursor<&mut [u8]>, h: &mut HuffmanOxide, ) -> io::Result<()>697     fn zero_code_size(
698         &mut self,
699         packed_code_sizes: &mut Cursor<&mut [u8]>,
700         h: &mut HuffmanOxide,
701     ) -> io::Result<()> {
702         let counts = &mut h.count[HUFF_CODES_TABLE];
703         if self.z_count != 0 {
704             if self.z_count < 3 {
705                 counts[0] = counts[0].wrapping_add(self.z_count as u16);
706                 packed_code_sizes.write_all(&[0, 0, 0][..self.z_count as usize])?;
707             } else if self.z_count <= 10 {
708                 counts[17] = counts[17].wrapping_add(1);
709                 packed_code_sizes.write_all(&[17, (self.z_count - 3) as u8][..])?;
710             } else {
711                 counts[18] = counts[18].wrapping_add(1);
712                 packed_code_sizes.write_all(&[18, (self.z_count - 11) as u8][..])?;
713             }
714             self.z_count = 0;
715         }
716 
717         Ok(())
718     }
719 }
720 
721 impl Default for HuffmanOxide {
default() -> Self722     fn default() -> Self {
723         HuffmanOxide {
724             count: [[0; MAX_HUFF_SYMBOLS]; MAX_HUFF_TABLES],
725             codes: [[0; MAX_HUFF_SYMBOLS]; MAX_HUFF_TABLES],
726             code_sizes: [[0; MAX_HUFF_SYMBOLS]; MAX_HUFF_TABLES],
727         }
728     }
729 }
730 
731 impl HuffmanOxide {
radix_sort_symbols<'a>( symbols0: &'a mut [SymFreq], symbols1: &'a mut [SymFreq], ) -> &'a mut [SymFreq]732     fn radix_sort_symbols<'a>(
733         symbols0: &'a mut [SymFreq],
734         symbols1: &'a mut [SymFreq],
735     ) -> &'a mut [SymFreq] {
736         let mut hist = [[0; 256]; 2];
737 
738         for freq in symbols0.iter() {
739             hist[0][(freq.key & 0xFF) as usize] += 1;
740             hist[1][((freq.key >> 8) & 0xFF) as usize] += 1;
741         }
742 
743         let mut n_passes = 2;
744         if symbols0.len() == hist[1][0] {
745             n_passes -= 1;
746         }
747 
748         let mut current_symbols = symbols0;
749         let mut new_symbols = symbols1;
750 
751         for pass in 0..n_passes {
752             let mut offsets = [0; 256];
753             let mut offset = 0;
754             for i in 0..256 {
755                 offsets[i] = offset;
756                 offset += hist[pass][i];
757             }
758 
759             for sym in current_symbols.iter() {
760                 let j = ((sym.key >> (pass * 8)) & 0xFF) as usize;
761                 new_symbols[offsets[j]] = *sym;
762                 offsets[j] += 1;
763             }
764 
765             mem::swap(&mut current_symbols, &mut new_symbols);
766         }
767 
768         current_symbols
769     }
770 
calculate_minimum_redundancy(symbols: &mut [SymFreq])771     fn calculate_minimum_redundancy(symbols: &mut [SymFreq]) {
772         match symbols.len() {
773             0 => (),
774             1 => symbols[0].key = 1,
775             n => {
776                 symbols[0].key += symbols[1].key;
777                 let mut root = 0;
778                 let mut leaf = 2;
779                 for next in 1..n - 1 {
780                     if (leaf >= n) || (symbols[root].key < symbols[leaf].key) {
781                         symbols[next].key = symbols[root].key;
782                         symbols[root].key = next as u16;
783                         root += 1;
784                     } else {
785                         symbols[next].key = symbols[leaf].key;
786                         leaf += 1;
787                     }
788 
789                     if (leaf >= n) || (root < next && symbols[root].key < symbols[leaf].key) {
790                         symbols[next].key = symbols[next].key.wrapping_add(symbols[root].key);
791                         symbols[root].key = next as u16;
792                         root += 1;
793                     } else {
794                         symbols[next].key = symbols[next].key.wrapping_add(symbols[leaf].key);
795                         leaf += 1;
796                     }
797                 }
798 
799                 symbols[n - 2].key = 0;
800                 for next in (0..n - 2).rev() {
801                     symbols[next].key = symbols[symbols[next].key as usize].key + 1;
802                 }
803 
804                 let mut avbl = 1;
805                 let mut used = 0;
806                 let mut dpth = 0;
807                 let mut root = (n - 2) as i32;
808                 let mut next = (n - 1) as i32;
809                 while avbl > 0 {
810                     while (root >= 0) && (symbols[root as usize].key == dpth) {
811                         used += 1;
812                         root -= 1;
813                     }
814                     while avbl > used {
815                         symbols[next as usize].key = dpth;
816                         next -= 1;
817                         avbl -= 1;
818                     }
819                     avbl = 2 * used;
820                     dpth += 1;
821                     used = 0;
822                 }
823             }
824         }
825     }
826 
enforce_max_code_size(num_codes: &mut [i32], code_list_len: usize, max_code_size: usize)827     fn enforce_max_code_size(num_codes: &mut [i32], code_list_len: usize, max_code_size: usize) {
828         if code_list_len <= 1 {
829             return;
830         }
831 
832         num_codes[max_code_size] += num_codes[max_code_size + 1..].iter().sum::<i32>();
833         let total = num_codes[1..=max_code_size]
834             .iter()
835             .rev()
836             .enumerate()
837             .fold(0u32, |total, (i, &x)| total + ((x as u32) << i));
838 
839         for _ in (1 << max_code_size)..total {
840             num_codes[max_code_size] -= 1;
841             for i in (1..max_code_size).rev() {
842                 if num_codes[i] != 0 {
843                     num_codes[i] -= 1;
844                     num_codes[i + 1] += 2;
845                     break;
846                 }
847             }
848         }
849     }
850 
optimize_table( &mut self, table_num: usize, table_len: usize, code_size_limit: usize, static_table: bool, )851     fn optimize_table(
852         &mut self,
853         table_num: usize,
854         table_len: usize,
855         code_size_limit: usize,
856         static_table: bool,
857     ) {
858         let mut num_codes = [0i32; MAX_SUPPORTED_HUFF_CODESIZE + 1];
859         let mut next_code = [0u32; MAX_SUPPORTED_HUFF_CODESIZE + 1];
860 
861         if static_table {
862             for &code_size in &self.code_sizes[table_num][..table_len] {
863                 num_codes[code_size as usize] += 1;
864             }
865         } else {
866             let mut symbols0 = [SymFreq {
867                 key: 0,
868                 sym_index: 0,
869             }; MAX_HUFF_SYMBOLS];
870             let mut symbols1 = [SymFreq {
871                 key: 0,
872                 sym_index: 0,
873             }; MAX_HUFF_SYMBOLS];
874 
875             let mut num_used_symbols = 0;
876             for i in 0..table_len {
877                 if self.count[table_num][i] != 0 {
878                     symbols0[num_used_symbols] = SymFreq {
879                         key: self.count[table_num][i],
880                         sym_index: i as u16,
881                     };
882                     num_used_symbols += 1;
883                 }
884             }
885 
886             let symbols = Self::radix_sort_symbols(
887                 &mut symbols0[..num_used_symbols],
888                 &mut symbols1[..num_used_symbols],
889             );
890             Self::calculate_minimum_redundancy(symbols);
891 
892             for symbol in symbols.iter() {
893                 num_codes[symbol.key as usize] += 1;
894             }
895 
896             Self::enforce_max_code_size(&mut num_codes, num_used_symbols, code_size_limit);
897 
898             memset(&mut self.code_sizes[table_num][..], 0);
899             memset(&mut self.codes[table_num][..], 0);
900 
901             let mut last = num_used_symbols;
902             for i in 1..=code_size_limit {
903                 let first = last - num_codes[i] as usize;
904                 for symbol in &symbols[first..last] {
905                     self.code_sizes[table_num][symbol.sym_index as usize] = i as u8;
906                 }
907                 last = first;
908             }
909         }
910 
911         let mut j = 0;
912         next_code[1] = 0;
913         for i in 2..=code_size_limit {
914             j = (j + num_codes[i - 1]) << 1;
915             next_code[i] = j as u32;
916         }
917 
918         for (&code_size, huff_code) in self.code_sizes[table_num]
919             .iter()
920             .take(table_len)
921             .zip(self.codes[table_num].iter_mut().take(table_len))
922         {
923             if code_size == 0 {
924                 continue;
925             }
926 
927             let mut code = next_code[code_size as usize];
928             next_code[code_size as usize] += 1;
929 
930             let mut rev_code = 0;
931             for _ in 0..code_size {
932                 rev_code = (rev_code << 1) | (code & 1);
933                 code >>= 1;
934             }
935             *huff_code = rev_code as u16;
936         }
937     }
938 
start_static_block(&mut self, output: &mut OutputBufferOxide)939     fn start_static_block(&mut self, output: &mut OutputBufferOxide) {
940         memset(&mut self.code_sizes[LITLEN_TABLE][0..144], 8);
941         memset(&mut self.code_sizes[LITLEN_TABLE][144..256], 9);
942         memset(&mut self.code_sizes[LITLEN_TABLE][256..280], 7);
943         memset(&mut self.code_sizes[LITLEN_TABLE][280..288], 8);
944 
945         memset(&mut self.code_sizes[DIST_TABLE][..32], 5);
946 
947         self.optimize_table(LITLEN_TABLE, 288, 15, true);
948         self.optimize_table(DIST_TABLE, 32, 15, true);
949 
950         output.put_bits(0b01, 2)
951     }
952 
start_dynamic_block(&mut self, output: &mut OutputBufferOxide) -> io::Result<()>953     fn start_dynamic_block(&mut self, output: &mut OutputBufferOxide) -> io::Result<()> {
954         // There will always be one, and only one end of block code.
955         self.count[0][256] = 1;
956 
957         self.optimize_table(0, MAX_HUFF_SYMBOLS_0, 15, false);
958         self.optimize_table(1, MAX_HUFF_SYMBOLS_1, 15, false);
959 
960         let num_lit_codes = 286
961             - &self.code_sizes[0][257..286]
962                 .iter()
963                 .rev()
964                 .take_while(|&x| *x == 0)
965                 .count();
966 
967         let num_dist_codes = 30
968             - &self.code_sizes[1][1..30]
969                 .iter()
970                 .rev()
971                 .take_while(|&x| *x == 0)
972                 .count();
973 
974         let mut code_sizes_to_pack = [0u8; MAX_HUFF_SYMBOLS_0 + MAX_HUFF_SYMBOLS_1];
975         let mut packed_code_sizes = [0u8; MAX_HUFF_SYMBOLS_0 + MAX_HUFF_SYMBOLS_1];
976 
977         let total_code_sizes_to_pack = num_lit_codes + num_dist_codes;
978 
979         code_sizes_to_pack[..num_lit_codes].copy_from_slice(&self.code_sizes[0][..num_lit_codes]);
980 
981         code_sizes_to_pack[num_lit_codes..total_code_sizes_to_pack]
982             .copy_from_slice(&self.code_sizes[1][..num_dist_codes]);
983 
984         let mut rle = RLE {
985             z_count: 0,
986             repeat_count: 0,
987             prev_code_size: 0xFF,
988         };
989 
990         memset(&mut self.count[HUFF_CODES_TABLE][..MAX_HUFF_SYMBOLS_2], 0);
991 
992         let mut packed_code_sizes_cursor = Cursor::new(&mut packed_code_sizes[..]);
993         for &code_size in &code_sizes_to_pack[..total_code_sizes_to_pack] {
994             if code_size == 0 {
995                 rle.prev_code_size(&mut packed_code_sizes_cursor, self)?;
996                 rle.z_count += 1;
997                 if rle.z_count == 138 {
998                     rle.zero_code_size(&mut packed_code_sizes_cursor, self)?;
999                 }
1000             } else {
1001                 rle.zero_code_size(&mut packed_code_sizes_cursor, self)?;
1002                 if code_size != rle.prev_code_size {
1003                     rle.prev_code_size(&mut packed_code_sizes_cursor, self)?;
1004                     self.count[HUFF_CODES_TABLE][code_size as usize] =
1005                         self.count[HUFF_CODES_TABLE][code_size as usize].wrapping_add(1);
1006                     packed_code_sizes_cursor.write_all(&[code_size][..])?;
1007                 } else {
1008                     rle.repeat_count += 1;
1009                     if rle.repeat_count == 6 {
1010                         rle.prev_code_size(&mut packed_code_sizes_cursor, self)?;
1011                     }
1012                 }
1013             }
1014             rle.prev_code_size = code_size;
1015         }
1016 
1017         if rle.repeat_count != 0 {
1018             rle.prev_code_size(&mut packed_code_sizes_cursor, self)?;
1019         } else {
1020             rle.zero_code_size(&mut packed_code_sizes_cursor, self)?;
1021         }
1022 
1023         self.optimize_table(2, MAX_HUFF_SYMBOLS_2, 7, false);
1024 
1025         output.put_bits(2, 2);
1026 
1027         output.put_bits((num_lit_codes - 257) as u32, 5);
1028         output.put_bits((num_dist_codes - 1) as u32, 5);
1029 
1030         let mut num_bit_lengths = 18
1031             - HUFFMAN_LENGTH_ORDER
1032                 .iter()
1033                 .rev()
1034                 .take_while(|&swizzle| self.code_sizes[HUFF_CODES_TABLE][*swizzle as usize] == 0)
1035                 .count();
1036 
1037         num_bit_lengths = cmp::max(4, num_bit_lengths + 1);
1038         output.put_bits(num_bit_lengths as u32 - 4, 4);
1039         for &swizzle in &HUFFMAN_LENGTH_ORDER[..num_bit_lengths] {
1040             output.put_bits(
1041                 u32::from(self.code_sizes[HUFF_CODES_TABLE][swizzle as usize]),
1042                 3,
1043             );
1044         }
1045 
1046         let mut packed_code_size_index = 0 as usize;
1047         let packed_code_sizes = packed_code_sizes_cursor.get_ref();
1048         while packed_code_size_index < packed_code_sizes_cursor.position() as usize {
1049             let code = packed_code_sizes[packed_code_size_index] as usize;
1050             packed_code_size_index += 1;
1051             assert!(code < MAX_HUFF_SYMBOLS_2);
1052             output.put_bits(
1053                 u32::from(self.codes[HUFF_CODES_TABLE][code]),
1054                 u32::from(self.code_sizes[HUFF_CODES_TABLE][code]),
1055             );
1056             if code >= 16 {
1057                 output.put_bits(
1058                     u32::from(packed_code_sizes[packed_code_size_index]),
1059                     [2, 3, 7][code - 16],
1060                 );
1061                 packed_code_size_index += 1;
1062             }
1063         }
1064 
1065         Ok(())
1066     }
1067 }
1068 
1069 struct DictOxide {
1070     /// The maximum number of checks in the hash chain, for the initial,
1071     /// and the lazy match respectively.
1072     pub max_probes: [u32; 2],
1073     /// Buffer of input data.
1074     /// Padded with 1 byte to simplify matching code in `compress_fast`.
1075     pub b: Box<HashBuffers>,
1076 
1077     pub code_buf_dict_pos: u32,
1078     pub lookahead_size: u32,
1079     pub lookahead_pos: u32,
1080     pub size: u32,
1081 }
1082 
probes_from_flags(flags: u32) -> [u32; 2]1083 fn probes_from_flags(flags: u32) -> [u32; 2] {
1084     [
1085         1 + ((flags & 0xFFF) + 2) / 3,
1086         1 + (((flags & 0xFFF) >> 2) + 2) / 3,
1087     ]
1088 }
1089 
1090 impl DictOxide {
new(flags: u32) -> Self1091     fn new(flags: u32) -> Self {
1092         DictOxide {
1093             max_probes: probes_from_flags(flags),
1094             b: Box::default(),
1095             code_buf_dict_pos: 0,
1096             lookahead_size: 0,
1097             lookahead_pos: 0,
1098             size: 0,
1099         }
1100     }
1101 
update_flags(&mut self, flags: u32)1102     fn update_flags(&mut self, flags: u32) {
1103         self.max_probes = probes_from_flags(flags);
1104     }
1105 
reset(&mut self)1106     fn reset(&mut self) {
1107         self.b.reset();
1108         self.code_buf_dict_pos = 0;
1109         self.lookahead_size = 0;
1110         self.lookahead_pos = 0;
1111         self.size = 0;
1112     }
1113 
1114     /// Do an unaligned read of the data at `pos` in the dictionary and treat it as if it was of
1115     /// type T.
1116     #[inline]
read_unaligned_u32(&self, pos: u32) -> u321117     fn read_unaligned_u32(&self, pos: u32) -> u32 {
1118         // Masking the value here helps avoid bounds checks.
1119         let pos = (pos & LZ_DICT_SIZE_MASK) as usize;
1120         let end = pos + 4;
1121         // Somehow this assertion makes things faster.
1122         assert!(end < LZ_DICT_FULL_SIZE);
1123 
1124         let bytes: [u8; 4] = self.b.dict[pos..end].try_into().unwrap();
1125         u32::from_le_bytes(bytes)
1126     }
1127 
1128     /// Do an unaligned read of the data at `pos` in the dictionary and treat it as if it was of
1129     /// type T.
1130     #[inline]
read_unaligned_u64(&self, pos: u32) -> u641131     fn read_unaligned_u64(&self, pos: u32) -> u64 {
1132         let pos = pos as usize;
1133         let bytes: [u8; 8] = self.b.dict[pos..pos + 8].try_into().unwrap();
1134         u64::from_le_bytes(bytes)
1135     }
1136 
1137     /// Do an unaligned read of the data at `pos` in the dictionary and treat it as if it was of
1138     /// type T.
1139     #[inline]
read_as_u16(&self, pos: usize) -> u161140     fn read_as_u16(&self, pos: usize) -> u16 {
1141         read_u16_le(&self.b.dict[..], pos)
1142     }
1143 
1144     /// Try to find a match for the data at lookahead_pos in the dictionary that is
1145     /// longer than `match_len`.
1146     /// Returns a tuple containing (match_distance, match_length). Will be equal to the input
1147     /// values if no better matches were found.
find_match( &self, lookahead_pos: u32, max_dist: u32, max_match_len: u32, mut match_dist: u32, mut match_len: u32, ) -> (u32, u32)1148     fn find_match(
1149         &self,
1150         lookahead_pos: u32,
1151         max_dist: u32,
1152         max_match_len: u32,
1153         mut match_dist: u32,
1154         mut match_len: u32,
1155     ) -> (u32, u32) {
1156         // Clamp the match len and max_match_len to be valid. (It should be when this is called, but
1157         // do it for now just in case for safety reasons.)
1158         // This should normally end up as at worst conditional moves,
1159         // so it shouldn't slow us down much.
1160         // TODO: Statically verify these so we don't need to do this.
1161         let max_match_len = cmp::min(MAX_MATCH_LEN as u32, max_match_len);
1162         match_len = cmp::max(match_len, 1);
1163 
1164         let pos = lookahead_pos & LZ_DICT_SIZE_MASK;
1165         let mut probe_pos = pos;
1166         // Number of probes into the hash chains.
1167         let mut num_probes_left = self.max_probes[(match_len >= 32) as usize];
1168 
1169         // If we already have a match of the full length don't bother searching for another one.
1170         if max_match_len <= match_len {
1171             return (match_dist, match_len);
1172         }
1173 
1174         // Read the last byte of the current match, and the next one, used to compare matches.
1175         let mut c01: u16 = self.read_as_u16(pos as usize + match_len as usize - 1);
1176         // Read the two bytes at the end position of the current match.
1177         let s01: u16 = self.read_as_u16(pos as usize);
1178 
1179         'outer: loop {
1180             let mut dist;
1181             'found: loop {
1182                 num_probes_left -= 1;
1183                 if num_probes_left == 0 {
1184                     // We have done as many probes in the hash chain as the current compression
1185                     // settings allow, so return the best match we found, if any.
1186                     return (match_dist, match_len);
1187                 }
1188 
1189                 for _ in 0..3 {
1190                     let next_probe_pos = u32::from(self.b.next[probe_pos as usize]);
1191 
1192                     dist = (lookahead_pos - next_probe_pos) & 0xFFFF;
1193                     if next_probe_pos == 0 || dist > max_dist {
1194                         // We reached the end of the hash chain, or the next value is further away
1195                         // than the maximum allowed distance, so return the best match we found, if
1196                         // any.
1197                         return (match_dist, match_len);
1198                     }
1199 
1200                     // Mask the position value to get the position in the hash chain of the next
1201                     // position to match against.
1202                     probe_pos = next_probe_pos & LZ_DICT_SIZE_MASK;
1203 
1204                     if self.read_as_u16((probe_pos + match_len - 1) as usize) == c01 {
1205                         break 'found;
1206                     }
1207                 }
1208             }
1209 
1210             if dist == 0 {
1211                 // We've looked through the whole match range, so return the best match we
1212                 // found.
1213                 return (match_dist, match_len);
1214             }
1215 
1216             // Check if the two first bytes match.
1217             if self.read_as_u16(probe_pos as usize) != s01 {
1218                 continue;
1219             }
1220 
1221             let mut p = pos + 2;
1222             let mut q = probe_pos + 2;
1223             // The first two bytes matched, so check the full length of the match.
1224             for _ in 0..32 {
1225                 let p_data: u64 = self.read_unaligned_u64(p);
1226                 let q_data: u64 = self.read_unaligned_u64(q);
1227                 // Compare of 8 bytes at a time by using unaligned loads of 64-bit integers.
1228                 let xor_data = p_data ^ q_data;
1229                 if xor_data == 0 {
1230                     p += 8;
1231                     q += 8;
1232                 } else {
1233                     // If not all of the last 8 bytes matched, check how may of them did.
1234                     let trailing = xor_data.trailing_zeros();
1235 
1236                     let probe_len = p - pos + (trailing >> 3);
1237                     if probe_len > match_len {
1238                         match_dist = dist;
1239                         match_len = cmp::min(max_match_len, probe_len);
1240                         if match_len == max_match_len {
1241                             // We found a match that had the maximum allowed length,
1242                             // so there is now point searching further.
1243                             return (match_dist, match_len);
1244                         }
1245                         // We found a better match, so save the last two bytes for further match
1246                         // comparisons.
1247                         c01 = self.read_as_u16((pos + match_len - 1) as usize)
1248                     }
1249                     continue 'outer;
1250                 }
1251             }
1252 
1253             return (dist, cmp::min(max_match_len, MAX_MATCH_LEN as u32));
1254         }
1255     }
1256 }
1257 
1258 struct ParamsOxide {
1259     pub flags: u32,
1260     pub greedy_parsing: bool,
1261     pub block_index: u32,
1262 
1263     pub saved_match_dist: u32,
1264     pub saved_match_len: u32,
1265     pub saved_lit: u8,
1266 
1267     pub flush: TDEFLFlush,
1268     pub flush_ofs: u32,
1269     pub flush_remaining: u32,
1270     pub finished: bool,
1271 
1272     pub adler32: u32,
1273 
1274     pub src_pos: usize,
1275 
1276     pub out_buf_ofs: usize,
1277     pub prev_return_status: TDEFLStatus,
1278 
1279     pub saved_bit_buffer: u32,
1280     pub saved_bits_in: u32,
1281 
1282     pub local_buf: Box<LocalBuf>,
1283 }
1284 
1285 impl ParamsOxide {
new(flags: u32) -> Self1286     fn new(flags: u32) -> Self {
1287         ParamsOxide {
1288             flags,
1289             greedy_parsing: flags & TDEFL_GREEDY_PARSING_FLAG != 0,
1290             block_index: 0,
1291             saved_match_dist: 0,
1292             saved_match_len: 0,
1293             saved_lit: 0,
1294             flush: TDEFLFlush::None,
1295             flush_ofs: 0,
1296             flush_remaining: 0,
1297             finished: false,
1298             adler32: MZ_ADLER32_INIT,
1299             src_pos: 0,
1300             out_buf_ofs: 0,
1301             prev_return_status: TDEFLStatus::Okay,
1302             saved_bit_buffer: 0,
1303             saved_bits_in: 0,
1304             local_buf: Box::default(),
1305         }
1306     }
1307 
update_flags(&mut self, flags: u32)1308     fn update_flags(&mut self, flags: u32) {
1309         self.flags = flags;
1310         self.greedy_parsing = self.flags & TDEFL_GREEDY_PARSING_FLAG != 0;
1311     }
1312 
1313     /// Reset state, saving settings.
reset(&mut self)1314     fn reset(&mut self) {
1315         self.block_index = 0;
1316         self.saved_match_len = 0;
1317         self.saved_match_dist = 0;
1318         self.saved_lit = 0;
1319         self.flush = TDEFLFlush::None;
1320         self.flush_ofs = 0;
1321         self.flush_remaining = 0;
1322         self.finished = false;
1323         self.adler32 = MZ_ADLER32_INIT;
1324         self.src_pos = 0;
1325         self.out_buf_ofs = 0;
1326         self.prev_return_status = TDEFLStatus::Okay;
1327         self.saved_bit_buffer = 0;
1328         self.saved_bits_in = 0;
1329         self.local_buf.b = [0; OUT_BUF_SIZE];
1330     }
1331 }
1332 
1333 struct LZOxide {
1334     pub codes: [u8; LZ_CODE_BUF_SIZE],
1335     pub code_position: usize,
1336     pub flag_position: usize,
1337 
1338     pub total_bytes: u32,
1339     pub num_flags_left: u32,
1340 }
1341 
1342 impl LZOxide {
new() -> Self1343     fn new() -> Self {
1344         LZOxide {
1345             codes: [0; LZ_CODE_BUF_SIZE],
1346             code_position: 1,
1347             flag_position: 0,
1348             total_bytes: 0,
1349             num_flags_left: 8,
1350         }
1351     }
1352 
write_code(&mut self, val: u8)1353     fn write_code(&mut self, val: u8) {
1354         self.codes[self.code_position] = val;
1355         self.code_position += 1;
1356     }
1357 
init_flag(&mut self)1358     fn init_flag(&mut self) {
1359         if self.num_flags_left == 8 {
1360             *self.get_flag() = 0;
1361             self.code_position -= 1;
1362         } else {
1363             *self.get_flag() >>= self.num_flags_left;
1364         }
1365     }
1366 
get_flag(&mut self) -> &mut u81367     fn get_flag(&mut self) -> &mut u8 {
1368         &mut self.codes[self.flag_position]
1369     }
1370 
plant_flag(&mut self)1371     fn plant_flag(&mut self) {
1372         self.flag_position = self.code_position;
1373         self.code_position += 1;
1374     }
1375 
consume_flag(&mut self)1376     fn consume_flag(&mut self) {
1377         self.num_flags_left -= 1;
1378         if self.num_flags_left == 0 {
1379             self.num_flags_left = 8;
1380             self.plant_flag();
1381         }
1382     }
1383 }
1384 
compress_lz_codes( huff: &HuffmanOxide, output: &mut OutputBufferOxide, lz_code_buf: &[u8], ) -> io::Result<bool>1385 fn compress_lz_codes(
1386     huff: &HuffmanOxide,
1387     output: &mut OutputBufferOxide,
1388     lz_code_buf: &[u8],
1389 ) -> io::Result<bool> {
1390     let mut flags = 1;
1391     let mut bb = BitBuffer {
1392         bit_buffer: u64::from(output.bit_buffer),
1393         bits_in: output.bits_in,
1394     };
1395 
1396     let mut i: usize = 0;
1397     while i < lz_code_buf.len() {
1398         if flags == 1 {
1399             flags = u32::from(lz_code_buf[i]) | 0x100;
1400             i += 1;
1401         }
1402 
1403         // The lz code was a length code
1404         if flags & 1 == 1 {
1405             flags >>= 1;
1406 
1407             let sym;
1408             let num_extra_bits;
1409 
1410             let match_len = lz_code_buf[i] as usize;
1411 
1412             let match_dist = read_u16_le(lz_code_buf, i + 1);
1413 
1414             i += 3;
1415 
1416             debug_assert!(huff.code_sizes[0][LEN_SYM[match_len] as usize] != 0);
1417             bb.put_fast(
1418                 u64::from(huff.codes[0][LEN_SYM[match_len] as usize]),
1419                 u32::from(huff.code_sizes[0][LEN_SYM[match_len] as usize]),
1420             );
1421             bb.put_fast(
1422                 match_len as u64 & u64::from(BITMASKS[LEN_EXTRA[match_len] as usize]),
1423                 u32::from(LEN_EXTRA[match_len]),
1424             );
1425 
1426             if match_dist < 512 {
1427                 sym = SMALL_DIST_SYM[match_dist as usize] as usize;
1428                 num_extra_bits = SMALL_DIST_EXTRA[match_dist as usize] as usize;
1429             } else {
1430                 sym = LARGE_DIST_SYM[(match_dist >> 8) as usize] as usize;
1431                 num_extra_bits = LARGE_DIST_EXTRA[(match_dist >> 8) as usize] as usize;
1432             }
1433 
1434             debug_assert!(huff.code_sizes[1][sym] != 0);
1435             bb.put_fast(
1436                 u64::from(huff.codes[1][sym]),
1437                 u32::from(huff.code_sizes[1][sym]),
1438             );
1439             bb.put_fast(
1440                 u64::from(match_dist) & u64::from(BITMASKS[num_extra_bits as usize]),
1441                 num_extra_bits as u32,
1442             );
1443         } else {
1444             // The lz code was a literal
1445             for _ in 0..3 {
1446                 flags >>= 1;
1447                 let lit = lz_code_buf[i];
1448                 i += 1;
1449 
1450                 debug_assert!(huff.code_sizes[0][lit as usize] != 0);
1451                 bb.put_fast(
1452                     u64::from(huff.codes[0][lit as usize]),
1453                     u32::from(huff.code_sizes[0][lit as usize]),
1454                 );
1455 
1456                 if flags & 1 == 1 || i >= lz_code_buf.len() {
1457                     break;
1458                 }
1459             }
1460         }
1461 
1462         bb.flush(output)?;
1463     }
1464 
1465     output.bits_in = 0;
1466     output.bit_buffer = 0;
1467     while bb.bits_in != 0 {
1468         let n = cmp::min(bb.bits_in, 16);
1469         output.put_bits(bb.bit_buffer as u32 & BITMASKS[n as usize], n);
1470         bb.bit_buffer >>= n;
1471         bb.bits_in -= n;
1472     }
1473 
1474     // Output the end of block symbol.
1475     output.put_bits(
1476         u32::from(huff.codes[0][256]),
1477         u32::from(huff.code_sizes[0][256]),
1478     );
1479 
1480     Ok(true)
1481 }
1482 
compress_block( huff: &mut HuffmanOxide, output: &mut OutputBufferOxide, lz: &LZOxide, static_block: bool, ) -> io::Result<bool>1483 fn compress_block(
1484     huff: &mut HuffmanOxide,
1485     output: &mut OutputBufferOxide,
1486     lz: &LZOxide,
1487     static_block: bool,
1488 ) -> io::Result<bool> {
1489     if static_block {
1490         huff.start_static_block(output);
1491     } else {
1492         huff.start_dynamic_block(output)?;
1493     }
1494 
1495     compress_lz_codes(huff, output, &lz.codes[..lz.code_position])
1496 }
1497 
flush_block( d: &mut CompressorOxide, callback: &mut CallbackOxide, flush: TDEFLFlush, ) -> io::Result<i32>1498 fn flush_block(
1499     d: &mut CompressorOxide,
1500     callback: &mut CallbackOxide,
1501     flush: TDEFLFlush,
1502 ) -> io::Result<i32> {
1503     let mut saved_buffer;
1504     {
1505         let mut output = callback
1506             .out
1507             .new_output_buffer(&mut d.params.local_buf.b, d.params.out_buf_ofs);
1508         output.bit_buffer = d.params.saved_bit_buffer;
1509         output.bits_in = d.params.saved_bits_in;
1510 
1511         let use_raw_block = (d.params.flags & TDEFL_FORCE_ALL_RAW_BLOCKS != 0)
1512             && (d.dict.lookahead_pos - d.dict.code_buf_dict_pos) <= d.dict.size;
1513 
1514         assert!(d.params.flush_remaining == 0);
1515         d.params.flush_ofs = 0;
1516         d.params.flush_remaining = 0;
1517 
1518         d.lz.init_flag();
1519 
1520         // If we are at the start of the stream, write the zlib header if requested.
1521         if d.params.flags & TDEFL_WRITE_ZLIB_HEADER != 0 && d.params.block_index == 0 {
1522             output.put_bits(0x78, 8);
1523             output.put_bits(0x01, 8);
1524         }
1525 
1526         // Output the block header.
1527         output.put_bits((flush == TDEFLFlush::Finish) as u32, 1);
1528 
1529         saved_buffer = output.save();
1530 
1531         let comp_success = if !use_raw_block {
1532             let use_static =
1533                 (d.params.flags & TDEFL_FORCE_ALL_STATIC_BLOCKS != 0) || (d.lz.total_bytes < 48);
1534             compress_block(&mut d.huff, &mut output, &d.lz, use_static)?
1535         } else {
1536             false
1537         };
1538 
1539         // If we failed to compress anything and the output would take up more space than the output
1540         // data, output a stored block instead, which has at most 5 bytes of overhead.
1541         // We only use some simple heuristics for now.
1542         // A stored block will have an overhead of at least 4 bytes containing the block length
1543         // but usually more due to the length parameters having to start at a byte boundary and thus
1544         // requiring up to 5 bytes of padding.
1545         // As a static block will have an overhead of at most 1 bit per byte
1546         // (as literals are either 8 or 9 bytes), a raw block will
1547         // never take up less space if the number of input bytes are less than 32.
1548         let expanded = (d.lz.total_bytes > 32)
1549             && (output.inner.position() - saved_buffer.pos + 1 >= u64::from(d.lz.total_bytes))
1550             && (d.dict.lookahead_pos - d.dict.code_buf_dict_pos <= d.dict.size);
1551 
1552         if use_raw_block || expanded {
1553             output.load(saved_buffer);
1554 
1555             // Block header.
1556             output.put_bits(0, 2);
1557 
1558             // Block length has to start on a byte boundary, s opad.
1559             output.pad_to_bytes();
1560 
1561             // Block length and ones complement of block length.
1562             output.put_bits(d.lz.total_bytes & 0xFFFF, 16);
1563             output.put_bits(!d.lz.total_bytes & 0xFFFF, 16);
1564 
1565             // Write the actual bytes.
1566             for i in 0..d.lz.total_bytes {
1567                 let pos = (d.dict.code_buf_dict_pos + i) & LZ_DICT_SIZE_MASK;
1568                 output.put_bits(u32::from(d.dict.b.dict[pos as usize]), 8);
1569             }
1570         } else if !comp_success {
1571             output.load(saved_buffer);
1572             compress_block(&mut d.huff, &mut output, &d.lz, true)?;
1573         }
1574 
1575         if flush != TDEFLFlush::None {
1576             if flush == TDEFLFlush::Finish {
1577                 output.pad_to_bytes();
1578                 if d.params.flags & TDEFL_WRITE_ZLIB_HEADER != 0 {
1579                     let mut adler = d.params.adler32;
1580                     for _ in 0..4 {
1581                         output.put_bits((adler >> 24) & 0xFF, 8);
1582                         adler <<= 8;
1583                     }
1584                 }
1585             } else {
1586                 // Sync or Full flush.
1587                 // Output an empty raw block.
1588                 output.put_bits(0, 3);
1589                 output.pad_to_bytes();
1590                 output.put_bits(0, 16);
1591                 output.put_bits(0xFFFF, 16);
1592             }
1593         }
1594 
1595         memset(&mut d.huff.count[0][..MAX_HUFF_SYMBOLS_0], 0);
1596         memset(&mut d.huff.count[1][..MAX_HUFF_SYMBOLS_1], 0);
1597 
1598         d.lz.code_position = 1;
1599         d.lz.flag_position = 0;
1600         d.lz.num_flags_left = 8;
1601         d.dict.code_buf_dict_pos += d.lz.total_bytes;
1602         d.lz.total_bytes = 0;
1603         d.params.block_index += 1;
1604 
1605         saved_buffer = output.save();
1606 
1607         d.params.saved_bit_buffer = saved_buffer.bit_buffer;
1608         d.params.saved_bits_in = saved_buffer.bits_in;
1609     }
1610 
1611     Ok(callback.flush_output(saved_buffer, &mut d.params))
1612 }
1613 
record_literal(h: &mut HuffmanOxide, lz: &mut LZOxide, lit: u8)1614 fn record_literal(h: &mut HuffmanOxide, lz: &mut LZOxide, lit: u8) {
1615     lz.total_bytes += 1;
1616     lz.write_code(lit);
1617 
1618     *lz.get_flag() >>= 1;
1619     lz.consume_flag();
1620 
1621     h.count[0][lit as usize] += 1;
1622 }
1623 
record_match(h: &mut HuffmanOxide, lz: &mut LZOxide, mut match_len: u32, mut match_dist: u32)1624 fn record_match(h: &mut HuffmanOxide, lz: &mut LZOxide, mut match_len: u32, mut match_dist: u32) {
1625     assert!(match_len >= MIN_MATCH_LEN);
1626     assert!(match_dist >= 1);
1627     assert!(match_dist as usize <= LZ_DICT_SIZE);
1628 
1629     lz.total_bytes += match_len;
1630     match_dist -= 1;
1631     match_len -= MIN_MATCH_LEN;
1632     lz.write_code(match_len as u8);
1633     lz.write_code(match_dist as u8);
1634     lz.write_code((match_dist >> 8) as u8);
1635 
1636     *lz.get_flag() >>= 1;
1637     *lz.get_flag() |= 0x80;
1638     lz.consume_flag();
1639 
1640     let symbol = if match_dist < 512 {
1641         SMALL_DIST_SYM[match_dist as usize]
1642     } else {
1643         LARGE_DIST_SYM[((match_dist >> 8) & 127) as usize]
1644     } as usize;
1645     h.count[1][symbol] += 1;
1646     h.count[0][LEN_SYM[match_len as usize] as usize] += 1;
1647 }
1648 
compress_normal(d: &mut CompressorOxide, callback: &mut CallbackOxide) -> bool1649 fn compress_normal(d: &mut CompressorOxide, callback: &mut CallbackOxide) -> bool {
1650     let mut src_pos = d.params.src_pos;
1651     let in_buf = match callback.in_buf {
1652         None => return true,
1653         Some(in_buf) => in_buf,
1654     };
1655 
1656     let mut lookahead_size = d.dict.lookahead_size;
1657     let mut lookahead_pos = d.dict.lookahead_pos;
1658     let mut saved_lit = d.params.saved_lit;
1659     let mut saved_match_dist = d.params.saved_match_dist;
1660     let mut saved_match_len = d.params.saved_match_len;
1661 
1662     while src_pos < in_buf.len() || (d.params.flush != TDEFLFlush::None && lookahead_size != 0) {
1663         let src_buf_left = in_buf.len() - src_pos;
1664         let num_bytes_to_process = cmp::min(src_buf_left, MAX_MATCH_LEN - lookahead_size as usize);
1665 
1666         if lookahead_size + d.dict.size >= MIN_MATCH_LEN - 1 && num_bytes_to_process > 0 {
1667             let dictb = &mut d.dict.b;
1668 
1669             let mut dst_pos = (lookahead_pos + lookahead_size) & LZ_DICT_SIZE_MASK;
1670             let mut ins_pos = lookahead_pos + lookahead_size - 2;
1671             let mut hash = (u32::from(dictb.dict[(ins_pos & LZ_DICT_SIZE_MASK) as usize])
1672                 << LZ_HASH_SHIFT)
1673                 ^ u32::from(dictb.dict[((ins_pos + 1) & LZ_DICT_SIZE_MASK) as usize]);
1674 
1675             lookahead_size += num_bytes_to_process as u32;
1676             for &c in &in_buf[src_pos..src_pos + num_bytes_to_process] {
1677                 dictb.dict[dst_pos as usize] = c;
1678                 if (dst_pos as usize) < MAX_MATCH_LEN - 1 {
1679                     dictb.dict[LZ_DICT_SIZE + dst_pos as usize] = c;
1680                 }
1681 
1682                 hash = ((hash << LZ_HASH_SHIFT) ^ u32::from(c)) & (LZ_HASH_SIZE as u32 - 1);
1683                 dictb.next[(ins_pos & LZ_DICT_SIZE_MASK) as usize] = dictb.hash[hash as usize];
1684 
1685                 dictb.hash[hash as usize] = ins_pos as u16;
1686                 dst_pos = (dst_pos + 1) & LZ_DICT_SIZE_MASK;
1687                 ins_pos += 1;
1688             }
1689             src_pos += num_bytes_to_process;
1690         } else {
1691             let dictb = &mut d.dict.b;
1692             for &c in &in_buf[src_pos..src_pos + num_bytes_to_process] {
1693                 let dst_pos = (lookahead_pos + lookahead_size) & LZ_DICT_SIZE_MASK;
1694                 dictb.dict[dst_pos as usize] = c;
1695                 if (dst_pos as usize) < MAX_MATCH_LEN - 1 {
1696                     dictb.dict[LZ_DICT_SIZE + dst_pos as usize] = c;
1697                 }
1698 
1699                 lookahead_size += 1;
1700                 if lookahead_size + d.dict.size >= MIN_MATCH_LEN {
1701                     let ins_pos = lookahead_pos + lookahead_size - 3;
1702                     let hash = ((u32::from(dictb.dict[(ins_pos & LZ_DICT_SIZE_MASK) as usize])
1703                         << (LZ_HASH_SHIFT * 2))
1704                         ^ ((u32::from(dictb.dict[((ins_pos + 1) & LZ_DICT_SIZE_MASK) as usize])
1705                             << LZ_HASH_SHIFT)
1706                             ^ u32::from(c)))
1707                         & (LZ_HASH_SIZE as u32 - 1);
1708 
1709                     dictb.next[(ins_pos & LZ_DICT_SIZE_MASK) as usize] = dictb.hash[hash as usize];
1710                     dictb.hash[hash as usize] = ins_pos as u16;
1711                 }
1712             }
1713 
1714             src_pos += num_bytes_to_process;
1715         }
1716 
1717         d.dict.size = cmp::min(LZ_DICT_SIZE as u32 - lookahead_size, d.dict.size);
1718         if d.params.flush == TDEFLFlush::None && (lookahead_size as usize) < MAX_MATCH_LEN {
1719             break;
1720         }
1721 
1722         let mut len_to_move = 1;
1723         let mut cur_match_dist = 0;
1724         let mut cur_match_len = if saved_match_len != 0 {
1725             saved_match_len
1726         } else {
1727             MIN_MATCH_LEN - 1
1728         };
1729         let cur_pos = lookahead_pos & LZ_DICT_SIZE_MASK;
1730         if d.params.flags & (TDEFL_RLE_MATCHES | TDEFL_FORCE_ALL_RAW_BLOCKS) != 0 {
1731             if d.dict.size != 0 && d.params.flags & TDEFL_FORCE_ALL_RAW_BLOCKS == 0 {
1732                 let c = d.dict.b.dict[((cur_pos.wrapping_sub(1)) & LZ_DICT_SIZE_MASK) as usize];
1733                 cur_match_len = d.dict.b.dict[cur_pos as usize..(cur_pos + lookahead_size) as usize]
1734                     .iter()
1735                     .take_while(|&x| *x == c)
1736                     .count() as u32;
1737                 if cur_match_len < MIN_MATCH_LEN {
1738                     cur_match_len = 0
1739                 } else {
1740                     cur_match_dist = 1
1741                 }
1742             }
1743         } else {
1744             let dist_len = d.dict.find_match(
1745                 lookahead_pos,
1746                 d.dict.size,
1747                 lookahead_size,
1748                 cur_match_dist,
1749                 cur_match_len,
1750             );
1751             cur_match_dist = dist_len.0;
1752             cur_match_len = dist_len.1;
1753         }
1754 
1755         let far_and_small = cur_match_len == MIN_MATCH_LEN && cur_match_dist >= 8 * 1024;
1756         let filter_small = d.params.flags & TDEFL_FILTER_MATCHES != 0 && cur_match_len <= 5;
1757         if far_and_small || filter_small || cur_pos == cur_match_dist {
1758             cur_match_dist = 0;
1759             cur_match_len = 0;
1760         }
1761 
1762         if saved_match_len != 0 {
1763             if cur_match_len > saved_match_len {
1764                 record_literal(&mut d.huff, &mut d.lz, saved_lit);
1765                 if cur_match_len >= 128 {
1766                     record_match(&mut d.huff, &mut d.lz, cur_match_len, cur_match_dist);
1767                     saved_match_len = 0;
1768                     len_to_move = cur_match_len;
1769                 } else {
1770                     saved_lit = d.dict.b.dict[cur_pos as usize];
1771                     saved_match_dist = cur_match_dist;
1772                     saved_match_len = cur_match_len;
1773                 }
1774             } else {
1775                 record_match(&mut d.huff, &mut d.lz, saved_match_len, saved_match_dist);
1776                 len_to_move = saved_match_len - 1;
1777                 saved_match_len = 0;
1778             }
1779         } else if cur_match_dist == 0 {
1780             record_literal(
1781                 &mut d.huff,
1782                 &mut d.lz,
1783                 d.dict.b.dict[cmp::min(cur_pos as usize, d.dict.b.dict.len() - 1)],
1784             );
1785         } else if d.params.greedy_parsing
1786             || (d.params.flags & TDEFL_RLE_MATCHES != 0)
1787             || cur_match_len >= 128
1788         {
1789             // If we are using lazy matching, check for matches at the next byte if the current
1790             // match was shorter than 128 bytes.
1791             record_match(&mut d.huff, &mut d.lz, cur_match_len, cur_match_dist);
1792             len_to_move = cur_match_len;
1793         } else {
1794             saved_lit = d.dict.b.dict[cmp::min(cur_pos as usize, d.dict.b.dict.len() - 1)];
1795             saved_match_dist = cur_match_dist;
1796             saved_match_len = cur_match_len;
1797         }
1798 
1799         lookahead_pos += len_to_move;
1800         assert!(lookahead_size >= len_to_move);
1801         lookahead_size -= len_to_move;
1802         d.dict.size = cmp::min(d.dict.size + len_to_move, LZ_DICT_SIZE as u32);
1803 
1804         let lz_buf_tight = d.lz.code_position > LZ_CODE_BUF_SIZE - 8;
1805         let raw = d.params.flags & TDEFL_FORCE_ALL_RAW_BLOCKS != 0;
1806         let fat = ((d.lz.code_position * 115) >> 7) >= d.lz.total_bytes as usize;
1807         let fat_or_raw = (d.lz.total_bytes > 31 * 1024) && (fat || raw);
1808 
1809         if lz_buf_tight || fat_or_raw {
1810             d.params.src_pos = src_pos;
1811             // These values are used in flush_block, so we need to write them back here.
1812             d.dict.lookahead_size = lookahead_size;
1813             d.dict.lookahead_pos = lookahead_pos;
1814 
1815             let n = flush_block(d, callback, TDEFLFlush::None)
1816                 .unwrap_or(TDEFLStatus::PutBufFailed as i32);
1817             if n != 0 {
1818                 d.params.saved_lit = saved_lit;
1819                 d.params.saved_match_dist = saved_match_dist;
1820                 d.params.saved_match_len = saved_match_len;
1821                 return n > 0;
1822             }
1823         }
1824     }
1825 
1826     d.params.src_pos = src_pos;
1827     d.dict.lookahead_size = lookahead_size;
1828     d.dict.lookahead_pos = lookahead_pos;
1829     d.params.saved_lit = saved_lit;
1830     d.params.saved_match_dist = saved_match_dist;
1831     d.params.saved_match_len = saved_match_len;
1832     true
1833 }
1834 
1835 const COMP_FAST_LOOKAHEAD_SIZE: u32 = 4096;
1836 
compress_fast(d: &mut CompressorOxide, callback: &mut CallbackOxide) -> bool1837 fn compress_fast(d: &mut CompressorOxide, callback: &mut CallbackOxide) -> bool {
1838     let mut src_pos = d.params.src_pos;
1839     let mut lookahead_size = d.dict.lookahead_size;
1840     let mut lookahead_pos = d.dict.lookahead_pos;
1841 
1842     let mut cur_pos = lookahead_pos & LZ_DICT_SIZE_MASK;
1843     let in_buf = match callback.in_buf {
1844         None => return true,
1845         Some(in_buf) => in_buf,
1846     };
1847 
1848     debug_assert!(d.lz.code_position < LZ_CODE_BUF_SIZE - 2);
1849 
1850     while src_pos < in_buf.len() || (d.params.flush != TDEFLFlush::None && lookahead_size > 0) {
1851         let mut dst_pos = ((lookahead_pos + lookahead_size) & LZ_DICT_SIZE_MASK) as usize;
1852         let mut num_bytes_to_process = cmp::min(
1853             in_buf.len() - src_pos,
1854             (COMP_FAST_LOOKAHEAD_SIZE - lookahead_size) as usize,
1855         );
1856         lookahead_size += num_bytes_to_process as u32;
1857 
1858         while num_bytes_to_process != 0 {
1859             let n = cmp::min(LZ_DICT_SIZE - dst_pos, num_bytes_to_process);
1860             d.dict.b.dict[dst_pos..dst_pos + n].copy_from_slice(&in_buf[src_pos..src_pos + n]);
1861 
1862             if dst_pos < MAX_MATCH_LEN - 1 {
1863                 let m = cmp::min(n, MAX_MATCH_LEN - 1 - dst_pos);
1864                 d.dict.b.dict[dst_pos + LZ_DICT_SIZE..dst_pos + LZ_DICT_SIZE + m]
1865                     .copy_from_slice(&in_buf[src_pos..src_pos + m]);
1866             }
1867 
1868             src_pos += n;
1869             dst_pos = (dst_pos + n) & LZ_DICT_SIZE_MASK as usize;
1870             num_bytes_to_process -= n;
1871         }
1872 
1873         d.dict.size = cmp::min(LZ_DICT_SIZE as u32 - lookahead_size, d.dict.size);
1874         if d.params.flush == TDEFLFlush::None && lookahead_size < COMP_FAST_LOOKAHEAD_SIZE {
1875             break;
1876         }
1877 
1878         while lookahead_size >= 4 {
1879             let mut cur_match_len = 1;
1880 
1881             let first_trigram = d.dict.read_unaligned_u32(cur_pos) & 0xFF_FFFF;
1882 
1883             let hash = (first_trigram ^ (first_trigram >> (24 - (LZ_HASH_BITS - 8))))
1884                 & LEVEL1_HASH_SIZE_MASK;
1885 
1886             let mut probe_pos = u32::from(d.dict.b.hash[hash as usize]);
1887             d.dict.b.hash[hash as usize] = lookahead_pos as u16;
1888 
1889             let mut cur_match_dist = (lookahead_pos - probe_pos) as u16;
1890             if u32::from(cur_match_dist) <= d.dict.size {
1891                 probe_pos &= LZ_DICT_SIZE_MASK;
1892 
1893                 let trigram = d.dict.read_unaligned_u32(probe_pos) & 0xFF_FFFF;
1894 
1895                 if first_trigram == trigram {
1896                     // Trigram was tested, so we can start with "+ 3" displacement.
1897                     let mut p = cur_pos + 3;
1898                     let mut q = probe_pos + 3;
1899                     cur_match_len = 'find_match: loop {
1900                         for _ in 0..32 {
1901                             let p_data: u64 = d.dict.read_unaligned_u64(p);
1902                             let q_data: u64 = d.dict.read_unaligned_u64(q);
1903                             let xor_data = p_data ^ q_data;
1904                             if xor_data == 0 {
1905                                 p += 8;
1906                                 q += 8;
1907                             } else {
1908                                 let trailing = xor_data.trailing_zeros();
1909                                 break 'find_match p as u32 - cur_pos + (trailing >> 3);
1910                             }
1911                         }
1912 
1913                         break 'find_match if cur_match_dist == 0 {
1914                             0
1915                         } else {
1916                             MAX_MATCH_LEN as u32
1917                         };
1918                     };
1919 
1920                     if cur_match_len < MIN_MATCH_LEN
1921                         || (cur_match_len == MIN_MATCH_LEN && cur_match_dist >= 8 * 1024)
1922                     {
1923                         let lit = first_trigram as u8;
1924                         cur_match_len = 1;
1925                         d.lz.write_code(lit);
1926                         *d.lz.get_flag() >>= 1;
1927                         d.huff.count[0][lit as usize] += 1;
1928                     } else {
1929                         // Limit the match to the length of the lookahead so we don't create a match
1930                         // that ends after the end of the input data.
1931                         cur_match_len = cmp::min(cur_match_len, lookahead_size);
1932                         debug_assert!(cur_match_len >= MIN_MATCH_LEN);
1933                         debug_assert!(cur_match_dist >= 1);
1934                         debug_assert!(cur_match_dist as usize <= LZ_DICT_SIZE);
1935                         cur_match_dist -= 1;
1936 
1937                         d.lz.write_code((cur_match_len - MIN_MATCH_LEN) as u8);
1938                         d.lz.write_code(cur_match_dist as u8);
1939                         d.lz.write_code((cur_match_dist >> 8) as u8);
1940 
1941                         *d.lz.get_flag() >>= 1;
1942                         *d.lz.get_flag() |= 0x80;
1943                         if cur_match_dist < 512 {
1944                             d.huff.count[1][SMALL_DIST_SYM[cur_match_dist as usize] as usize] += 1;
1945                         } else {
1946                             d.huff.count[1]
1947                                 [LARGE_DIST_SYM[(cur_match_dist >> 8) as usize] as usize] += 1;
1948                         }
1949 
1950                         d.huff.count[0]
1951                             [LEN_SYM[(cur_match_len - MIN_MATCH_LEN) as usize] as usize] += 1;
1952                     }
1953                 } else {
1954                     d.lz.write_code(first_trigram as u8);
1955                     *d.lz.get_flag() >>= 1;
1956                     d.huff.count[0][first_trigram as u8 as usize] += 1;
1957                 }
1958 
1959                 d.lz.consume_flag();
1960                 d.lz.total_bytes += cur_match_len;
1961                 lookahead_pos += cur_match_len;
1962                 d.dict.size = cmp::min(d.dict.size + cur_match_len, LZ_DICT_SIZE as u32);
1963                 cur_pos = (cur_pos + cur_match_len) & LZ_DICT_SIZE_MASK;
1964                 lookahead_size -= cur_match_len;
1965 
1966                 if d.lz.code_position > LZ_CODE_BUF_SIZE - 8 {
1967                     // These values are used in flush_block, so we need to write them back here.
1968                     d.dict.lookahead_size = lookahead_size;
1969                     d.dict.lookahead_pos = lookahead_pos;
1970 
1971                     let n = match flush_block(d, callback, TDEFLFlush::None) {
1972                         Err(_) => {
1973                             d.params.src_pos = src_pos;
1974                             d.params.prev_return_status = TDEFLStatus::PutBufFailed;
1975                             return false;
1976                         }
1977                         Ok(status) => status,
1978                     };
1979                     if n != 0 {
1980                         d.params.src_pos = src_pos;
1981                         return n > 0;
1982                     }
1983                     debug_assert!(d.lz.code_position < LZ_CODE_BUF_SIZE - 2);
1984 
1985                     lookahead_size = d.dict.lookahead_size;
1986                     lookahead_pos = d.dict.lookahead_pos;
1987                 }
1988             }
1989         }
1990 
1991         while lookahead_size != 0 {
1992             let lit = d.dict.b.dict[cur_pos as usize];
1993             d.lz.total_bytes += 1;
1994             d.lz.write_code(lit);
1995             *d.lz.get_flag() >>= 1;
1996             d.lz.consume_flag();
1997 
1998             d.huff.count[0][lit as usize] += 1;
1999             lookahead_pos += 1;
2000             d.dict.size = cmp::min(d.dict.size + 1, LZ_DICT_SIZE as u32);
2001             cur_pos = (cur_pos + 1) & LZ_DICT_SIZE_MASK;
2002             lookahead_size -= 1;
2003 
2004             if d.lz.code_position > LZ_CODE_BUF_SIZE - 8 {
2005                 // These values are used in flush_block, so we need to write them back here.
2006                 d.dict.lookahead_size = lookahead_size;
2007                 d.dict.lookahead_pos = lookahead_pos;
2008 
2009                 let n = match flush_block(d, callback, TDEFLFlush::None) {
2010                     Err(_) => {
2011                         d.params.prev_return_status = TDEFLStatus::PutBufFailed;
2012                         d.params.src_pos = src_pos;
2013                         return false;
2014                     }
2015                     Ok(status) => status,
2016                 };
2017                 if n != 0 {
2018                     d.params.src_pos = src_pos;
2019                     return n > 0;
2020                 }
2021 
2022                 lookahead_size = d.dict.lookahead_size;
2023                 lookahead_pos = d.dict.lookahead_pos;
2024             }
2025         }
2026     }
2027 
2028     d.params.src_pos = src_pos;
2029     d.dict.lookahead_size = lookahead_size;
2030     d.dict.lookahead_pos = lookahead_pos;
2031     true
2032 }
2033 
flush_output_buffer(c: &mut CallbackOxide, p: &mut ParamsOxide) -> (TDEFLStatus, usize, usize)2034 fn flush_output_buffer(c: &mut CallbackOxide, p: &mut ParamsOxide) -> (TDEFLStatus, usize, usize) {
2035     let mut res = (TDEFLStatus::Okay, p.src_pos, 0);
2036     if let CallbackOut::Buf(ref mut cb) = c.out {
2037         let n = cmp::min(cb.out_buf.len() - p.out_buf_ofs, p.flush_remaining as usize);
2038         if n != 0 {
2039             (&mut cb.out_buf[p.out_buf_ofs..p.out_buf_ofs + n])
2040                 .copy_from_slice(&p.local_buf.b[p.flush_ofs as usize..p.flush_ofs as usize + n]);
2041         }
2042         p.flush_ofs += n as u32;
2043         p.flush_remaining -= n as u32;
2044         p.out_buf_ofs += n;
2045         res.2 = p.out_buf_ofs;
2046     }
2047 
2048     if p.finished && p.flush_remaining == 0 {
2049         res.0 = TDEFLStatus::Done
2050     }
2051     res
2052 }
2053 
2054 /// Main compression function. Tries to compress as much as possible from `in_buf` and
2055 /// puts compressed output into `out_buf`.
2056 ///
2057 /// The value of `flush` determines if the compressor should attempt to flush all output
2058 /// and alternatively try to finish the stream.
2059 /// Should be `TDeflflush::Finish` on the final call.
2060 ///
2061 /// # Returns
2062 /// Returns a tuple containing the current status of the compressor, the current position
2063 /// in the input buffer and the current position in the output buffer.
compress( d: &mut CompressorOxide, in_buf: &[u8], out_buf: &mut [u8], flush: TDEFLFlush, ) -> (TDEFLStatus, usize, usize)2064 pub fn compress(
2065     d: &mut CompressorOxide,
2066     in_buf: &[u8],
2067     out_buf: &mut [u8],
2068     flush: TDEFLFlush,
2069 ) -> (TDEFLStatus, usize, usize) {
2070     compress_inner(
2071         d,
2072         &mut CallbackOxide::new_callback_buf(in_buf, out_buf),
2073         flush,
2074     )
2075 }
2076 
2077 /// Main compression function. Callbacks output.
2078 ///
2079 /// # Returns
2080 /// Returns a tuple containing the current status of the compressor, the current position
2081 /// in the input buffer.
2082 ///
2083 /// The caller is responsible for ensuring the `CallbackFunc` struct will not cause undefined
2084 /// behaviour.
compress_to_output( d: &mut CompressorOxide, in_buf: &[u8], flush: TDEFLFlush, callback_func: impl FnMut(&[u8]) -> bool, ) -> (TDEFLStatus, usize)2085 pub fn compress_to_output(
2086     d: &mut CompressorOxide,
2087     in_buf: &[u8],
2088     flush: TDEFLFlush,
2089     callback_func: impl FnMut(&[u8]) -> bool,
2090 ) -> (TDEFLStatus, usize) {
2091     let res = compress_inner(
2092         d,
2093         &mut CallbackOxide::new_callback_func(
2094             in_buf,
2095             CallbackFunc {
2096                 put_buf_func: Box::new(callback_func),
2097             },
2098         ),
2099         flush,
2100     );
2101 
2102     (res.0, res.1)
2103 }
2104 
compress_inner( d: &mut CompressorOxide, callback: &mut CallbackOxide, flush: TDEFLFlush, ) -> (TDEFLStatus, usize, usize)2105 fn compress_inner(
2106     d: &mut CompressorOxide,
2107     callback: &mut CallbackOxide,
2108     flush: TDEFLFlush,
2109 ) -> (TDEFLStatus, usize, usize) {
2110     d.params.out_buf_ofs = 0;
2111     d.params.src_pos = 0;
2112 
2113     let prev_ok = d.params.prev_return_status == TDEFLStatus::Okay;
2114     let flush_finish_once = d.params.flush != TDEFLFlush::Finish || flush == TDEFLFlush::Finish;
2115 
2116     d.params.flush = flush;
2117     if !prev_ok || !flush_finish_once {
2118         d.params.prev_return_status = TDEFLStatus::BadParam;
2119         return (d.params.prev_return_status, 0, 0);
2120     }
2121 
2122     if d.params.flush_remaining != 0 || d.params.finished {
2123         let res = flush_output_buffer(callback, &mut d.params);
2124         d.params.prev_return_status = res.0;
2125         return res;
2126     }
2127 
2128     let one_probe = d.params.flags & MAX_PROBES_MASK as u32 == 1;
2129     let greedy = d.params.flags & TDEFL_GREEDY_PARSING_FLAG != 0;
2130     let filter_or_rle_or_raw = d.params.flags
2131         & (TDEFL_FILTER_MATCHES | TDEFL_FORCE_ALL_RAW_BLOCKS | TDEFL_RLE_MATCHES)
2132         != 0;
2133 
2134     let compress_success = if one_probe && greedy && !filter_or_rle_or_raw {
2135         compress_fast(d, callback)
2136     } else {
2137         compress_normal(d, callback)
2138     };
2139 
2140     if !compress_success {
2141         return (
2142             d.params.prev_return_status,
2143             d.params.src_pos,
2144             d.params.out_buf_ofs,
2145         );
2146     }
2147 
2148     if let Some(in_buf) = callback.in_buf {
2149         if d.params.flags & (TDEFL_WRITE_ZLIB_HEADER | TDEFL_COMPUTE_ADLER32) != 0 {
2150             d.params.adler32 = update_adler32(d.params.adler32, &in_buf[..d.params.src_pos]);
2151         }
2152     }
2153 
2154     let flush_none = d.params.flush == TDEFLFlush::None;
2155     let in_left = callback.in_buf.map_or(0, |buf| buf.len()) - d.params.src_pos;
2156     let remaining = in_left != 0 || d.params.flush_remaining != 0;
2157     if !flush_none && d.dict.lookahead_size == 0 && !remaining {
2158         let flush = d.params.flush;
2159         match flush_block(d, callback, flush) {
2160             Err(_) => {
2161                 d.params.prev_return_status = TDEFLStatus::PutBufFailed;
2162                 return (
2163                     d.params.prev_return_status,
2164                     d.params.src_pos,
2165                     d.params.out_buf_ofs,
2166                 );
2167             }
2168             Ok(x) if x < 0 => {
2169                 return (
2170                     d.params.prev_return_status,
2171                     d.params.src_pos,
2172                     d.params.out_buf_ofs,
2173                 )
2174             }
2175             _ => {
2176                 d.params.finished = d.params.flush == TDEFLFlush::Finish;
2177                 if d.params.flush == TDEFLFlush::Full {
2178                     memset(&mut d.dict.b.hash[..], 0);
2179                     memset(&mut d.dict.b.next[..], 0);
2180                     d.dict.size = 0;
2181                 }
2182             }
2183         }
2184     }
2185 
2186     let res = flush_output_buffer(callback, &mut d.params);
2187     d.params.prev_return_status = res.0;
2188 
2189     res
2190 }
2191 
2192 /// Create a set of compression flags using parameters used by zlib and other compressors.
2193 /// Mainly intented for use with transition from c libraries as it deals with raw integers.
2194 ///
2195 /// # Parameters
2196 /// `level` determines compression level. Clamped to maximum of 10. Negative values result in
2197 /// `Compressionlevel::DefaultLevel`.
2198 /// `window_bits`: Above 0, wraps the stream in a zlib wrapper, 0 or negative for a raw deflate
2199 /// stream.
2200 /// `strategy`: Sets the strategy if this conforms to any of the values in `CompressionStrategy`.
2201 ///
2202 /// # Notes
2203 /// This function may be removed or moved to the `miniz_oxide_c_api` in the future.
create_comp_flags_from_zip_params(level: i32, window_bits: i32, strategy: i32) -> u322204 pub fn create_comp_flags_from_zip_params(level: i32, window_bits: i32, strategy: i32) -> u32 {
2205     let num_probes = (if level >= 0 {
2206         cmp::min(10, level)
2207     } else {
2208         CompressionLevel::DefaultLevel as i32
2209     }) as usize;
2210     let greedy = if level <= 3 {
2211         TDEFL_GREEDY_PARSING_FLAG
2212     } else {
2213         0
2214     };
2215     let mut comp_flags = NUM_PROBES[num_probes] | greedy;
2216 
2217     if window_bits > 0 {
2218         comp_flags |= TDEFL_WRITE_ZLIB_HEADER;
2219     }
2220 
2221     if level == 0 {
2222         comp_flags |= TDEFL_FORCE_ALL_RAW_BLOCKS;
2223     } else if strategy == CompressionStrategy::Filtered as i32 {
2224         comp_flags |= TDEFL_FILTER_MATCHES;
2225     } else if strategy == CompressionStrategy::HuffmanOnly as i32 {
2226         comp_flags &= !MAX_PROBES_MASK as u32;
2227     } else if strategy == CompressionStrategy::Fixed as i32 {
2228         comp_flags |= TDEFL_FORCE_ALL_STATIC_BLOCKS;
2229     } else if strategy == CompressionStrategy::RLE as i32 {
2230         comp_flags |= TDEFL_RLE_MATCHES;
2231     }
2232 
2233     comp_flags
2234 }
2235 
2236 #[cfg(test)]
2237 mod test {
2238     use super::{
2239         compress_to_output, create_comp_flags_from_zip_params, read_u16_le, write_u16_le,
2240         CompressionStrategy, CompressorOxide, TDEFLFlush, TDEFLStatus, DEFAULT_FLAGS,
2241         MZ_DEFAULT_WINDOW_BITS,
2242     };
2243     use crate::inflate::decompress_to_vec;
2244 
2245     #[test]
u16_to_slice()2246     fn u16_to_slice() {
2247         let mut slice = [0, 0];
2248         write_u16_le(2000, &mut slice, 0);
2249         assert_eq!(slice, [208, 7]);
2250     }
2251 
2252     #[test]
u16_from_slice()2253     fn u16_from_slice() {
2254         let mut slice = [208, 7];
2255         assert_eq!(read_u16_le(&mut slice, 0), 2000);
2256     }
2257 
2258     #[test]
compress_output()2259     fn compress_output() {
2260         assert_eq!(
2261             DEFAULT_FLAGS,
2262             create_comp_flags_from_zip_params(
2263                 4,
2264                 MZ_DEFAULT_WINDOW_BITS,
2265                 CompressionStrategy::Default as i32
2266             )
2267         );
2268 
2269         let slice = [
2270             1, 2, 3, 4, 1, 2, 3, 1, 2, 3, 1, 2, 6, 1, 2, 3, 1, 2, 3, 2, 3, 1, 2, 3,
2271         ];
2272         let mut encoded = vec![];
2273         let flags = create_comp_flags_from_zip_params(6, 0, 0);
2274         let mut d = CompressorOxide::new(flags);
2275         let (status, in_consumed) =
2276             compress_to_output(&mut d, &slice, TDEFLFlush::Finish, |out: &[u8]| {
2277                 encoded.extend_from_slice(out);
2278                 true
2279             });
2280 
2281         assert_eq!(status, TDEFLStatus::Done);
2282         assert_eq!(in_consumed, slice.len());
2283 
2284         let decoded = decompress_to_vec(&encoded[..]).unwrap();
2285         assert_eq!(&decoded[..], &slice[..]);
2286     }
2287 }
2288