Coverage Report

Created: 2025-07-04 06:57

/rust/registry/src/index.crates.io-6f17d22bba15001f/zune-inflate-0.2.54/src/encoder.rs
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Copyright (c) 2023.
3
 *
4
 * This software is free software; You can redistribute it or modify it under terms of the MIT, Apache License or Zlib license
5
 */
6
7
use alloc::vec;
8
use alloc::vec::Vec;
9
10
use crate::constants::DEFLATE_BLOCKTYPE_UNCOMPRESSED;
11
12
mod fast_match_finder;
13
14
const _SEQ_LENGTH_SHIFT: u32 = 23;
15
16
const _SEQ_LITRUNLEN_MASK: u32 = (1_u32 << _SEQ_LENGTH_SHIFT) - 1;
17
18
pub(crate) struct _Sequence
19
{
20
    /*
21
     * Bits 0..22: the number of literals in this run.  This may be 0 and
22
     * can be at most MAX_BLOCK_LENGTH.  The literals are not stored
23
     * explicitly in this structure; instead, they are read directly from
24
     * the uncompressed data.
25
     *
26
     * Bits 23..31: the length of the match which follows the literals, or 0
27
     * if this literal run was the last in the block, so there is no match
28
     * which follows it.
29
     */
30
    litrunlen_and_length: u32
31
}
32
33
#[derive(Debug, Copy, Clone)]
34
pub enum DeflateEncodingStrategy
35
{
36
    NoCompression
37
}
38
39
impl DeflateEncodingStrategy
40
{
41
    #[allow(dead_code)]
42
0
    fn to_level(self) -> u8
43
0
    {
44
0
        match self
45
0
        {
46
0
            Self::NoCompression => 0
47
0
        }
48
0
    }
49
}
50
51
pub struct DeflateEncodingOptions
52
{
53
    strategy: DeflateEncodingStrategy
54
}
55
56
impl Default for DeflateEncodingOptions
57
{
58
0
    fn default() -> Self
59
0
    {
60
0
        DeflateEncodingOptions {
61
0
            strategy: DeflateEncodingStrategy::NoCompression
62
0
        }
63
0
    }
64
}
65
66
/// A simple Deflate Encoder.
67
///
68
/// Not yet complete
69
pub struct DeflateEncoder<'a>
70
{
71
    data:            &'a [u8],
72
    options:         DeflateEncodingOptions,
73
    output_position: usize,
74
    input_position:  usize,
75
    output:          Vec<u8>
76
}
77
78
impl<'a> DeflateEncoder<'a>
79
{
80
    /// Create a new deflate encoder.
81
    ///
82
    /// The
83
0
    pub fn new(data: &'a [u8]) -> DeflateEncoder<'a>
84
0
    {
85
0
        DeflateEncoder::new_with_options(data, DeflateEncodingOptions::default())
86
0
    }
87
0
    pub fn new_with_options(data: &'a [u8], options: DeflateEncodingOptions) -> DeflateEncoder<'a>
88
0
    {
89
0
        let length = data.len() + 1024;
90
0
        let out_array = vec![0; length];
91
0
92
0
        DeflateEncoder {
93
0
            data,
94
0
            options,
95
0
            output_position: 0,
96
0
            input_position: 0,
97
0
            output: out_array
98
0
        }
99
0
    }
100
101
    #[cfg(feature = "zlib")]
102
0
    fn write_zlib_header(&mut self)
103
0
    {
104
        const ZLIB_CM_DEFLATE: u16 = 8;
105
        const ZLIB_CINFO_32K_WINDOW: u16 = 7;
106
107
0
        let level_hint = self.options.strategy.to_level();
108
0
109
0
        let mut hdr = (ZLIB_CM_DEFLATE << 8) | (ZLIB_CINFO_32K_WINDOW << 12);
110
0
111
0
        hdr |= u16::from(level_hint) << 6;
112
0
        hdr |= 31 - (hdr % 31);
113
0
114
0
        self.output[self.output_position..self.output_position + 2]
115
0
            .copy_from_slice(&hdr.to_be_bytes());
116
0
    }
117
    /// Encode a deflate data block with no compression
118
    ///
119
    /// # Argument
120
    /// - `bytes`: number of bytes to compress from input as non-compressed
121
    /// bytes
122
0
    fn encode_no_compression(&mut self, bytes: usize)
123
0
    {
124
0
        let final_position = self.input_position + bytes;
125
0
126
0
        /*
127
0
         * If the input is zero-length, we still must output a block in order
128
0
         * for the output to be a valid DEFLATE stream.  Handle this case
129
0
         * specially to avoid potentially passing NULL to memcpy() below.
130
0
         */
131
0
        if self.data.is_empty()
132
        {
133
            /* BFINAL and BTYPE */
134
0
            self.output[self.output_position] = (1 | (DEFLATE_BLOCKTYPE_UNCOMPRESSED << 1)) as u8;
135
0
            self.output_position += 1;
136
0
            /* LEN and NLEN */
137
0
            let num: u32 = 0xFFFF0000;
138
0
            self.output[self.output_position..self.output_position + 4]
139
0
                .copy_from_slice(&num.to_le_bytes());
140
0
            self.output_position += 4;
141
0
            return;
142
0
        }
143
        loop
144
        {
145
0
            let mut bfinal = 0;
146
0
            let mut len = usize::from(u16::MAX);
147
0
148
0
            if final_position - self.input_position <= usize::from(u16::MAX)
149
0
            {
150
0
                bfinal = 1;
151
0
                len = final_position - self.input_position;
152
0
            }
153
            /*
154
             * Output BFINAL and BTYPE.  The stream is already byte-aligned
155
             * here, so this step always requires outputting exactly 1 byte.
156
             */
157
0
            self.output[self.output_position] =
158
0
                (bfinal | (DEFLATE_BLOCKTYPE_UNCOMPRESSED << 1)) as u8;
159
0
160
0
            self.output_position += 1;
161
0
            // output len and nlen
162
0
            let len_u16 = len as u16;
163
0
164
0
            self.output[self.output_position..self.output_position + 2]
165
0
                .copy_from_slice(&len_u16.to_le_bytes());
166
0
            self.output_position += 2;
167
0
168
0
            self.output[self.output_position..self.output_position + 2]
169
0
                .copy_from_slice(&(!len_u16).to_le_bytes());
170
0
            self.output_position += 2;
171
0
172
0
            // copy from input to output
173
0
            self.output[self.output_position..self.output_position + len]
174
0
                .copy_from_slice(&self.data[self.input_position..self.input_position + len]);
175
0
            self.output_position += len;
176
0
            self.input_position += len;
177
0
178
0
            if self.input_position == final_position
179
            {
180
0
                break;
181
0
            }
182
        }
183
0
    }
184
185
    /// Encode a deflate stream
186
0
    pub fn encode_deflate(&mut self)
187
0
    {
188
0
        match self.options.strategy
189
0
        {
190
0
            DeflateEncodingStrategy::NoCompression =>
191
0
            {
192
0
                self.encode_no_compression(self.data.len());
193
0
            }
194
0
        }
195
0
    }
196
197
    #[cfg(feature = "zlib")]
198
0
    pub fn encode_zlib(&mut self) -> Vec<u8>
199
0
    {
200
0
        let extra = 40 * ((self.data.len() + 41) / 40);
201
0
        self.output = vec![0_u8; self.data.len() + extra];
202
0
        self.write_zlib_header();
203
0
        self.output_position = 2;
204
0
205
0
        self.encode_deflate();
206
0
207
0
        // add adler hash
208
0
        let hash = crate::utils::calc_adler_hash(self.data);
209
0
        self.output[self.output_position..self.output_position + 4]
210
0
            .copy_from_slice(&hash.to_be_bytes());
211
0
        self.output_position += 4;
212
0
213
0
        self.output.truncate(self.output_position);
214
0
215
0
        core::mem::take(&mut self.output)
216
0
    }
217
}