lz4_compression/
decompress.rs

1//! The decompression algorithm.
2
3use std::convert::TryInto;
4
5#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)]
6pub enum Error {
7    /// Expected more bytes, but found none
8    UnexpectedEnd,
9
10    /// The offset for a deduplication is out of bounds
11    InvalidDeduplicationOffset,
12}
13
14/// An LZ4 decoder.
15///
16/// This will decode in accordance to the LZ4 format. It represents a particular state of the
17/// decompressor.
18struct Decoder<'a> {
19
20    /// The compressed input.
21    input: &'a [u8],
22
23    /// The decompressed output.
24    output: &'a mut Vec<u8>,
25
26    /// The current block's "token".
27    ///
28    /// This token contains to 4-bit "fields", a higher and a lower, representing the literals'
29    /// length and the back reference's length, respectively. LSIC is used if either are their
30    /// maximal values.
31    token: u8,
32}
33
34impl<'a> Decoder<'a> {
35    /// Internal (partial) function for `take`.
36    #[inline]
37    fn take_imp(input: &mut &'a [u8], n: usize) -> Result<&'a [u8], Error> {
38        // Check if we have enough bytes left.
39        if input.len() < n {
40            // No extra bytes. This is clearly not expected, so we return an error.
41            Err(Error::UnexpectedEnd)
42        }
43        else {
44            // Take the first n bytes.
45            let res = Ok(&input[..n]);
46
47            // Shift the stream to left, so that it is no longer the first byte.
48            *input = &input[n..];
49
50            // Return the former first byte.
51            res
52        }
53    }
54
55    /// Pop n bytes from the start of the input stream.
56    fn take(&mut self, n: usize) -> Result<&[u8], Error> {
57        Self::take_imp(&mut self.input, n)
58    }
59
60    /// Write a buffer to the output stream.
61    ///
62    /// The reason this doesn't take `&mut self` is that we need partial borrowing due to the rules
63    /// of the borrow checker. For this reason, we instead take some number of segregated
64    /// references so we can read and write them independently.
65    fn output(output: &mut Vec<u8>, buf: &[u8]) {
66        // We use simple memcpy to extend the vector.
67        output.extend_from_slice(&buf[..buf.len()]);
68    }
69
70    /// Write an already decompressed match to the output stream.
71    ///
72    /// This is used for the essential part of the algorithm: deduplication. We start at some
73    /// position `start` and then keep pushing the following element until we've added
74    /// `match_length` elements.
75    fn duplicate(&mut self, start: usize, match_length: usize) {
76        // We cannot simply use memcpy or `extend_from_slice`, because these do not allow
77        // self-referential copies: http://ticki.github.io/img/lz4_runs_encoding_diagram.svg
78        for i in start..start + match_length {
79            let b = self.output[i];
80            self.output.push(b);
81        }
82    }
83
84    /// Read an integer LSIC (linear small integer code) encoded.
85    ///
86    /// In LZ4, we encode small integers in a way that we can have an arbitrary number of bytes. In
87    /// particular, we add the bytes repeatedly until we hit a non-0xFF byte. When we do, we add
88    /// this byte to our sum and terminate the loop.
89    ///
90    /// # Example
91    ///
92    /// ```notest
93    ///     255, 255, 255, 4, 2, 3, 4, 6, 7
94    /// ```
95    ///
96    /// is encoded to _255 + 255 + 255 + 4 = 769_. The bytes after the first 4 is ignored, because
97    /// 4 is the first non-0xFF byte.
98    #[inline]
99    fn read_integer(&mut self) -> Result<usize, Error> {
100        // We start at zero and count upwards.
101        let mut n = 0;
102
103        // If this byte takes value 255 (the maximum value it can take), another byte is read
104        // and added to the sum. This repeats until a byte lower than 255 is read.
105        while {
106            // We add the next byte until we get a byte which we add to the counting variable.
107            let extra = self.take(1)?[0];
108            n += extra as usize;
109
110            // We continue if we got 255.
111            extra == 0xFF
112        } {}
113
114        Ok(n)
115    }
116
117    /// Read a little-endian 16-bit integer from the input stream.
118    #[inline]
119    fn read_u16(&mut self) -> Result<u16, Error> {
120        // Read a u16 in little endian.
121        let bytes = self.take(2)?;
122        Ok(u16::from_le_bytes(bytes.try_into().unwrap()))
123    }
124
125    /// Read the literals section of a block.
126    ///
127    /// The literals section encodes some bytes which are to be copied to the output without any
128    /// modification.
129    ///
130    /// It consists of two parts:
131    ///
132    /// 1. An LSIC integer extension to the literals length as defined by the first part of the
133    ///    token, if it takes the highest value (15).
134    /// 2. The literals themself.
135    fn read_literal_section(&mut self) -> Result<(), Error> {
136        // The higher token is the literals part of the token. It takes a value from 0 to 15.
137        let mut literal = (self.token >> 4) as usize;
138
139        // If the initial value is 15, it is indicated that another byte will be read and added to
140        // it.
141        if literal == 15 {
142            // The literal length took the maximal value, indicating that there is more than 15
143            // literal bytes. We read the extra integer.
144            literal += self.read_integer()?;
145        }
146
147        // Now we know the literal length. The number will be used to indicate how long the
148        // following literal copied to the output buffer is.
149
150        // Read the literals segment and output them without processing.
151        Self::output(&mut self.output, Self::take_imp(&mut self.input, literal)?);
152
153        Ok(())
154    }
155
156    /// Read the duplicates section of the block.
157    ///
158    /// The duplicates section serves to reference an already decoded segment. This consists of two
159    /// parts:
160    ///
161    /// 1. A 16-bit little-endian integer defining the "offset", i.e. how long back we need to go
162    ///    in the decoded buffer and copy.
163    /// 2. An LSIC integer extension to the duplicate length as defined by the first part of the
164    ///    token, if it takes the highest value (15).
165    fn read_duplicate_section(&mut self) -> Result<(), Error> {
166        // Now, we will obtain the offset which we will use to copy from the output. It is an
167        // 16-bit integer.
168        let offset = self.read_u16()?;
169
170        // Obtain the initial match length. The match length is the length of the duplicate segment
171        // which will later be copied from data previously decompressed into the output buffer. The
172        // initial length is derived from the second part of the token (the lower nibble), we read
173        // earlier. Since having a match length of less than 4 would mean negative compression
174        // ratio, we start at 4.
175        let mut match_length = (4 + (self.token & 0xF)) as usize;
176
177        // The intial match length can maximally be 19. As with the literal length, this indicates
178        // that there are more bytes to read.
179        if match_length == 4 + 15 {
180            // The match length took the maximal value, indicating that there is more bytes. We
181            // read the extra integer.
182            match_length += self.read_integer()?;
183        }
184
185        // We now copy from the already decompressed buffer. This allows us for storing duplicates
186        // by simply referencing the other location.
187
188        // Calculate the start of this duplicate segment. We use wrapping subtraction to avoid
189        // overflow checks, which we will catch later.
190        let start = self.output.len().wrapping_sub(offset as usize);
191
192        // We'll do a bound check to avoid panicking.
193        if start < self.output.len() {
194            // Write the duplicate segment to the output buffer.
195            self.duplicate(start, match_length);
196
197            Ok(())
198        }
199        else {
200            Err(Error::InvalidDeduplicationOffset)
201        }
202    }
203
204    /// Complete the decompression by reading all the blocks.
205    ///
206    /// # Decompressing a block
207    ///
208    /// Blocks consists of:
209    ///  - A 1 byte token
210    ///      * A 4 bit integer $t_1$.
211    ///      * A 4 bit integer $t_2$.
212    ///  - A $n$ byte sequence of 0xFF bytes (if $t_1 \neq 15$, then $n = 0$).
213    ///  - $x$ non-0xFF 8-bit integers, L (if $t_1 = 15$, $x = 1$, else $x = 0$).
214    ///  - $t_1 + 15n + L$ bytes of uncompressed data (literals).
215    ///  - 16-bits offset (little endian), $a$.
216    ///  - A $m$ byte sequence of 0xFF bytes (if $t_2 \neq 15$, then $m = 0$).
217    ///  - $y$ non-0xFF 8-bit integers, $c$ (if $t_2 = 15$, $y = 1$, else $y = 0$).
218    ///
219    /// First, the literals are copied directly and unprocessed to the output buffer, then (after
220    /// the involved parameters are read) $t_2 + 15m + c$ bytes are copied from the output buffer
221    /// at position $a + 4$ and appended to the output buffer. Note that this copy can be
222    /// overlapping.
223    #[inline]
224    fn complete(&mut self) -> Result<(), Error> {
225        // Exhaust the decoder by reading and decompressing all blocks until the remaining buffer
226        // is empty.
227        while !self.input.is_empty() {
228            // Read the token. The token is the first byte in a block. It is divided into two 4-bit
229            // subtokens, the higher and the lower.
230            self.token = self.take(1)?[0];
231
232            // Now, we read the literals section.
233            self.read_literal_section()?;
234
235            // If the input stream is emptied, we break out of the loop. This is only the case
236            // in the end of the stream, since the block is intact otherwise.
237            if self.input.is_empty() { break; }
238
239            // Now, we read the duplicates section.
240            self.read_duplicate_section()?;
241        }
242
243        Ok(())
244    }
245}
246
247/// Decompress all bytes of `input` into `output`.
248pub fn decompress_into(input: &[u8], output: &mut Vec<u8>) -> Result<(), Error> {
249    // Decode into our vector.
250    Decoder {
251        input,
252        output,
253        token: 0,
254    }.complete()?;
255
256    Ok(())
257}
258
259/// Decompress all bytes of `input`.
260pub fn decompress(input: &[u8]) -> Result<Vec<u8>, Error> {
261    // Allocate a vector to contain the decompressed stream.
262    let mut vec = Vec::with_capacity(4096);
263
264    decompress_into(input, &mut vec)?;
265
266    Ok(vec)
267}
268
269#[cfg(test)]
270mod test {
271    use super::*;
272
273    #[test]
274    fn aaaaaaaaaaa_lots_of_aaaaaaaaa() {
275        assert_eq!(decompress(&[0x11, b'a', 1, 0]).unwrap(), b"aaaaaa");
276    }
277
278    #[test]
279    fn multiple_repeated_blocks() {
280        assert_eq!(decompress(&[0x11, b'a', 1, 0, 0x22, b'b', b'c', 2, 0]).unwrap(), b"aaaaaabcbcbcbc");
281    }
282
283    #[test]
284    fn all_literal() {
285        assert_eq!(decompress(&[0x30, b'a', b'4', b'9']).unwrap(), b"a49");
286    }
287
288    #[test]
289    fn offset_oob() {
290        decompress(&[0x10, b'a', 2, 0]).unwrap_err();
291        decompress(&[0x40, b'a', 1, 0]).unwrap_err();
292    }
293}