1use super::*;
4use crate::shared::{update_adler32, HUFFMAN_LENGTH_ORDER};
5
6use std::convert::TryInto;
7use std::{cmp, slice};
8
9use self::output_buffer::OutputBuffer;
10
11pub const TINFL_LZ_DICT_SIZE: usize = 32_768;
12
13struct HuffmanTable {
15 pub code_size: [u8; MAX_HUFF_SYMBOLS_0],
17 pub look_up: [i16; FAST_LOOKUP_SIZE as usize],
21 pub tree: [i16; MAX_HUFF_TREE_SIZE],
26}
27
28impl HuffmanTable {
29 fn new() -> HuffmanTable {
30 HuffmanTable {
31 code_size: [0; MAX_HUFF_SYMBOLS_0],
32 look_up: [0; FAST_LOOKUP_SIZE as usize],
33 tree: [0; MAX_HUFF_TREE_SIZE],
34 }
35 }
36
37 #[inline]
42 fn fast_lookup(&self, bit_buf: BitBuffer) -> i16 {
43 self.look_up[(bit_buf & BitBuffer::from(FAST_LOOKUP_SIZE - 1)) as usize]
44 }
45
46 #[inline]
48 fn tree_lookup(&self, fast_symbol: i32, bit_buf: BitBuffer, mut code_len: u32) -> (i32, u32) {
49 let mut symbol = fast_symbol;
50 loop {
53 symbol = i32::from(self.tree[(!symbol + ((bit_buf >> code_len) & 1) as i32) as usize]);
56 code_len += 1;
57 if symbol >= 0 {
58 break;
59 }
60 }
61 (symbol, code_len)
62 }
63
64 #[inline]
65 fn lookup(&self, bit_buf: BitBuffer) -> Option<(i32, u32)> {
73 let symbol = self.fast_lookup(bit_buf).into();
74 if symbol >= 0 {
75 if (symbol >> 9) as u32 != 0 {
76 Some((symbol, (symbol >> 9) as u32))
77 } else {
78 None
80 }
81 } else {
82 Some(self.tree_lookup(symbol, bit_buf, FAST_LOOKUP_BITS.into()))
84 }
85 }
86}
87
88const MAX_HUFF_TABLES: usize = 3;
90const MAX_HUFF_SYMBOLS_0: usize = 288;
92const MAX_HUFF_SYMBOLS_1: usize = 32;
94const _MAX_HUFF_SYMBOLS_2: usize = 19;
96const FAST_LOOKUP_BITS: u8 = 10;
98const FAST_LOOKUP_SIZE: u32 = 1 << FAST_LOOKUP_BITS;
100const MAX_HUFF_TREE_SIZE: usize = MAX_HUFF_SYMBOLS_0 * 2;
101const LITLEN_TABLE: usize = 0;
102const DIST_TABLE: usize = 1;
103const HUFFLEN_TABLE: usize = 2;
104
105pub mod inflate_flags {
106 pub const TINFL_FLAG_PARSE_ZLIB_HEADER: u32 = 1;
108 pub const TINFL_FLAG_HAS_MORE_INPUT: u32 = 2;
110 pub const TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF: u32 = 4;
112 pub const TINFL_FLAG_COMPUTE_ADLER32: u32 = 8;
114}
115
116use self::inflate_flags::*;
117
118const MIN_TABLE_SIZES: [u16; 3] = [257, 1, 4];
119
120#[cfg(target_pointer_width = "64")]
121type BitBuffer = u64;
122
123#[cfg(not(target_pointer_width = "64"))]
124type BitBuffer = u32;
125
126pub struct DecompressorOxide {
129 state: core::State,
131 num_bits: u32,
133 z_header0: u32,
135 z_header1: u32,
137 z_adler32: u32,
139 finish: u32,
141 block_type: u32,
143 check_adler32: u32,
145 dist: u32,
147 counter: u32,
149 num_extra: u32,
151 table_sizes: [u32; MAX_HUFF_TABLES],
153 bit_buf: BitBuffer,
155 tables: [HuffmanTable; MAX_HUFF_TABLES],
157 raw_header: [u8; 4],
159 len_codes: [u8; MAX_HUFF_SYMBOLS_0 + MAX_HUFF_SYMBOLS_1 + 137],
161}
162
163impl DecompressorOxide {
164 pub fn new() -> DecompressorOxide {
166 DecompressorOxide::default()
167 }
168
169 #[inline]
171 pub fn init(&mut self) {
172 self.state = core::State::Start;
174 }
175
176 #[inline]
178 pub fn adler32(&self) -> Option<u32> {
179 if self.state != State::Start && !self.state.is_failure() && self.z_header0 != 0 {
180 Some(self.check_adler32)
181 } else {
182 None
183 }
184 }
185}
186
187impl Default for DecompressorOxide {
188 #[inline(always)]
190 fn default() -> Self {
191 DecompressorOxide {
192 state: core::State::Start,
193 num_bits: 0,
194 z_header0: 0,
195 z_header1: 0,
196 z_adler32: 0,
197 finish: 0,
198 block_type: 0,
199 check_adler32: 0,
200 dist: 0,
201 counter: 0,
202 num_extra: 0,
203 table_sizes: [0; MAX_HUFF_TABLES],
204 bit_buf: 0,
205 tables: [
207 HuffmanTable::new(),
208 HuffmanTable::new(),
209 HuffmanTable::new(),
210 ],
211 raw_header: [0; 4],
212 len_codes: [0; MAX_HUFF_SYMBOLS_0 + MAX_HUFF_SYMBOLS_1 + 137],
213 }
214 }
215}
216
217#[derive(Copy, Clone, PartialEq, Eq, Debug)]
218enum State {
219 Start = 0,
220 ReadZlibCmf,
221 ReadZlibFlg,
222 ReadBlockHeader,
223 BlockTypeNoCompression,
224 RawHeader,
225 RawMemcpy1,
226 RawMemcpy2,
227 ReadTableSizes,
228 ReadHufflenTableCodeSize,
229 ReadLitlenDistTablesCodeSize,
230 ReadExtraBitsCodeSize,
231 DecodeLitlen,
232 WriteSymbol,
233 ReadExtraBitsLitlen,
234 DecodeDistance,
235 ReadExtraBitsDistance,
236 RawReadFirstByte,
237 RawStoreFirstByte,
238 WriteLenBytesToEnd,
239 BlockDone,
240 HuffDecodeOuterLoop1,
241 HuffDecodeOuterLoop2,
242 ReadAdler32,
243
244 DoneForever,
245
246 BlockTypeUnexpected,
248 BadCodeSizeSum,
249 BadTotalSymbols,
250 BadZlibHeader,
251 DistanceOutOfBounds,
252 BadRawLength,
253 BadCodeSizeDistPrevLookup,
254 InvalidLitlen,
255 InvalidDist,
256 InvalidCodeLen,
257}
258
259impl State {
260 fn is_failure(self) -> bool {
261 match self {
262 BlockTypeUnexpected => true,
263 BadCodeSizeSum => true,
264 BadTotalSymbols => true,
265 BadZlibHeader => true,
266 DistanceOutOfBounds => true,
267 BadRawLength => true,
268 BadCodeSizeDistPrevLookup => true,
269 InvalidLitlen => true,
270 InvalidDist => true,
271 _ => false,
272 }
273 }
274
275 #[inline]
276 fn begin(&mut self, new_state: State) {
277 *self = new_state;
278 }
279}
280
281use self::State::*;
282
283#[rustfmt::skip]
294const LENGTH_BASE: [u16; 32] = [
295 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31,
296 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 512, 512, 512
297];
298
299#[rustfmt::skip]
301const LENGTH_EXTRA: [u8; 32] = [
302 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2,
303 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0, 0, 0, 0
304];
305
306#[rustfmt::skip]
308const DIST_BASE: [u16; 32] = [
309 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33,
310 49, 65, 97, 129, 193, 257, 385, 513, 769, 1025, 1537,
311 2049, 3073, 4097, 6145, 8193, 12_289, 16_385, 24_577, 32_768, 32_768
312];
313
314#[rustfmt::skip]
316const DIST_EXTRA: [u8; 32] = [
317 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6,
318 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13, 13, 13
319];
320
321const BASE_EXTRA_MASK: usize = 32 - 1;
323
324#[inline]
326fn memset<T: Copy>(slice: &mut [T], val: T) {
327 for x in slice {
328 *x = val
329 }
330}
331
332#[inline]
337fn read_u16_le(iter: &mut slice::Iter<u8>) -> u16 {
338 let ret = {
339 let two_bytes = iter.as_ref()[..2].try_into().unwrap();
340 u16::from_le_bytes(two_bytes)
341 };
342 iter.nth(1);
343 ret
344}
345
346#[inline(always)]
351#[cfg(target_pointer_width = "64")]
352fn read_u32_le(iter: &mut slice::Iter<u8>) -> u32 {
353 let ret = {
354 let four_bytes: [u8; 4] = iter.as_ref()[..4].try_into().unwrap();
355 u32::from_le_bytes(four_bytes)
356 };
357 iter.nth(3);
358 ret
359}
360
361#[inline(always)]
367#[cfg(target_pointer_width = "64")]
368fn fill_bit_buffer(l: &mut LocalVars, in_iter: &mut slice::Iter<u8>) {
369 if l.num_bits < 30 {
371 l.bit_buf |= BitBuffer::from(read_u32_le(in_iter)) << l.num_bits;
372 l.num_bits += 32;
373 }
374}
375
376#[inline(always)]
379#[cfg(not(target_pointer_width = "64"))]
380fn fill_bit_buffer(l: &mut LocalVars, in_iter: &mut slice::Iter<u8>) {
381 if l.num_bits < 15 {
383 l.bit_buf |= BitBuffer::from(read_u16_le(in_iter)) << l.num_bits;
384 l.num_bits += 16;
385 }
386}
387
388#[inline]
393fn validate_zlib_header(cmf: u32, flg: u32, flags: u32, mask: usize) -> Action {
394 let mut failed =
395 (((cmf * 256) + flg) % 31 != 0) ||
397 ((flg & 0b0010_0000) != 0) ||
400 ((cmf & 15) != 8);
402
403 let window_size = 1 << ((cmf >> 4) + 8);
404 if (flags & TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF) == 0 {
405 failed |= (mask + 1) < window_size;
407 }
408
409 failed |= window_size > 32_768;
411
412 if failed {
413 Action::Jump(BadZlibHeader)
414 } else {
415 Action::Jump(ReadBlockHeader)
416 }
417}
418
419enum Action {
420 None,
421 Jump(State),
422 End(TINFLStatus),
423}
424
425fn decode_huffman_code<F>(
432 r: &mut DecompressorOxide,
433 l: &mut LocalVars,
434 table: usize,
435 flags: u32,
436 in_iter: &mut slice::Iter<u8>,
437 f: F,
438) -> Action
439where
440 F: FnOnce(&mut DecompressorOxide, &mut LocalVars, i32) -> Action,
441{
442 if l.num_bits < 15 {
445 if in_iter.len() < 2 {
447 loop {
460 let mut temp = i32::from(r.tables[table].fast_lookup(l.bit_buf));
461
462 if temp >= 0 {
463 let code_len = (temp >> 9) as u32;
464 if (code_len != 0) && (l.num_bits >= code_len) {
465 break;
466 }
467 } else if l.num_bits > FAST_LOOKUP_BITS.into() {
468 let mut code_len = u32::from(FAST_LOOKUP_BITS);
469 loop {
470 temp = i32::from(
471 r.tables[table].tree
472 [(!temp + ((l.bit_buf >> code_len) & 1) as i32) as usize],
473 );
474 code_len += 1;
475 if temp >= 0 || l.num_bits < code_len + 1 {
476 break;
477 }
478 }
479 if temp >= 0 {
480 break;
481 }
482 }
483
484 let mut byte = 0;
489 if let a @ Action::End(_) = read_byte(in_iter, flags, |b| {
490 byte = b;
491 Action::None
492 }) {
493 return a;
494 };
495
496 l.bit_buf |= BitBuffer::from(byte) << l.num_bits;
498 l.num_bits += 8;
499
500 if l.num_bits >= 15 {
501 break;
502 }
503 }
504 } else {
505 l.bit_buf |= BitBuffer::from(read_u16_le(in_iter)) << l.num_bits;
510 l.num_bits += 16;
511 }
512 }
513
514 let mut symbol = i32::from(r.tables[table].fast_lookup(l.bit_buf));
516 let code_len;
517 if symbol >= 0 {
519 code_len = (symbol >> 9) as u32;
523 symbol &= 511;
525 } else {
526 let res = r.tables[table].tree_lookup(symbol, l.bit_buf, u32::from(FAST_LOOKUP_BITS));
527 symbol = res.0;
528 code_len = res.1 as u32;
529 };
530
531 if code_len == 0 {
532 return Action::Jump(InvalidCodeLen);
533 }
534
535 l.bit_buf >>= code_len as u32;
536 l.num_bits -= code_len;
537 f(r, l, symbol)
538}
539
540#[inline]
544fn read_byte<F>(in_iter: &mut slice::Iter<u8>, flags: u32, f: F) -> Action
545where
546 F: FnOnce(u8) -> Action,
547{
548 match in_iter.next() {
549 None => end_of_input(flags),
550 Some(&byte) => f(byte),
551 }
552}
553
554#[inline]
559#[allow(clippy::while_immutable_condition)]
560fn read_bits<F>(
561 l: &mut LocalVars,
562 amount: u32,
563 in_iter: &mut slice::Iter<u8>,
564 flags: u32,
565 f: F,
566) -> Action
567where
568 F: FnOnce(&mut LocalVars, BitBuffer) -> Action,
569{
570 while l.num_bits < amount {
573 match read_byte(in_iter, flags, |byte| {
574 l.bit_buf |= BitBuffer::from(byte) << l.num_bits;
575 l.num_bits += 8;
576 Action::None
577 }) {
578 Action::None => (),
579 action => return action,
582 }
583 }
584
585 let bits = l.bit_buf & ((1 << amount) - 1);
586 l.bit_buf >>= amount;
587 l.num_bits -= amount;
588 f(l, bits)
589}
590
591#[inline]
592fn pad_to_bytes<F>(l: &mut LocalVars, in_iter: &mut slice::Iter<u8>, flags: u32, f: F) -> Action
593where
594 F: FnOnce(&mut LocalVars) -> Action,
595{
596 let num_bits = l.num_bits & 7;
597 read_bits(l, num_bits, in_iter, flags, |l, _| f(l))
598}
599
600#[inline]
601fn end_of_input(flags: u32) -> Action {
602 Action::End(if flags & TINFL_FLAG_HAS_MORE_INPUT != 0 {
603 TINFLStatus::NeedsMoreInput
604 } else {
605 TINFLStatus::FailedCannotMakeProgress
606 })
607}
608
609#[inline]
610fn undo_bytes(l: &mut LocalVars, max: u32) -> u32 {
611 let res = cmp::min(l.num_bits >> 3, max);
612 l.num_bits -= res << 3;
613 res
614}
615
616fn start_static_table(r: &mut DecompressorOxide) {
617 r.table_sizes[LITLEN_TABLE] = 288;
618 r.table_sizes[DIST_TABLE] = 32;
619 memset(&mut r.tables[LITLEN_TABLE].code_size[0..144], 8);
620 memset(&mut r.tables[LITLEN_TABLE].code_size[144..256], 9);
621 memset(&mut r.tables[LITLEN_TABLE].code_size[256..280], 7);
622 memset(&mut r.tables[LITLEN_TABLE].code_size[280..288], 8);
623 memset(&mut r.tables[DIST_TABLE].code_size[0..32], 5);
624}
625
626fn init_tree(r: &mut DecompressorOxide, l: &mut LocalVars) -> Action {
627 loop {
628 let table = &mut r.tables[r.block_type as usize];
629 let table_size = r.table_sizes[r.block_type as usize] as usize;
630 let mut total_symbols = [0u32; 16];
631 let mut next_code = [0u32; 17];
632 memset(&mut table.look_up[..], 0);
633 memset(&mut table.tree[..], 0);
634
635 for &code_size in &table.code_size[..table_size] {
636 total_symbols[code_size as usize] += 1;
637 }
638
639 let mut used_symbols = 0;
640 let mut total = 0;
641 for i in 1..16 {
642 used_symbols += total_symbols[i];
643 total += total_symbols[i];
644 total <<= 1;
645 next_code[i + 1] = total;
646 }
647
648 if total != 65_536 && used_symbols > 1 {
649 return Action::Jump(BadTotalSymbols);
650 }
651
652 let mut tree_next = -1;
653 for symbol_index in 0..table_size {
654 let mut rev_code = 0;
655 let code_size = table.code_size[symbol_index];
656 if code_size == 0 {
657 continue;
658 }
659
660 let mut cur_code = next_code[code_size as usize];
661 next_code[code_size as usize] += 1;
662
663 for _ in 0..code_size {
664 rev_code = (rev_code << 1) | (cur_code & 1);
665 cur_code >>= 1;
666 }
667
668 if code_size <= FAST_LOOKUP_BITS {
669 let k = (i16::from(code_size) << 9) | symbol_index as i16;
670 while rev_code < FAST_LOOKUP_SIZE {
671 table.look_up[rev_code as usize] = k;
672 rev_code += 1 << code_size;
673 }
674 continue;
675 }
676
677 let mut tree_cur = table.look_up[(rev_code & (FAST_LOOKUP_SIZE - 1)) as usize];
678 if tree_cur == 0 {
679 table.look_up[(rev_code & (FAST_LOOKUP_SIZE - 1)) as usize] = tree_next as i16;
680 tree_cur = tree_next;
681 tree_next -= 2;
682 }
683
684 rev_code >>= FAST_LOOKUP_BITS - 1;
685 for _ in FAST_LOOKUP_BITS + 1..code_size {
686 rev_code >>= 1;
687 tree_cur -= (rev_code & 1) as i16;
688 if table.tree[(-tree_cur - 1) as usize] == 0 {
689 table.tree[(-tree_cur - 1) as usize] = tree_next as i16;
690 tree_cur = tree_next;
691 tree_next -= 2;
692 } else {
693 tree_cur = table.tree[(-tree_cur - 1) as usize];
694 }
695 }
696
697 rev_code >>= 1;
698 tree_cur -= (rev_code & 1) as i16;
699 table.tree[(-tree_cur - 1) as usize] = symbol_index as i16;
700 }
701
702 if r.block_type == 2 {
703 l.counter = 0;
704 return Action::Jump(ReadLitlenDistTablesCodeSize);
705 }
706
707 if r.block_type == 0 {
708 break;
709 }
710 r.block_type -= 1;
711 }
712
713 l.counter = 0;
714 Action::Jump(DecodeLitlen)
715}
716
717macro_rules! generate_state {
722 ($state: ident, $state_machine: tt, $f: expr) => {
723 loop {
724 match $f {
725 Action::None => continue,
726 Action::Jump(new_state) => {
727 $state = new_state;
728 continue $state_machine;
729 },
730 Action::End(result) => break $state_machine result,
731 }
732 }
733 };
734}
735
736#[derive(Copy, Clone)]
737struct LocalVars {
738 pub bit_buf: BitBuffer,
739 pub num_bits: u32,
740 pub dist: u32,
741 pub counter: u32,
742 pub num_extra: u32,
743}
744
745#[inline]
746fn transfer(
747 out_slice: &mut [u8],
748 mut source_pos: usize,
749 mut out_pos: usize,
750 match_len: usize,
751 out_buf_size_mask: usize,
752) {
753 for _ in 0..match_len >> 2 {
754 out_slice[out_pos] = out_slice[source_pos & out_buf_size_mask];
755 out_slice[out_pos + 1] = out_slice[(source_pos + 1) & out_buf_size_mask];
756 out_slice[out_pos + 2] = out_slice[(source_pos + 2) & out_buf_size_mask];
757 out_slice[out_pos + 3] = out_slice[(source_pos + 3) & out_buf_size_mask];
758 source_pos += 4;
759 out_pos += 4;
760 }
761
762 match match_len & 3 {
763 0 => (),
764 1 => out_slice[out_pos] = out_slice[source_pos & out_buf_size_mask],
765 2 => {
766 out_slice[out_pos] = out_slice[source_pos & out_buf_size_mask];
767 out_slice[out_pos + 1] = out_slice[(source_pos + 1) & out_buf_size_mask];
768 }
769 3 => {
770 out_slice[out_pos] = out_slice[source_pos & out_buf_size_mask];
771 out_slice[out_pos + 1] = out_slice[(source_pos + 1) & out_buf_size_mask];
772 out_slice[out_pos + 2] = out_slice[(source_pos + 2) & out_buf_size_mask];
773 }
774 _ => unreachable!(),
775 }
776}
777
778#[inline]
780fn apply_match(
781 out_slice: &mut [u8],
782 out_pos: usize,
783 dist: usize,
784 match_len: usize,
785 out_buf_size_mask: usize,
786) {
787 debug_assert!(out_pos + match_len <= out_slice.len());
788
789 let source_pos = out_pos.wrapping_sub(dist) & out_buf_size_mask;
790
791 if match_len == 3 {
792 out_slice[out_pos] = out_slice[source_pos];
794 out_slice[out_pos + 1] = out_slice[(source_pos + 1) & out_buf_size_mask];
795 out_slice[out_pos + 2] = out_slice[(source_pos + 2) & out_buf_size_mask];
796 return;
797 }
798
799 if cfg!(not(any(target_arch = "x86", target_arch = "x86_64"))) {
800 transfer(out_slice, source_pos, out_pos, match_len, out_buf_size_mask);
802 return;
803 }
804
805 if source_pos >= out_pos && (source_pos - out_pos) < match_len {
806 transfer(out_slice, source_pos, out_pos, match_len, out_buf_size_mask);
807 } else if match_len <= dist && source_pos + match_len < out_slice.len() {
808 if source_pos < out_pos {
810 let (from_slice, to_slice) = out_slice.split_at_mut(out_pos);
811 to_slice[..match_len].copy_from_slice(&from_slice[source_pos..source_pos + match_len]);
812 } else {
813 let (to_slice, from_slice) = out_slice.split_at_mut(source_pos);
814 to_slice[out_pos..out_pos + match_len].copy_from_slice(&from_slice[..match_len]);
815 }
816 } else {
817 transfer(out_slice, source_pos, out_pos, match_len, out_buf_size_mask);
818 }
819}
820
821fn decompress_fast(
831 r: &mut DecompressorOxide,
832 mut in_iter: &mut slice::Iter<u8>,
833 out_buf: &mut OutputBuffer,
834 flags: u32,
835 local_vars: &mut LocalVars,
836 out_buf_size_mask: usize,
837) -> (TINFLStatus, State) {
838 let mut l = *local_vars;
841 let mut state;
842
843 let status: TINFLStatus = 'o: loop {
844 state = State::DecodeLitlen;
845 loop {
846 if out_buf.bytes_left() < 259 || in_iter.len() < 14 {
853 state = State::DecodeLitlen;
854 break 'o TINFLStatus::Done;
855 }
856
857 fill_bit_buffer(&mut l, &mut in_iter);
858
859 if let Some((symbol, code_len)) = r.tables[LITLEN_TABLE].lookup(l.bit_buf) {
860 l.counter = symbol as u32;
861 l.bit_buf >>= code_len;
862 l.num_bits -= code_len;
863
864 if (l.counter & 256) != 0 {
865 break;
867 } else {
868 if cfg!(not(target_pointer_width = "64")) {
871 fill_bit_buffer(&mut l, &mut in_iter);
872 }
873
874 if let Some((symbol, code_len)) = r.tables[LITLEN_TABLE].lookup(l.bit_buf) {
875 l.bit_buf >>= code_len;
876 l.num_bits -= code_len;
877 out_buf.write_byte(l.counter as u8);
880 if (symbol & 256) != 0 {
881 l.counter = symbol as u32;
882 break;
884 } else {
885 out_buf.write_byte(symbol as u8);
887 }
888 } else {
889 state.begin(InvalidCodeLen);
890 break 'o TINFLStatus::Failed;
891 }
892 }
893 } else {
894 state.begin(InvalidCodeLen);
895 break 'o TINFLStatus::Failed;
896 }
897 }
898
899 l.counter &= 511;
901 if l.counter == 256 {
902 state.begin(BlockDone);
904 break 'o TINFLStatus::Done;
905 } else if l.counter > 285 {
906 state.begin(InvalidLitlen);
909 break 'o TINFLStatus::Failed;
910 } else {
911 l.num_extra = u32::from(LENGTH_EXTRA[(l.counter - 257) as usize & BASE_EXTRA_MASK]);
917 l.counter = u32::from(LENGTH_BASE[(l.counter - 257) as usize & BASE_EXTRA_MASK]);
918 fill_bit_buffer(&mut l, &mut in_iter);
922 if l.num_extra != 0 {
923 let extra_bits = l.bit_buf & ((1 << l.num_extra) - 1);
924 l.bit_buf >>= l.num_extra;
925 l.num_bits -= l.num_extra;
926 l.counter += extra_bits as u32;
927 }
928
929 if cfg!(not(target_pointer_width = "64")) {
932 fill_bit_buffer(&mut l, &mut in_iter);
933 }
934
935 if let Some((mut symbol, code_len)) = r.tables[DIST_TABLE].lookup(l.bit_buf) {
936 symbol &= 511;
937 l.bit_buf >>= code_len;
938 l.num_bits -= code_len;
939 if symbol > 29 {
940 state.begin(InvalidDist);
941 break 'o TINFLStatus::Failed;
942 }
943
944 l.num_extra = u32::from(DIST_EXTRA[symbol as usize]);
945 l.dist = u32::from(DIST_BASE[symbol as usize]);
946 } else {
947 state.begin(InvalidCodeLen);
948 break 'o TINFLStatus::Failed;
949 }
950
951 if l.num_extra != 0 {
952 fill_bit_buffer(&mut l, &mut in_iter);
953 let extra_bits = l.bit_buf & ((1 << l.num_extra) - 1);
954 l.bit_buf >>= l.num_extra;
955 l.num_bits -= l.num_extra;
956 l.dist += extra_bits as u32;
957 }
958
959 let position = out_buf.position();
960 if l.dist as usize > out_buf.position()
961 && (flags & TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF != 0)
962 {
963 state.begin(DistanceOutOfBounds);
966 break TINFLStatus::Failed;
967 }
968
969 apply_match(
970 out_buf.get_mut(),
971 position,
972 l.dist as usize,
973 l.counter as usize,
974 out_buf_size_mask,
975 );
976
977 out_buf.set_position(position + l.counter as usize);
978 }
979 };
980
981 *local_vars = l;
982 (status, state)
983}
984
985pub fn decompress(
1021 r: &mut DecompressorOxide,
1022 in_buf: &[u8],
1023 out_cur: &mut Cursor<&mut [u8]>,
1024 flags: u32,
1025) -> (TINFLStatus, usize, usize) {
1026 let res = decompress_inner(r, in_buf, out_cur, flags);
1027 let new_pos = out_cur.position() + res.2 as u64;
1028 out_cur.set_position(new_pos);
1029 res
1030}
1031
1032#[inline]
1033fn decompress_inner(
1034 r: &mut DecompressorOxide,
1035 in_buf: &[u8],
1036 out_cur: &mut Cursor<&mut [u8]>,
1037 flags: u32,
1038) -> (TINFLStatus, usize, usize) {
1039 let out_buf_start_pos = out_cur.position() as usize;
1040 let out_buf_size_mask = if flags & TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF != 0 {
1041 usize::max_value()
1042 } else {
1043 out_cur.get_ref().len().saturating_sub(1)
1047 };
1048
1049 if (out_buf_size_mask.wrapping_add(1) & out_buf_size_mask) != 0
1054 || out_cur.position() > out_cur.get_ref().len() as u64
1055 {
1056 return (TINFLStatus::BadParam, 0, 0);
1057 }
1058
1059 let mut in_iter = in_buf.iter();
1060
1061 let mut state = r.state;
1062
1063 let mut out_buf = OutputBuffer::from_slice_and_pos(out_cur.get_mut(), out_buf_start_pos);
1064
1065 let mut l = LocalVars {
1067 bit_buf: r.bit_buf,
1068 num_bits: r.num_bits,
1069 dist: r.dist,
1070 counter: r.counter,
1071 num_extra: r.num_extra,
1072 };
1073
1074 let mut status = 'state_machine: loop {
1075 match state {
1076 Start => generate_state!(state, 'state_machine, {
1077 l.bit_buf = 0;
1078 l.num_bits = 0;
1079 l.dist = 0;
1080 l.counter = 0;
1081 l.num_extra = 0;
1082 r.z_header0 = 0;
1083 r.z_header1 = 0;
1084 r.z_adler32 = 1;
1085 r.check_adler32 = 1;
1086 if flags & TINFL_FLAG_PARSE_ZLIB_HEADER != 0 {
1087 Action::Jump(State::ReadZlibCmf)
1088 } else {
1089 Action::Jump(State::ReadBlockHeader)
1090 }
1091 }),
1092
1093 ReadZlibCmf => generate_state!(state, 'state_machine, {
1094 read_byte(&mut in_iter, flags, |cmf| {
1095 r.z_header0 = u32::from(cmf);
1096 Action::Jump(State::ReadZlibFlg)
1097 })
1098 }),
1099
1100 ReadZlibFlg => generate_state!(state, 'state_machine, {
1101 read_byte(&mut in_iter, flags, |flg| {
1102 r.z_header1 = u32::from(flg);
1103 validate_zlib_header(r.z_header0, r.z_header1, flags, out_buf_size_mask)
1104 })
1105 }),
1106
1107 ReadBlockHeader => generate_state!(state, 'state_machine, {
1109 read_bits(&mut l, 3, &mut in_iter, flags, |l, bits| {
1110 r.finish = (bits & 1) as u32;
1111 r.block_type = (bits >> 1) as u32 & 3;
1112 match r.block_type {
1113 0 => Action::Jump(BlockTypeNoCompression),
1114 1 => {
1115 start_static_table(r);
1116 init_tree(r, l)
1117 },
1118 2 => {
1119 l.counter = 0;
1120 Action::Jump(ReadTableSizes)
1121 },
1122 3 => Action::Jump(BlockTypeUnexpected),
1123 _ => unreachable!()
1124 }
1125 })
1126 }),
1127
1128 BlockTypeNoCompression => generate_state!(state, 'state_machine, {
1130 pad_to_bytes(&mut l, &mut in_iter, flags, |l| {
1131 l.counter = 0;
1132 Action::Jump(RawHeader)
1133 })
1134 }),
1135
1136 RawHeader => generate_state!(state, 'state_machine, {
1138 if l.counter < 4 {
1139 if l.num_bits != 0 {
1141 read_bits(&mut l, 8, &mut in_iter, flags, |l, bits| {
1142 r.raw_header[l.counter as usize] = bits as u8;
1143 l.counter += 1;
1144 Action::None
1145 })
1146 } else {
1147 read_byte(&mut in_iter, flags, |byte| {
1148 r.raw_header[l.counter as usize] = byte;
1149 l.counter += 1;
1150 Action::None
1151 })
1152 }
1153 } else {
1154 let length = u16::from(r.raw_header[0]) | (u16::from(r.raw_header[1]) << 8);
1158 let check = u16::from(r.raw_header[2]) | (u16::from(r.raw_header[3]) << 8);
1159 let valid = length == !check;
1160 l.counter = length.into();
1161
1162 if !valid {
1163 Action::Jump(BadRawLength)
1164 } else if l.counter == 0 {
1165 Action::Jump(BlockDone)
1167 } else if l.num_bits != 0 {
1168 Action::Jump(RawReadFirstByte)
1170 } else {
1171 Action::Jump(RawMemcpy1)
1174 }
1175 }
1176 }),
1177
1178 RawReadFirstByte => generate_state!(state, 'state_machine, {
1180 read_bits(&mut l, 8, &mut in_iter, flags, |l, bits| {
1181 l.dist = bits as u32;
1182 Action::Jump(RawStoreFirstByte)
1183 })
1184 }),
1185
1186 RawStoreFirstByte => generate_state!(state, 'state_machine, {
1188 if out_buf.bytes_left() == 0 {
1189 Action::End(TINFLStatus::HasMoreOutput)
1190 } else {
1191 out_buf.write_byte(l.dist as u8);
1192 l.counter -= 1;
1193 if l.counter == 0 || l.num_bits == 0 {
1194 Action::Jump(RawMemcpy1)
1195 } else {
1196 Action::Jump(RawReadFirstByte)
1201 }
1202 }
1203 }),
1204
1205 RawMemcpy1 => generate_state!(state, 'state_machine, {
1206 if l.counter == 0 {
1207 Action::Jump(BlockDone)
1208 } else if out_buf.bytes_left() == 0 {
1209 Action::End(TINFLStatus::HasMoreOutput)
1210 } else {
1211 Action::Jump(RawMemcpy2)
1212 }
1213 }),
1214
1215 RawMemcpy2 => generate_state!(state, 'state_machine, {
1216 if in_iter.len() > 0 {
1217 let space_left = out_buf.bytes_left();
1221 let bytes_to_copy = cmp::min(cmp::min(
1222 space_left,
1223 in_iter.len()),
1224 l.counter as usize
1225 );
1226
1227 out_buf.write_slice(&in_iter.as_slice()[..bytes_to_copy]);
1228
1229 (&mut in_iter).nth(bytes_to_copy - 1);
1230 l.counter -= bytes_to_copy as u32;
1231 Action::Jump(RawMemcpy1)
1232 } else {
1233 end_of_input(flags)
1234 }
1235 }),
1236
1237 ReadTableSizes => generate_state!(state, 'state_machine, {
1239 if l.counter < 3 {
1240 let num_bits = [5, 5, 4][l.counter as usize];
1241 read_bits(&mut l, num_bits, &mut in_iter, flags, |l, bits| {
1242 r.table_sizes[l.counter as usize] =
1243 bits as u32 + u32::from(MIN_TABLE_SIZES[l.counter as usize]);
1244 l.counter += 1;
1245 Action::None
1246 })
1247 } else {
1248 memset(&mut r.tables[HUFFLEN_TABLE].code_size[..], 0);
1249 l.counter = 0;
1250 Action::Jump(ReadHufflenTableCodeSize)
1251 }
1252 }),
1253
1254 ReadHufflenTableCodeSize => generate_state!(state, 'state_machine, {
1257 if l.counter < r.table_sizes[HUFFLEN_TABLE] {
1258 read_bits(&mut l, 3, &mut in_iter, flags, |l, bits| {
1259 r.tables[HUFFLEN_TABLE]
1263 .code_size[HUFFMAN_LENGTH_ORDER[l.counter as usize] as usize] =
1264 bits as u8;
1265 l.counter += 1;
1266 Action::None
1267 })
1268 } else {
1269 r.table_sizes[HUFFLEN_TABLE] = 19;
1270 init_tree(r, &mut l)
1271 }
1272 }),
1273
1274 ReadLitlenDistTablesCodeSize => generate_state!(state, 'state_machine, {
1275 if l.counter < r.table_sizes[LITLEN_TABLE] + r.table_sizes[DIST_TABLE] {
1276 decode_huffman_code(
1277 r, &mut l, HUFFLEN_TABLE,
1278 flags, &mut in_iter, |r, l, symbol| {
1279 l.dist = symbol as u32;
1280 if l.dist < 16 {
1281 r.len_codes[l.counter as usize] = l.dist as u8;
1282 l.counter += 1;
1283 Action::None
1284 } else if l.dist == 16 && l.counter == 0 {
1285 Action::Jump(BadCodeSizeDistPrevLookup)
1286 } else {
1287 l.num_extra = [2, 3, 7][l.dist as usize - 16];
1288 Action::Jump(ReadExtraBitsCodeSize)
1289 }
1290 }
1291 )
1292 } else if l.counter != r.table_sizes[LITLEN_TABLE] + r.table_sizes[DIST_TABLE] {
1293 Action::Jump(BadCodeSizeSum)
1294 } else {
1295 r.tables[LITLEN_TABLE].code_size[..r.table_sizes[LITLEN_TABLE] as usize]
1296 .copy_from_slice(&r.len_codes[..r.table_sizes[LITLEN_TABLE] as usize]);
1297
1298 let dist_table_start = r.table_sizes[LITLEN_TABLE] as usize;
1299 let dist_table_end = (r.table_sizes[LITLEN_TABLE] +
1300 r.table_sizes[DIST_TABLE]) as usize;
1301 r.tables[DIST_TABLE].code_size[..r.table_sizes[DIST_TABLE] as usize]
1302 .copy_from_slice(&r.len_codes[dist_table_start..dist_table_end]);
1303
1304 r.block_type -= 1;
1305 init_tree(r, &mut l)
1306 }
1307 }),
1308
1309 ReadExtraBitsCodeSize => generate_state!(state, 'state_machine, {
1310 let num_extra = l.num_extra;
1311 read_bits(&mut l, num_extra, &mut in_iter, flags, |l, mut extra_bits| {
1312 extra_bits += [3, 3, 11][(l.dist as usize - 16) & 3];
1314 let val = if l.dist == 16 {
1315 r.len_codes[l.counter as usize - 1]
1316 } else {
1317 0
1318 };
1319
1320 memset(
1321 &mut r.len_codes[
1322 l.counter as usize..l.counter as usize + extra_bits as usize
1323 ],
1324 val,
1325 );
1326 l.counter += extra_bits as u32;
1327 Action::Jump(ReadLitlenDistTablesCodeSize)
1328 })
1329 }),
1330
1331 DecodeLitlen => generate_state!(state, 'state_machine, {
1332 if in_iter.len() < 4 || out_buf.bytes_left() < 2 {
1333 decode_huffman_code(
1336 r,
1337 &mut l,
1338 LITLEN_TABLE,
1339 flags,
1340 &mut in_iter,
1341 |_r, l, symbol| {
1342 l.counter = symbol as u32;
1343 Action::Jump(WriteSymbol)
1344 },
1345 )
1346 } else if
1347 out_buf.bytes_left() >= 259 &&
1350 in_iter.len() >= 14
1351 {
1352 let (status, new_state) = decompress_fast(
1353 r,
1354 &mut in_iter,
1355 &mut out_buf,
1356 flags,
1357 &mut l,
1358 out_buf_size_mask,
1359 );
1360
1361 state = new_state;
1362 if status == TINFLStatus::Done {
1363 Action::Jump(new_state)
1364 } else {
1365 Action::End(status)
1366 }
1367 } else {
1368 fill_bit_buffer(&mut l, &mut in_iter);
1369
1370 if let Some((symbol, code_len)) = r.tables[LITLEN_TABLE].lookup(l.bit_buf) {
1371
1372 l.counter = symbol as u32;
1373 l.bit_buf >>= code_len;
1374 l.num_bits -= code_len;
1375
1376 if (l.counter & 256) != 0 {
1377 Action::Jump(HuffDecodeOuterLoop1)
1379 } else {
1380 if cfg!(not(target_pointer_width = "64")) {
1383 fill_bit_buffer(&mut l, &mut in_iter);
1384 }
1385
1386 if let Some((symbol, code_len)) = r.tables[LITLEN_TABLE].lookup(l.bit_buf) {
1387
1388 l.bit_buf >>= code_len;
1389 l.num_bits -= code_len;
1390 out_buf.write_byte(l.counter as u8);
1393 if (symbol & 256) != 0 {
1394 l.counter = symbol as u32;
1395 Action::Jump(HuffDecodeOuterLoop1)
1397 } else {
1398 out_buf.write_byte(symbol as u8);
1400 Action::None
1401 }
1402 } else {
1403 Action::Jump(InvalidCodeLen)
1404 }
1405 }
1406 } else {
1407 Action::Jump(InvalidCodeLen)
1408 }
1409 }
1410 }),
1411
1412 WriteSymbol => generate_state!(state, 'state_machine, {
1413 if l.counter >= 256 {
1414 Action::Jump(HuffDecodeOuterLoop1)
1415 } else if out_buf.bytes_left() > 0 {
1416 out_buf.write_byte(l.counter as u8);
1417 Action::Jump(DecodeLitlen)
1418 } else {
1419 Action::End(TINFLStatus::HasMoreOutput)
1420 }
1421 }),
1422
1423 HuffDecodeOuterLoop1 => generate_state!(state, 'state_machine, {
1424 l.counter &= 511;
1426
1427 if l.counter == 256 {
1428 Action::Jump(BlockDone)
1430 } else if l.counter > 285 {
1431 Action::Jump(InvalidLitlen)
1434 } else {
1435 l.num_extra =
1440 u32::from(LENGTH_EXTRA[(l.counter - 257) as usize & BASE_EXTRA_MASK]);
1441 l.counter = u32::from(LENGTH_BASE[(l.counter - 257) as usize & BASE_EXTRA_MASK]);
1442 if l.num_extra != 0 {
1445 Action::Jump(ReadExtraBitsLitlen)
1446 } else {
1447 Action::Jump(DecodeDistance)
1448 }
1449 }
1450 }),
1451
1452 ReadExtraBitsLitlen => generate_state!(state, 'state_machine, {
1453 let num_extra = l.num_extra;
1454 read_bits(&mut l, num_extra, &mut in_iter, flags, |l, extra_bits| {
1455 l.counter += extra_bits as u32;
1456 Action::Jump(DecodeDistance)
1457 })
1458 }),
1459
1460 DecodeDistance => generate_state!(state, 'state_machine, {
1461 decode_huffman_code(r, &mut l, DIST_TABLE, flags, &mut in_iter, |_r, l, symbol| {
1464 if symbol > 29 {
1465 return Action::Jump(InvalidDist)
1467 }
1468 l.num_extra = u32::from(DIST_EXTRA[symbol as usize & BASE_EXTRA_MASK]);
1473 l.dist = u32::from(DIST_BASE[symbol as usize & BASE_EXTRA_MASK]);
1474 if l.num_extra != 0 {
1475 Action::Jump(ReadExtraBitsDistance)
1477 } else {
1478 Action::Jump(HuffDecodeOuterLoop2)
1479 }
1480 })
1481 }),
1482
1483 ReadExtraBitsDistance => generate_state!(state, 'state_machine, {
1484 let num_extra = l.num_extra;
1485 read_bits(&mut l, num_extra, &mut in_iter, flags, |l, extra_bits| {
1486 l.dist += extra_bits as u32;
1487 Action::Jump(HuffDecodeOuterLoop2)
1488 })
1489 }),
1490
1491 HuffDecodeOuterLoop2 => generate_state!(state, 'state_machine, {
1492 if l.dist as usize > out_buf.position() &&
1493 (flags & TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF != 0)
1494 {
1495 Action::Jump(DistanceOutOfBounds)
1498 } else {
1499 let out_pos = out_buf.position();
1500 let source_pos = out_buf.position()
1501 .wrapping_sub(l.dist as usize) & out_buf_size_mask;
1502
1503 let out_len = out_buf.get_ref().len() as usize;
1504 let match_end_pos = out_buf.position() + l.counter as usize;
1505
1506 if match_end_pos > out_len ||
1507 (source_pos >= out_pos && (source_pos - out_pos) < l.counter as usize)
1510 {
1511 if l.counter == 0 {
1514 Action::Jump(DecodeLitlen)
1515 } else {
1516 Action::Jump(WriteLenBytesToEnd)
1517 }
1518 } else {
1519 apply_match(
1520 out_buf.get_mut(),
1521 out_pos,
1522 l.dist as usize,
1523 l.counter as usize,
1524 out_buf_size_mask
1525 );
1526 out_buf.set_position(out_pos + l.counter as usize);
1527 Action::Jump(DecodeLitlen)
1528 }
1529 }
1530 }),
1531
1532 WriteLenBytesToEnd => generate_state!(state, 'state_machine, {
1533 if out_buf.bytes_left() > 0 {
1534 let out_pos = out_buf.position();
1535 let source_pos = out_buf.position()
1536 .wrapping_sub(l.dist as usize) & out_buf_size_mask;
1537
1538
1539 let len = cmp::min(out_buf.bytes_left(), l.counter as usize);
1540
1541 transfer(out_buf.get_mut(), source_pos, out_pos, len, out_buf_size_mask);
1542
1543 out_buf.set_position(out_pos + len);
1544 l.counter -= len as u32;
1545 if l.counter == 0 {
1546 Action::Jump(DecodeLitlen)
1547 } else {
1548 Action::None
1549 }
1550 } else {
1551 Action::End(TINFLStatus::HasMoreOutput)
1552 }
1553 }),
1554
1555 BlockDone => generate_state!(state, 'state_machine, {
1556 if r.finish != 0 {
1558 pad_to_bytes(&mut l, &mut in_iter, flags, |_| Action::None);
1559
1560 let in_consumed = in_buf.len() - in_iter.len();
1561 let undo = undo_bytes(&mut l, in_consumed as u32) as usize;
1562 in_iter = in_buf[in_consumed - undo..].iter();
1563
1564 l.bit_buf &= ((1 as BitBuffer) << l.num_bits) - 1;
1565 debug_assert_eq!(l.num_bits, 0);
1566
1567 if flags & TINFL_FLAG_PARSE_ZLIB_HEADER != 0 {
1568 l.counter = 0;
1569 Action::Jump(ReadAdler32)
1570 } else {
1571 Action::Jump(DoneForever)
1572 }
1573 } else {
1574 Action::Jump(ReadBlockHeader)
1575 }
1576 }),
1577
1578 ReadAdler32 => generate_state!(state, 'state_machine, {
1579 if l.counter < 4 {
1580 if l.num_bits != 0 {
1581 read_bits(&mut l, 8, &mut in_iter, flags, |l, bits| {
1582 r.z_adler32 <<= 8;
1583 r.z_adler32 |= bits as u32;
1584 l.counter += 1;
1585 Action::None
1586 })
1587 } else {
1588 read_byte(&mut in_iter, flags, |byte| {
1589 r.z_adler32 <<= 8;
1590 r.z_adler32 |= u32::from(byte);
1591 l.counter += 1;
1592 Action::None
1593 })
1594 }
1595 } else {
1596 Action::Jump(DoneForever)
1597 }
1598 }),
1599
1600 DoneForever => break TINFLStatus::Done,
1602
1603 _ => break TINFLStatus::Failed,
1608 };
1609 };
1610
1611 let in_undo = if status != TINFLStatus::NeedsMoreInput
1612 && status != TINFLStatus::FailedCannotMakeProgress
1613 {
1614 undo_bytes(&mut l, (in_buf.len() - in_iter.len()) as u32) as usize
1615 } else {
1616 0
1617 };
1618
1619 if status == TINFLStatus::NeedsMoreInput && out_buf.bytes_left() == 0 {
1620 status = TINFLStatus::HasMoreOutput
1621 }
1622
1623 r.state = state;
1624 r.bit_buf = l.bit_buf;
1625 r.num_bits = l.num_bits;
1626 r.dist = l.dist;
1627 r.counter = l.counter;
1628 r.num_extra = l.num_extra;
1629
1630 r.bit_buf &= ((1 as BitBuffer) << r.num_bits) - 1;
1631
1632 let need_adler = flags & (TINFL_FLAG_PARSE_ZLIB_HEADER | TINFL_FLAG_COMPUTE_ADLER32) != 0;
1635 if need_adler && status as i32 >= 0 {
1636 let out_buf_pos = out_buf.position();
1637 r.check_adler32 = update_adler32(
1638 r.check_adler32,
1639 &out_buf.get_ref()[out_buf_start_pos..out_buf_pos],
1640 );
1641
1642 if !cfg!(fuzzing) {
1645 if status == TINFLStatus::Done
1647 && flags & TINFL_FLAG_PARSE_ZLIB_HEADER != 0
1648 && r.check_adler32 != r.z_adler32
1649 {
1650 status = TINFLStatus::Adler32Mismatch;
1651 }
1652 }
1653 }
1654
1655 (
1656 status,
1657 in_buf.len() - in_iter.len() - in_undo,
1658 out_buf.position() - out_buf_start_pos,
1659 )
1660}
1661
1662#[cfg(test)]
1663mod test {
1664 use super::*;
1665
1666 fn tinfl_decompress_oxide<'i>(
1669 r: &mut DecompressorOxide,
1670 input_buffer: &'i [u8],
1671 output_buffer: &mut [u8],
1672 flags: u32,
1673 ) -> (TINFLStatus, &'i [u8], usize) {
1674 let (status, in_pos, out_pos) =
1675 decompress(r, input_buffer, &mut Cursor::new(output_buffer), flags);
1676 (status, &input_buffer[in_pos..], out_pos)
1677 }
1678
1679 #[test]
1680 fn decompress_zlib() {
1681 let encoded = [
1682 120, 156, 243, 72, 205, 201, 201, 215, 81, 168, 202, 201, 76, 82, 4, 0, 27, 101, 4, 19,
1683 ];
1684 let flags = TINFL_FLAG_COMPUTE_ADLER32 | TINFL_FLAG_PARSE_ZLIB_HEADER;
1685
1686 let mut b = DecompressorOxide::new();
1687 const LEN: usize = 32;
1688 let mut b_buf = vec![0; LEN];
1689
1690 let b_status = tinfl_decompress_oxide(&mut b, &encoded[..], b_buf.as_mut_slice(), flags);
1692
1693 assert_eq!(b_status.0, TINFLStatus::Failed);
1694
1695 let flags = flags | TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF;
1696
1697 b = DecompressorOxide::new();
1698
1699 let b_status = tinfl_decompress_oxide(&mut b, &encoded[..], b_buf.as_mut_slice(), flags);
1701
1702 assert_eq!(b_buf[..b_status.2], b"Hello, zlib!"[..]);
1703 assert_eq!(b_status.0, TINFLStatus::Done);
1704 }
1705
1706 #[test]
1707 fn raw_block() {
1708 const LEN: usize = 64;
1709
1710 let text = b"Hello, zlib!";
1711 let encoded = {
1712 let len = text.len();
1713 let notlen = !len;
1714 let mut encoded = vec![
1715 1,
1716 len as u8,
1717 (len >> 8) as u8,
1718 notlen as u8,
1719 (notlen >> 8) as u8,
1720 ];
1721 encoded.extend_from_slice(&text[..]);
1722 encoded
1723 };
1724
1725 let flags = TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF;
1727
1728 let mut b = DecompressorOxide::new();
1729
1730 let mut b_buf = vec![0; LEN];
1731
1732 let b_status = tinfl_decompress_oxide(&mut b, &encoded[..], b_buf.as_mut_slice(), flags);
1733 assert_eq!(b_buf[..b_status.2], text[..]);
1734 assert_eq!(b_status.0, TINFLStatus::Done);
1735 }
1736
1737 fn masked_lookup(table: &HuffmanTable, bit_buf: BitBuffer) -> (i32, u32) {
1738 let ret = table.lookup(bit_buf).unwrap();
1739 (ret.0 & 511, ret.1)
1740 }
1741
1742 #[test]
1743 fn fixed_table_lookup() {
1744 let mut d = DecompressorOxide::new();
1745 d.block_type = 1;
1746 start_static_table(&mut d);
1747 let mut l = LocalVars {
1748 bit_buf: d.bit_buf,
1749 num_bits: d.num_bits,
1750 dist: d.dist,
1751 counter: d.counter,
1752 num_extra: d.num_extra,
1753 };
1754 init_tree(&mut d, &mut l);
1755 let llt = &d.tables[LITLEN_TABLE];
1756 let dt = &d.tables[DIST_TABLE];
1757 assert_eq!(masked_lookup(llt, 0b00001100), (0, 8));
1758 assert_eq!(masked_lookup(llt, 0b00011110), (72, 8));
1759 assert_eq!(masked_lookup(llt, 0b01011110), (74, 8));
1760 assert_eq!(masked_lookup(llt, 0b11111101), (143, 8));
1761 assert_eq!(masked_lookup(llt, 0b000010011), (144, 9));
1762 assert_eq!(masked_lookup(llt, 0b111111111), (255, 9));
1763 assert_eq!(masked_lookup(llt, 0b00000000), (256, 7));
1764 assert_eq!(masked_lookup(llt, 0b1110100), (279, 7));
1765 assert_eq!(masked_lookup(llt, 0b00000011), (280, 8));
1766 assert_eq!(masked_lookup(llt, 0b11100011), (287, 8));
1767
1768 assert_eq!(masked_lookup(dt, 0), (0, 5));
1769 assert_eq!(masked_lookup(dt, 20), (5, 5));
1770 }
1771
1772 fn check_result(input: &[u8], expected_status: TINFLStatus, expected_state: State, zlib: bool) {
1773 let mut r = DecompressorOxide::default();
1774 let mut output_buf = vec![0; 1024 * 32];
1775 let mut out_cursor = Cursor::new(output_buf.as_mut_slice());
1776 let flags = if zlib {
1777 inflate_flags::TINFL_FLAG_PARSE_ZLIB_HEADER
1778 } else {
1779 0
1780 } | TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF
1781 | TINFL_FLAG_HAS_MORE_INPUT;
1782 let (d_status, _in_bytes, _out_bytes) = decompress(&mut r, input, &mut out_cursor, flags);
1783 assert_eq!(expected_status, d_status);
1784 assert_eq!(expected_state, r.state);
1785 }
1786
1787 #[test]
1788 fn bogus_input() {
1789 use self::check_result as cr;
1790 const F: TINFLStatus = TINFLStatus::Failed;
1791 const OK: TINFLStatus = TINFLStatus::Done;
1792 cr(&[0x77, 0x85], F, State::BadZlibHeader, true);
1794 cr(&[0x88, 0x98], F, State::BadZlibHeader, true);
1796 cr(&[0x78, 0x98], F, State::BadZlibHeader, true);
1798
1799 cr(
1801 b"M\xff\xffM*\xad\xad\xad\xad\xad\xad\xad\xcd\xcd\xcdM",
1802 F,
1803 State::BadTotalSymbols,
1804 false,
1805 );
1806 cr(
1808 b"\xdd\xff\xff*M\x94ffffffffff",
1809 F,
1810 State::BadTotalSymbols,
1811 false,
1812 );
1813
1814 let c = |a, b, c| cr(a, b, c, false);
1817
1818 c(&[0, 0, 0, 0, 0], F, State::BadRawLength);
1820 c(&[3, 0], OK, State::DoneForever);
1822 c(&[6], F, State::BlockTypeUnexpected);
1824 c(&[1, 1, 0, 0xfe, 0xff, 0], OK, State::DoneForever);
1826 c(&[4, 0, 0xfe, 0xff], F, State::BadTotalSymbols);
1831 c(&[4, 0, 0x24, 0x49, 0], F, State::BadCodeSizeDistPrevLookup);
1834 c(
1838 &[
1839 4, 0x80, 0x49, 0x92, 0x24, 0x49, 0x92, 0x24, 0x71, 0xff, 0xff, 0x93, 0x11, 0,
1840 ],
1841 F,
1842 State::BadTotalSymbols,
1843 );
1844 c(&[2, 0x7e, 0xff, 0xff], F, State::InvalidDist);
1848
1849 c(
1851 &[0x0c, 0xc0, 0x81, 0, 0, 0, 0, 0, 0x90, 0xff, 0x6b, 0x4, 0],
1852 F,
1853 State::DistanceOutOfBounds,
1854 );
1855
1856 }
1862
1863 #[test]
1864 fn empty_output_buffer_non_wrapping() {
1865 let encoded = [
1866 120, 156, 243, 72, 205, 201, 201, 215, 81, 168, 202, 201, 76, 82, 4, 0, 27, 101, 4, 19,
1867 ];
1868 let flags = TINFL_FLAG_COMPUTE_ADLER32
1869 | TINFL_FLAG_PARSE_ZLIB_HEADER
1870 | TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF;
1871 let mut r = DecompressorOxide::new();
1872 let mut output_buf = vec![];
1873 let mut out_cursor = Cursor::new(output_buf.as_mut_slice());
1874 let res = decompress(&mut r, &encoded, &mut out_cursor, flags);
1877 assert_eq!(res, (TINFLStatus::HasMoreOutput, 4, 0));
1878 }
1879
1880 #[test]
1881 fn empty_output_buffer_wrapping() {
1882 let encoded = [
1883 0x73, 0x49, 0x4d, 0xcb, 0x49, 0x2c, 0x49, 0x55, 0x00, 0x11, 0x00,
1884 ];
1885 let flags = TINFL_FLAG_COMPUTE_ADLER32;
1886 let mut r = DecompressorOxide::new();
1887 let mut output_buf = vec![];
1888 let mut out_cursor = Cursor::new(output_buf.as_mut_slice());
1889 let res = decompress(&mut r, &encoded, &mut out_cursor, flags);
1892 assert_eq!(res, (TINFLStatus::HasMoreOutput, 2, 0));
1893 }
1894}