deflate64/
lib.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
//! Deflate64 implementation based on [.NET System.IO.Compression][dotnet].
//!
//! This is made to unzip zip file with deflate64 made with windows 11.
//!
//! [dotnet]: https://github.com/dotnet/runtime/tree/e5efd8010e19593298dc2c3ee15106d5aec5a924/src/libraries/System.IO.Compression/src/System/IO/Compression/DeflateManaged

#![forbid(unsafe_code)]
#![deny(rust_2018_idioms, nonstandard_style, future_incompatible)]

mod huffman_tree;
mod inflater_managed;
mod input_buffer;
mod output_window;
mod stream;

pub use inflater_managed::InflaterManaged;
pub use stream::Deflate64Decoder;

#[derive(Debug, Copy, Clone, Eq, PartialEq)]
enum BlockType {
    Uncompressed = 0,
    Static = 1,
    Dynamic = 2,
}

impl BlockType {
    pub fn from_int(int: u16) -> Option<BlockType> {
        match int {
            0 => Some(Self::Uncompressed),
            1 => Some(Self::Static),
            2 => Some(Self::Dynamic),
            _ => None,
        }
    }
}

#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd)]
enum InflaterState {
    //ReadingHeader = 0,           // Only applies to GZIP
    ReadingBFinal = 2,
    // About to read bfinal bit
    ReadingBType = 3, // About to read blockType bits

    ReadingNumLitCodes = 4,
    // About to read # literal codes
    ReadingNumDistCodes = 5,
    // About to read # dist codes
    ReadingNumCodeLengthCodes = 6,
    // About to read # code length codes
    ReadingCodeLengthCodes = 7,
    // In the middle of reading the code length codes
    ReadingTreeCodesBefore = 8,
    // In the middle of reading tree codes (loop top)
    ReadingTreeCodesAfter = 9, // In the middle of reading tree codes (extension; code > 15)

    DecodeTop = 10,
    // About to decode a literal (char/match) in a compressed block
    HaveInitialLength = 11,
    // Decoding a match, have the literal code (base length)
    HaveFullLength = 12,
    // Ditto, now have the full match length (incl. extra length bits)
    HaveDistCode = 13, // Ditto, now have the distance code also, need extra dist bits

    /* uncompressed blocks */
    UncompressedAligning = 15,
    UncompressedByte1 = 16,
    UncompressedByte2 = 17,
    UncompressedByte3 = 18,
    UncompressedByte4 = 19,
    DecodingUncompressed = 20,

    // These three apply only to GZIP
    //StartReadingFooter = 21,
    // (Initialisation for reading footer)
    //ReadingFooter = 22,
    //VerifyingFooter = 23,
    Done = 24, // Finished

    DataErrored = 100,
}

impl std::ops::Sub for InflaterState {
    type Output = u8;

    fn sub(self, rhs: Self) -> Self::Output {
        self as u8 - rhs as u8
    }
}

fn array_copy<T: Copy>(source: &[T], dst: &mut [T], length: usize) {
    dst[..length].copy_from_slice(&source[..length]);
}

fn array_copy1<T: Copy>(
    source: &[T],
    source_index: usize,
    dst: &mut [T],
    dst_index: usize,
    length: usize,
) {
    dst[dst_index..][..length].copy_from_slice(&source[source_index..][..length]);
}

/// A structure containing result of streaming inflate.
#[derive(Debug)]
pub struct InflateResult {
    /// The number of bytes consumed from the input slice.
    pub bytes_consumed: usize,
    /// The number of bytes written to the output slice.
    pub bytes_written: usize,
    /// true if there is error in input buffer
    pub data_error: bool,
}

impl InflateResult {
    /// Creates `InflateResult` with zero bytes consumed and written, and no error.
    #[allow(clippy::new_without_default)]
    pub fn new() -> Self {
        Self {
            bytes_consumed: 0,
            bytes_written: 0,
            data_error: false,
        }
    }
}

#[derive(Debug)]
enum InternalErr {
    DataNeeded,
    DataError,
}