Coverage Report

Created: 2025-07-18 06:49

/rust/registry/src/index.crates.io-6f17d22bba15001f/fdeflate-0.3.7/src/compress.rs
Line
Count
Source (jump to first uncovered line)
1
use simd_adler32::Adler32;
2
use std::io::{self, Seek, SeekFrom, Write};
3
4
use crate::tables::{
5
    BITMASKS, HUFFMAN_CODES, HUFFMAN_LENGTHS, LENGTH_TO_LEN_EXTRA, LENGTH_TO_SYMBOL,
6
};
7
8
/// Compressor that produces fdeflate compressed streams.
9
pub struct Compressor<W: Write> {
10
    checksum: Adler32,
11
    buffer: u64,
12
    nbits: u8,
13
    writer: W,
14
}
15
impl<W: Write> Compressor<W> {
16
0
    fn write_bits(&mut self, bits: u64, nbits: u8) -> io::Result<()> {
17
0
        debug_assert!(nbits <= 64);
18
19
0
        self.buffer |= bits << self.nbits;
20
0
        self.nbits += nbits;
21
0
22
0
        if self.nbits >= 64 {
23
0
            self.writer.write_all(&self.buffer.to_le_bytes())?;
24
0
            self.nbits -= 64;
25
0
            self.buffer = bits.checked_shr((nbits - self.nbits) as u32).unwrap_or(0);
26
0
        }
27
0
        debug_assert!(self.nbits < 64);
28
0
        Ok(())
29
0
    }
Unexecuted instantiation: <fdeflate::compress::Compressor<std::io::cursor::Cursor<alloc::vec::Vec<u8>>>>::write_bits
Unexecuted instantiation: <fdeflate::compress::Compressor<alloc::vec::Vec<u8>>>::write_bits
30
31
0
    fn flush(&mut self) -> io::Result<()> {
32
0
        if self.nbits % 8 != 0 {
33
0
            self.write_bits(0, 8 - self.nbits % 8)?;
34
0
        }
35
0
        if self.nbits > 0 {
36
0
            self.writer
37
0
                .write_all(&self.buffer.to_le_bytes()[..self.nbits as usize / 8])
38
0
                .unwrap();
39
0
            self.buffer = 0;
40
0
            self.nbits = 0;
41
0
        }
42
0
        Ok(())
43
0
    }
Unexecuted instantiation: <fdeflate::compress::Compressor<std::io::cursor::Cursor<alloc::vec::Vec<u8>>>>::flush
Unexecuted instantiation: <fdeflate::compress::Compressor<alloc::vec::Vec<u8>>>::flush
44
45
0
    fn write_run(&mut self, mut run: u32) -> io::Result<()> {
46
0
        self.write_bits(HUFFMAN_CODES[0] as u64, HUFFMAN_LENGTHS[0])?;
47
0
        run -= 1;
48
49
0
        while run >= 258 {
50
0
            self.write_bits(HUFFMAN_CODES[285] as u64, HUFFMAN_LENGTHS[285] + 1)?;
51
0
            run -= 258;
52
        }
53
54
0
        if run > 4 {
55
0
            let sym = LENGTH_TO_SYMBOL[run as usize - 3] as usize;
56
0
            self.write_bits(HUFFMAN_CODES[sym] as u64, HUFFMAN_LENGTHS[sym])?;
57
58
0
            let len_extra = LENGTH_TO_LEN_EXTRA[run as usize - 3];
59
0
            let extra = ((run - 3) & BITMASKS[len_extra as usize]) as u64;
60
0
            self.write_bits(extra, len_extra + 1)?;
61
        } else {
62
0
            debug_assert_eq!(HUFFMAN_CODES[0], 0);
63
0
            self.write_bits(0, run as u8 * HUFFMAN_LENGTHS[0])?;
64
        }
65
66
0
        Ok(())
67
0
    }
Unexecuted instantiation: <fdeflate::compress::Compressor<std::io::cursor::Cursor<alloc::vec::Vec<u8>>>>::write_run
Unexecuted instantiation: <fdeflate::compress::Compressor<alloc::vec::Vec<u8>>>::write_run
68
69
    /// Create a new Compressor.
70
0
    pub fn new(writer: W) -> io::Result<Self> {
71
0
        let mut compressor = Self {
72
0
            checksum: Adler32::new(),
73
0
            buffer: 0,
74
0
            nbits: 0,
75
0
            writer,
76
0
        };
77
0
        compressor.write_headers()?;
78
0
        Ok(compressor)
79
0
    }
Unexecuted instantiation: <fdeflate::compress::Compressor<std::io::cursor::Cursor<alloc::vec::Vec<u8>>>>::new
Unexecuted instantiation: <fdeflate::compress::Compressor<alloc::vec::Vec<u8>>>::new
80
81
0
    fn write_headers(&mut self) -> io::Result<()> {
82
        const HEADER: [u8; 54] = [
83
            120, 1, 237, 192, 3, 160, 36, 89, 150, 198, 241, 255, 119, 238, 141, 200, 204, 167,
84
            114, 75, 99, 174, 109, 219, 182, 109, 219, 182, 109, 219, 182, 109, 105, 140, 158, 150,
85
            74, 175, 158, 50, 51, 34, 238, 249, 118, 183, 106, 122, 166, 135, 59, 107, 213, 15,
86
        ];
87
0
        self.writer.write_all(&HEADER[..53]).unwrap();
88
0
        self.write_bits(HEADER[53] as u64, 5)?;
89
90
0
        Ok(())
91
0
    }
Unexecuted instantiation: <fdeflate::compress::Compressor<std::io::cursor::Cursor<alloc::vec::Vec<u8>>>>::write_headers
Unexecuted instantiation: <fdeflate::compress::Compressor<alloc::vec::Vec<u8>>>::write_headers
92
93
    /// Write data to the compressor.
94
0
    pub fn write_data(&mut self, data: &[u8]) -> io::Result<()> {
95
0
        self.checksum.write(data);
96
0
97
0
        let mut run = 0;
98
0
        let mut chunks = data.chunks_exact(8);
99
0
        for chunk in &mut chunks {
100
0
            let ichunk = u64::from_le_bytes(chunk.try_into().unwrap());
101
0
102
0
            if ichunk == 0 {
103
0
                run += 8;
104
0
                continue;
105
0
            } else if run > 0 {
106
0
                let run_extra = ichunk.trailing_zeros() / 8;
107
0
                self.write_run(run + run_extra)?;
108
0
                run = 0;
109
0
110
0
                if run_extra > 0 {
111
0
                    run = ichunk.leading_zeros() / 8;
112
0
                    for &b in &chunk[run_extra as usize..8 - run as usize] {
113
0
                        self.write_bits(
114
0
                            HUFFMAN_CODES[b as usize] as u64,
115
0
                            HUFFMAN_LENGTHS[b as usize],
116
0
                        )?;
117
                    }
118
0
                    continue;
119
0
                }
120
0
            }
121
122
0
            let run_start = ichunk.leading_zeros() / 8;
123
0
            if run_start > 0 {
124
0
                for &b in &chunk[..8 - run_start as usize] {
125
0
                    self.write_bits(
126
0
                        HUFFMAN_CODES[b as usize] as u64,
127
0
                        HUFFMAN_LENGTHS[b as usize],
128
0
                    )?;
129
                }
130
0
                run = run_start;
131
0
                continue;
132
0
            }
133
0
134
0
            let n0 = HUFFMAN_LENGTHS[chunk[0] as usize];
135
0
            let n1 = HUFFMAN_LENGTHS[chunk[1] as usize];
136
0
            let n2 = HUFFMAN_LENGTHS[chunk[2] as usize];
137
0
            let n3 = HUFFMAN_LENGTHS[chunk[3] as usize];
138
0
            let bits = HUFFMAN_CODES[chunk[0] as usize] as u64
139
0
                | ((HUFFMAN_CODES[chunk[1] as usize] as u64) << n0)
140
0
                | ((HUFFMAN_CODES[chunk[2] as usize] as u64) << (n0 + n1))
141
0
                | ((HUFFMAN_CODES[chunk[3] as usize] as u64) << (n0 + n1 + n2));
142
0
            self.write_bits(bits, n0 + n1 + n2 + n3)?;
143
144
0
            let n4 = HUFFMAN_LENGTHS[chunk[4] as usize];
145
0
            let n5 = HUFFMAN_LENGTHS[chunk[5] as usize];
146
0
            let n6 = HUFFMAN_LENGTHS[chunk[6] as usize];
147
0
            let n7 = HUFFMAN_LENGTHS[chunk[7] as usize];
148
0
            let bits2 = HUFFMAN_CODES[chunk[4] as usize] as u64
149
0
                | ((HUFFMAN_CODES[chunk[5] as usize] as u64) << n4)
150
0
                | ((HUFFMAN_CODES[chunk[6] as usize] as u64) << (n4 + n5))
151
0
                | ((HUFFMAN_CODES[chunk[7] as usize] as u64) << (n4 + n5 + n6));
152
0
            self.write_bits(bits2, n4 + n5 + n6 + n7)?;
153
        }
154
155
0
        if run > 0 {
156
0
            self.write_run(run)?;
157
0
        }
158
159
0
        for &b in chunks.remainder() {
160
0
            self.write_bits(
161
0
                HUFFMAN_CODES[b as usize] as u64,
162
0
                HUFFMAN_LENGTHS[b as usize],
163
0
            )?;
164
        }
165
166
0
        Ok(())
167
0
    }
Unexecuted instantiation: <fdeflate::compress::Compressor<std::io::cursor::Cursor<alloc::vec::Vec<u8>>>>::write_data
Unexecuted instantiation: <fdeflate::compress::Compressor<alloc::vec::Vec<u8>>>::write_data
168
169
    /// Write the remainder of the stream and return the inner writer.
170
0
    pub fn finish(mut self) -> io::Result<W> {
171
0
        // Write end of block
172
0
        self.write_bits(HUFFMAN_CODES[256] as u64, HUFFMAN_LENGTHS[256])?;
173
0
        self.flush()?;
174
175
        // Write Adler32 checksum
176
0
        let checksum: u32 = self.checksum.finish();
177
0
        self.writer
178
0
            .write_all(checksum.to_be_bytes().as_ref())
179
0
            .unwrap();
180
0
        Ok(self.writer)
181
0
    }
Unexecuted instantiation: <fdeflate::compress::Compressor<std::io::cursor::Cursor<alloc::vec::Vec<u8>>>>::finish
Unexecuted instantiation: <fdeflate::compress::Compressor<alloc::vec::Vec<u8>>>::finish
182
}
183
184
/// Compressor that only writes the stored blocks.
185
///
186
/// This is useful for writing files that are not compressed, but still need to be wrapped in a
187
/// zlib stream.
188
pub struct StoredOnlyCompressor<W> {
189
    writer: W,
190
    checksum: Adler32,
191
    block_bytes: u16,
192
}
193
impl<W: Write + Seek> StoredOnlyCompressor<W> {
194
    /// Creates a new `StoredOnlyCompressor` that writes to the given writer.
195
0
    pub fn new(mut writer: W) -> io::Result<Self> {
196
0
        writer.write_all(&[0x78, 0x01])?; // zlib header
197
0
        writer.write_all(&[0; 5])?; // placeholder stored block header
198
199
0
        Ok(Self {
200
0
            writer,
201
0
            checksum: Adler32::new(),
202
0
            block_bytes: 0,
203
0
        })
204
0
    }
Unexecuted instantiation: <fdeflate::compress::StoredOnlyCompressor<std::io::cursor::Cursor<alloc::vec::Vec<u8>>>>::new
Unexecuted instantiation: <fdeflate::compress::StoredOnlyCompressor<_>>::new
205
206
0
    fn set_block_header(&mut self, size: u16, last: bool) -> io::Result<()> {
207
0
        self.writer.seek(SeekFrom::Current(-(size as i64 + 5)))?;
208
0
        self.writer.write_all(&[
209
0
            last as u8,
210
0
            (size & 0xFF) as u8,
211
0
            ((size >> 8) & 0xFF) as u8,
212
0
            (!size & 0xFF) as u8,
213
0
            ((!size >> 8) & 0xFF) as u8,
214
0
        ])?;
215
0
        self.writer.seek(SeekFrom::Current(size as i64))?;
216
217
0
        Ok(())
218
0
    }
Unexecuted instantiation: <fdeflate::compress::StoredOnlyCompressor<std::io::cursor::Cursor<alloc::vec::Vec<u8>>>>::set_block_header
Unexecuted instantiation: <fdeflate::compress::StoredOnlyCompressor<_>>::set_block_header
219
220
    /// Writes the given data to the underlying writer.
221
0
    pub fn write_data(&mut self, mut data: &[u8]) -> io::Result<()> {
222
0
        self.checksum.write(data);
223
0
        while !data.is_empty() {
224
0
            if self.block_bytes == u16::MAX {
225
0
                self.set_block_header(u16::MAX, false)?;
226
0
                self.writer.write_all(&[0; 5])?; // placeholder stored block header
227
0
                self.block_bytes = 0;
228
0
            }
229
230
0
            let prefix_bytes = data.len().min((u16::MAX - self.block_bytes) as usize);
231
0
            self.writer.write_all(&data[..prefix_bytes])?;
232
0
            self.block_bytes += prefix_bytes as u16;
233
0
            data = &data[prefix_bytes..];
234
        }
235
236
0
        Ok(())
237
0
    }
Unexecuted instantiation: <fdeflate::compress::StoredOnlyCompressor<std::io::cursor::Cursor<alloc::vec::Vec<u8>>>>::write_data
Unexecuted instantiation: <fdeflate::compress::StoredOnlyCompressor<_>>::write_data
238
239
    /// Finish writing the final block and return the underlying writer.
240
0
    pub fn finish(mut self) -> io::Result<W> {
241
0
        self.set_block_header(self.block_bytes, true)?;
242
243
        // Write Adler32 checksum
244
0
        let checksum: u32 = self.checksum.finish();
245
0
        self.writer
246
0
            .write_all(checksum.to_be_bytes().as_ref())
247
0
            .unwrap();
248
0
249
0
        Ok(self.writer)
250
0
    }
Unexecuted instantiation: <fdeflate::compress::StoredOnlyCompressor<std::io::cursor::Cursor<alloc::vec::Vec<u8>>>>::finish
Unexecuted instantiation: <fdeflate::compress::StoredOnlyCompressor<_>>::finish
251
}
252
impl<W> StoredOnlyCompressor<W> {
253
    /// Return the number of bytes that will be written to the output stream
254
    /// for the given input size. Because this compressor only writes stored blocks,
255
    /// the output size is always slightly *larger* than the input size.
256
0
    pub fn compressed_size(raw_size: usize) -> usize {
257
0
        (raw_size.saturating_sub(1) / u16::MAX as usize) * (u16::MAX as usize + 5)
258
0
            + (raw_size % u16::MAX as usize + 5)
259
0
            + 6
260
0
    }
Unexecuted instantiation: <fdeflate::compress::StoredOnlyCompressor<()>>::compressed_size
Unexecuted instantiation: <fdeflate::compress::StoredOnlyCompressor<_>>::compressed_size
261
}
262
263
/// Compresses the given data.
264
0
pub fn compress_to_vec(input: &[u8]) -> Vec<u8> {
265
0
    let mut compressor = Compressor::new(Vec::with_capacity(input.len() / 4)).unwrap();
266
0
    compressor.write_data(input).unwrap();
267
0
    compressor.finish().unwrap()
268
0
}
269
270
#[cfg(test)]
271
mod tests {
272
    use super::*;
273
    use rand::Rng;
274
275
    fn roundtrip(data: &[u8]) {
276
        let compressed = compress_to_vec(data);
277
        let decompressed = miniz_oxide::inflate::decompress_to_vec_zlib(&compressed).unwrap();
278
        assert_eq!(&decompressed, data);
279
    }
280
281
    #[test]
282
    fn it_works() {
283
        roundtrip(b"Hello world!");
284
    }
285
286
    #[test]
287
    fn constant() {
288
        roundtrip(&vec![0; 2048]);
289
        roundtrip(&vec![5; 2048]);
290
        roundtrip(&vec![128; 2048]);
291
        roundtrip(&vec![254; 2048]);
292
    }
293
294
    #[test]
295
    fn random() {
296
        let mut rng = rand::thread_rng();
297
        let mut data = vec![0; 2048];
298
        for _ in 0..10 {
299
            for byte in &mut data {
300
                *byte = rng.gen();
301
            }
302
            roundtrip(&data);
303
        }
304
    }
305
}