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)(¶ms.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(¶ms.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