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