Skip to content

Commit c5f8f76

Browse files
committed
fix(infalte): use smaller types in inflate struct, split up huffman table arrays to make struct smaller, make zlib level 0 if using rle, other minor tweaks
1 parent 02a8857 commit c5f8f76

File tree

2 files changed

+73
-54
lines changed

2 files changed

+73
-54
lines changed

miniz_oxide/src/deflate/core.rs

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -306,15 +306,15 @@ pub(crate) const MAX_MATCH_LEN: usize = 258;
306306
const DEFAULT_FLAGS: u32 = NUM_PROBES[4] | TDEFL_WRITE_ZLIB_HEADER;
307307

308308
mod zlib {
309-
use super::TDEFL_RLE_MATCHES;
309+
use super::{TDEFL_FORCE_ALL_RAW_BLOCKS, TDEFL_RLE_MATCHES};
310310

311311
const DEFAULT_CM: u8 = 8;
312312
const DEFAULT_CINFO: u8 = 7 << 4;
313313
const _DEFAULT_FDICT: u8 = 0;
314314
const DEFAULT_CMF: u8 = DEFAULT_CM | DEFAULT_CINFO;
315315
// CMF used for RLE (technically it uses a window size of 0 but the lowest that can
316316
// be specified in the header corresponds to a window size of 1 << (0 + 8) aka 256.
317-
const MIN_CMF: u8 = DEFAULT_CM | 0;
317+
const MIN_CMF: u8 = DEFAULT_CM; // | 0
318318
/// The 16-bit value consisting of CMF and FLG must be divisible by this to be valid.
319319
const FCHECK_DIVISOR: u8 = 31;
320320

@@ -352,8 +352,10 @@ mod zlib {
352352
}
353353

354354
const fn cmf_from_flags(flags: u32) -> u8 {
355-
if flags & TDEFL_RLE_MATCHES == 0 {
355+
if (flags & TDEFL_RLE_MATCHES == 0) && (flags & TDEFL_FORCE_ALL_RAW_BLOCKS == 0) {
356356
DEFAULT_CMF
357+
// If we are using RLE encoding or no compression the window bits can be set as the
358+
// minimum.
357359
} else {
358360
MIN_CMF
359361
}

miniz_oxide/src/inflate/core.rs

Lines changed: 68 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,6 @@ pub const TINFL_LZ_DICT_SIZE: usize = 32_768;
1414
/// A struct containing huffman code lengths and the huffman code tree used by the decompressor.
1515
#[derive(Clone)]
1616
struct HuffmanTable {
17-
/// Length of the code at each index.
18-
pub code_size: [u8; MAX_HUFF_SYMBOLS_0],
1917
/// Fast lookup table for shorter huffman codes.
2018
///
2119
/// See `HuffmanTable::fast_lookup`.
@@ -30,7 +28,6 @@ struct HuffmanTable {
3028
impl HuffmanTable {
3129
const fn new() -> HuffmanTable {
3230
HuffmanTable {
33-
code_size: [0; MAX_HUFF_SYMBOLS_0],
3431
look_up: [0; FAST_LOOKUP_SIZE as usize],
3532
tree: [0; MAX_HUFF_TREE_SIZE],
3633
}
@@ -81,11 +78,10 @@ impl HuffmanTable {
8178
fn lookup(&self, bit_buf: BitBuffer) -> Option<(i32, u32)> {
8279
let symbol = self.fast_lookup(bit_buf).into();
8380
if symbol >= 0 {
84-
if (symbol >> 9) as u32 != 0 {
85-
Some((symbol, (symbol >> 9) as u32))
86-
} else {
87-
// Zero-length code.
88-
None
81+
let length = (symbol >> 9) as u32;
82+
match length {
83+
0 => None,
84+
_ => Some((symbol, length)),
8985
}
9086
} else {
9187
// We didn't get a symbol from the fast lookup table, so check the tree instead.
@@ -101,7 +97,7 @@ const MAX_HUFF_SYMBOLS_0: usize = 288;
10197
/// The length of the second (distance) huffman table.
10298
const MAX_HUFF_SYMBOLS_1: usize = 32;
10399
/// The length of the last (huffman code length) huffman table.
104-
// const _MAX_HUFF_SYMBOLS_2: usize = 19;
100+
const MAX_HUFF_SYMBOLS_2: usize = 19;
105101
/// The maximum length of a code that can be looked up in the fast lookup table.
106102
const FAST_LOOKUP_BITS: u8 = 10;
107103
/// The size of the fast lookup table.
@@ -167,6 +163,13 @@ type BitBuffer = u64;
167163
#[cfg(not(target_pointer_width = "64"))]
168164
type BitBuffer = u32;
169165

166+
/*
167+
enum HuffmanTableType {
168+
LiteralLength = 0,
169+
Dist = 1,
170+
Huffman = 2,
171+
}*/
172+
170173
/// Main decompression struct.
171174
///
172175
#[derive(Clone)]
@@ -182,23 +185,26 @@ pub struct DecompressorOxide {
182185
/// Adler32 checksum from the zlib header.
183186
z_adler32: u32,
184187
/// 1 if the current block is the last block, 0 otherwise.
185-
finish: u32,
188+
finish: u8,
186189
/// The type of the current block.
187-
block_type: u32,
190+
block_type: u8,
188191
/// 1 if the adler32 value should be checked.
189192
check_adler32: u32,
190193
/// Last match distance.
191194
dist: u32,
192195
/// Variable used for match length, symbols, and a number of other things.
193196
counter: u32,
194197
/// Number of extra bits for the last length or distance code.
195-
num_extra: u32,
198+
num_extra: u8,
196199
/// Number of entries in each huffman table.
197-
table_sizes: [u32; MAX_HUFF_TABLES],
200+
table_sizes: [u16; MAX_HUFF_TABLES],
198201
/// Buffer of input data.
199202
bit_buf: BitBuffer,
200203
/// Huffman tables.
201204
tables: [HuffmanTable; MAX_HUFF_TABLES],
205+
code_size_literal: [u8; MAX_HUFF_SYMBOLS_0],
206+
code_size_dist: [u8; MAX_HUFF_SYMBOLS_1],
207+
code_size_huffman: [u8; MAX_HUFF_SYMBOLS_2],
202208
/// Raw block header.
203209
raw_header: [u8; 4],
204210
/// Huffman length codes.
@@ -245,6 +251,14 @@ impl DecompressorOxide {
245251
pub(crate) const fn zlib_header(&self) -> (u32, u32) {
246252
(self.z_header0, self.z_header1)
247253
}
254+
255+
/*fn code_size_table(&mut self, table_num: u8) -> &mut [u8] {
256+
match table_num {
257+
0 => &mut self.code_size_literal,
258+
1 => &mut self.code_size_dist,
259+
_ => &mut self.code_size_huffman,
260+
}
261+
}*/
248262
}
249263

250264
impl Default for DecompressorOxide {
@@ -271,6 +285,9 @@ impl Default for DecompressorOxide {
271285
HuffmanTable::new(),
272286
HuffmanTable::new(),
273287
],
288+
code_size_literal: [0; MAX_HUFF_SYMBOLS_0],
289+
code_size_dist: [0; MAX_HUFF_SYMBOLS_1],
290+
code_size_huffman: [0; MAX_HUFF_SYMBOLS_2],
274291
raw_header: [0; 4],
275292
len_codes: [0; MAX_HUFF_SYMBOLS_0 + MAX_HUFF_SYMBOLS_1 + 137],
276293
}
@@ -670,11 +687,11 @@ fn undo_bytes(l: &mut LocalVars, max: u32) -> u32 {
670687
fn start_static_table(r: &mut DecompressorOxide) {
671688
r.table_sizes[LITLEN_TABLE] = 288;
672689
r.table_sizes[DIST_TABLE] = 32;
673-
memset(&mut r.tables[LITLEN_TABLE].code_size[0..144], 8);
674-
memset(&mut r.tables[LITLEN_TABLE].code_size[144..256], 9);
675-
memset(&mut r.tables[LITLEN_TABLE].code_size[256..280], 7);
676-
memset(&mut r.tables[LITLEN_TABLE].code_size[280..288], 8);
677-
memset(&mut r.tables[DIST_TABLE].code_size[0..32], 5);
690+
memset(&mut r.code_size_literal[0..144], 8);
691+
memset(&mut r.code_size_literal[144..256], 9);
692+
memset(&mut r.code_size_literal[256..280], 7);
693+
memset(&mut r.code_size_literal[280..288], 8);
694+
memset(&mut r.code_size_dist[0..32], 5);
678695
}
679696

680697
#[cfg(feature = "rustc-dep-of-std")]
@@ -706,20 +723,25 @@ fn reverse_bits(n: u32) -> u32 {
706723
fn init_tree(r: &mut DecompressorOxide, l: &mut LocalVars) -> Option<Action> {
707724
loop {
708725
let bt = r.block_type as usize;
709-
if bt >= r.tables.len() {
710-
return None;
711-
}
726+
727+
let code_sizes = match bt {
728+
0 => &mut r.code_size_literal[..],
729+
1 => &mut r.code_size_dist,
730+
2 => &mut r.code_size_huffman,
731+
_ => return None,
732+
};
712733
let table = &mut r.tables[bt];
713-
let table_size = r.table_sizes[bt] as usize;
714-
if table_size > table.code_size.len() {
715-
return None;
716-
}
717-
let mut total_symbols = [0u32; 16];
734+
735+
let mut total_symbols = [0u16; 16];
718736
let mut next_code = [0u32; 17];
719737
memset(&mut table.look_up[..], 0);
720738
memset(&mut table.tree[..], 0);
721739

722-
for &code_size in &table.code_size[..table_size] {
740+
let table_size = r.table_sizes[bt] as usize;
741+
if table_size > code_sizes.len() {
742+
return None;
743+
}
744+
for &code_size in &code_sizes[..table_size] {
723745
let cs = code_size as usize;
724746
if cs >= total_symbols.len() {
725747
return None;
@@ -728,15 +750,10 @@ fn init_tree(r: &mut DecompressorOxide, l: &mut LocalVars) -> Option<Action> {
728750
}
729751

730752
let mut used_symbols = 0;
731-
let mut total = 0;
732-
for (ts, next) in total_symbols
733-
.iter()
734-
.copied()
735-
.zip(next_code.iter_mut().skip(1))
736-
.skip(1)
737-
{
753+
let mut total = 0u32;
754+
for (&ts, next) in total_symbols.iter().zip(next_code[1..].iter_mut()).skip(1) {
738755
used_symbols += ts;
739-
total += ts;
756+
total += u32::from(ts);
740757
total <<= 1;
741758
*next = total;
742759
}
@@ -747,7 +764,7 @@ fn init_tree(r: &mut DecompressorOxide, l: &mut LocalVars) -> Option<Action> {
747764

748765
let mut tree_next = -1;
749766
for symbol_index in 0..table_size {
750-
let code_size = table.code_size[symbol_index];
767+
let code_size = code_sizes[symbol_index];
751768
if code_size == 0 || usize::from(code_size) >= next_code.len() {
752769
continue;
753770
}
@@ -822,6 +839,7 @@ fn init_tree(r: &mut DecompressorOxide, l: &mut LocalVars) -> Option<Action> {
822839
}
823840

824841
l.counter = 0;
842+
825843
Some(Action::Jump(DecodeLitlen))
826844
}
827845

@@ -1203,7 +1221,7 @@ pub fn decompress(
12031221
num_bits: r.num_bits,
12041222
dist: r.dist,
12051223
counter: r.counter,
1206-
num_extra: r.num_extra as u8,
1224+
num_extra: r.num_extra,
12071225
};
12081226

12091227
let mut status = 'state_machine: loop {
@@ -1242,8 +1260,8 @@ pub fn decompress(
12421260
// Read the block header and jump to the relevant section depending on the block type.
12431261
ReadBlockHeader => generate_state!(state, 'state_machine, {
12441262
read_bits(&mut l, 3, &mut in_iter, flags, |l, bits| {
1245-
r.finish = (bits & 1) as u32;
1246-
r.block_type = (bits >> 1) as u32 & 3;
1263+
r.finish = (bits & 1) as u8;
1264+
r.block_type = ((bits >> 1) & 3) as u8;
12471265
match r.block_type {
12481266
0 => Action::Jump(BlockTypeNoCompression),
12491267
1 => {
@@ -1375,12 +1393,12 @@ pub fn decompress(
13751393
let num_bits = [5, 5, 4][l.counter as usize];
13761394
read_bits(&mut l, num_bits, &mut in_iter, flags, |l, bits| {
13771395
r.table_sizes[l.counter as usize] =
1378-
bits as u32 + u32::from(MIN_TABLE_SIZES[l.counter as usize]);
1396+
bits as u16 + MIN_TABLE_SIZES[l.counter as usize];
13791397
l.counter += 1;
13801398
Action::None
13811399
})
13821400
} else {
1383-
memset(&mut r.tables[HUFFLEN_TABLE].code_size[..], 0);
1401+
memset(&mut r.code_size_huffman[..], 0);
13841402
l.counter = 0;
13851403
// Check that the litlen and distance are within spec.
13861404
// litlen table should be <=286 acc to the RFC and
@@ -1400,25 +1418,24 @@ pub fn decompress(
14001418
// Read the 3-bit lengths of the huffman codes describing the huffman code lengths used
14011419
// to decode the lengths of the main tables.
14021420
ReadHufflenTableCodeSize => generate_state!(state, 'state_machine, {
1403-
if l.counter < r.table_sizes[HUFFLEN_TABLE] {
1421+
if l.counter < r.table_sizes[HUFFLEN_TABLE].into() {
14041422
read_bits(&mut l, 3, &mut in_iter, flags, |l, bits| {
14051423
// These lengths are not stored in a normal ascending order, but rather one
14061424
// specified by the deflate specification intended to put the most used
14071425
// values at the front as trailing zero lengths do not have to be stored.
1408-
r.tables[HUFFLEN_TABLE]
1409-
.code_size[HUFFMAN_LENGTH_ORDER[l.counter as usize] as usize] =
1426+
r.code_size_huffman[HUFFMAN_LENGTH_ORDER[l.counter as usize] as usize] =
14101427
bits as u8;
14111428
l.counter += 1;
14121429
Action::None
14131430
})
14141431
} else {
1415-
r.table_sizes[HUFFLEN_TABLE] = 19;
1432+
r.table_sizes[HUFFLEN_TABLE] = MAX_HUFF_SYMBOLS_2 as u16;
14161433
init_tree(r, &mut l).unwrap_or(Action::End(TINFLStatus::Failed))
14171434
}
14181435
}),
14191436

14201437
ReadLitlenDistTablesCodeSize => generate_state!(state, 'state_machine, {
1421-
if l.counter < r.table_sizes[LITLEN_TABLE] + r.table_sizes[DIST_TABLE] {
1438+
if l.counter < u32::from(r.table_sizes[LITLEN_TABLE]) + u32::from(r.table_sizes[DIST_TABLE]) {
14221439
decode_huffman_code(
14231440
r, &mut l, HUFFLEN_TABLE,
14241441
flags, &mut in_iter, |r, l, symbol| {
@@ -1435,16 +1452,16 @@ pub fn decompress(
14351452
}
14361453
}
14371454
)
1438-
} else if l.counter != r.table_sizes[LITLEN_TABLE] + r.table_sizes[DIST_TABLE] {
1455+
} else if l.counter != u32::from(r.table_sizes[LITLEN_TABLE]) + u32::from(r.table_sizes[DIST_TABLE]) {
14391456
Action::Jump(BadCodeSizeSum)
14401457
} else {
1441-
r.tables[LITLEN_TABLE].code_size[..r.table_sizes[LITLEN_TABLE] as usize]
1458+
r.code_size_literal[..r.table_sizes[LITLEN_TABLE] as usize]
14421459
.copy_from_slice(&r.len_codes[..r.table_sizes[LITLEN_TABLE] as usize]);
14431460

14441461
let dist_table_start = r.table_sizes[LITLEN_TABLE] as usize;
14451462
let dist_table_end = (r.table_sizes[LITLEN_TABLE] +
14461463
r.table_sizes[DIST_TABLE]) as usize;
1447-
r.tables[DIST_TABLE].code_size[..r.table_sizes[DIST_TABLE] as usize]
1464+
r.code_size_dist[..r.table_sizes[DIST_TABLE] as usize]
14481465
.copy_from_slice(&r.len_codes[dist_table_start..dist_table_end]);
14491466

14501467
r.block_type -= 1;
@@ -1782,7 +1799,7 @@ pub fn decompress(
17821799
r.num_bits = l.num_bits;
17831800
r.dist = l.dist;
17841801
r.counter = l.counter;
1785-
r.num_extra = l.num_extra.into();
1802+
r.num_extra = l.num_extra;
17861803

17871804
r.bit_buf &= ((1 as BitBuffer) << r.num_bits) - 1;
17881805

@@ -1908,7 +1925,7 @@ mod test {
19081925
num_bits: d.num_bits,
19091926
dist: d.dist,
19101927
counter: d.counter,
1911-
num_extra: d.num_extra as u8,
1928+
num_extra: d.num_extra,
19121929
};
19131930
init_tree(&mut d, &mut l).unwrap();
19141931
let llt = &d.tables[LITLEN_TABLE];

0 commit comments

Comments
 (0)