snap/decompress.rs
1use std::ptr;
2
3use crate::bytes;
4use crate::error::{Error, Result};
5use crate::tag;
6use crate::MAX_INPUT_SIZE;
7
8/// A lookup table for quickly computing the various attributes derived from a
9/// tag byte.
10const TAG_LOOKUP_TABLE: TagLookupTable = TagLookupTable(tag::TAG_LOOKUP_TABLE);
11
12/// `WORD_MASK` is a map from the size of an integer in bytes to its
13/// corresponding on a 32 bit integer. This is used when we need to read an
14/// integer and we know there are at least 4 bytes to read from a buffer. In
15/// this case, we can read a 32 bit little endian integer and mask out only the
16/// bits we need. This in particular saves a branch.
17const WORD_MASK: [usize; 5] = [0, 0xFF, 0xFFFF, 0xFFFFFF, 0xFFFFFFFF];
18
19/// Returns the decompressed size (in bytes) of the compressed bytes given.
20///
21/// `input` must be a sequence of bytes returned by a conforming Snappy
22/// compressor.
23///
24/// # Errors
25///
26/// This function returns an error in the following circumstances:
27///
28/// * An invalid Snappy header was seen.
29/// * The total space required for decompression exceeds `2^32 - 1`.
30pub fn decompress_len(input: &[u8]) -> Result<usize> {
31 if input.is_empty() {
32 return Ok(0);
33 }
34 Ok(Header::read(input)?.decompress_len)
35}
36
37/// Decoder is a raw decoder for decompressing bytes in the Snappy format.
38///
39/// This decoder does not use the Snappy frame format and simply decompresses
40/// the given bytes as if it were returned from `Encoder`.
41///
42/// Unless you explicitly need the low-level control, you should use
43/// [`read::FrameDecoder`](../read/struct.FrameDecoder.html)
44/// instead, which decompresses the Snappy frame format.
45#[derive(Clone, Debug, Default)]
46pub struct Decoder {
47 // Place holder for potential future fields.
48 _dummy: (),
49}
50
51impl Decoder {
52 /// Return a new decoder that can be used for decompressing bytes.
53 pub fn new() -> Decoder {
54 Decoder { _dummy: () }
55 }
56
57 /// Decompresses all bytes in `input` into `output`.
58 ///
59 /// `input` must be a sequence of bytes returned by a conforming Snappy
60 /// compressor.
61 ///
62 /// The size of `output` must be large enough to hold all decompressed
63 /// bytes from the `input`. The size required can be queried with the
64 /// `decompress_len` function.
65 ///
66 /// On success, this returns the number of bytes written to `output`.
67 ///
68 /// # Errors
69 ///
70 /// This method returns an error in the following circumstances:
71 ///
72 /// * Invalid compressed Snappy data was seen.
73 /// * The total space required for decompression exceeds `2^32 - 1`.
74 /// * `output` has length less than `decompress_len(input)`.
75 pub fn decompress(
76 &mut self,
77 input: &[u8],
78 output: &mut [u8],
79 ) -> Result<usize> {
80 if input.is_empty() {
81 return Err(Error::Empty);
82 }
83 let hdr = Header::read(input)?;
84 if hdr.decompress_len > output.len() {
85 return Err(Error::BufferTooSmall {
86 given: output.len() as u64,
87 min: hdr.decompress_len as u64,
88 });
89 }
90 let dst = &mut output[..hdr.decompress_len];
91 let mut dec =
92 Decompress { src: &input[hdr.len..], s: 0, dst: dst, d: 0 };
93 dec.decompress()?;
94 Ok(dec.dst.len())
95 }
96
97 /// Decompresses all bytes in `input` into a freshly allocated `Vec`.
98 ///
99 /// This is just like the `decompress` method, except it allocates a `Vec`
100 /// with the right size for you. (This is intended to be a convenience
101 /// method.)
102 ///
103 /// This method returns an error under the same circumstances that
104 /// `decompress` does.
105 pub fn decompress_vec(&mut self, input: &[u8]) -> Result<Vec<u8>> {
106 let mut buf = vec![0; decompress_len(input)?];
107 let n = self.decompress(input, &mut buf)?;
108 buf.truncate(n);
109 Ok(buf)
110 }
111}
112
113/// Decompress is the state of the Snappy compressor.
114struct Decompress<'s, 'd> {
115 /// The original compressed bytes not including the header.
116 src: &'s [u8],
117 /// The current position in the compressed bytes.
118 s: usize,
119 /// The output buffer to write the decompressed bytes.
120 dst: &'d mut [u8],
121 /// The current position in the decompressed buffer.
122 d: usize,
123}
124
125impl<'s, 'd> Decompress<'s, 'd> {
126 /// Decompresses snappy compressed bytes in `src` to `dst`.
127 ///
128 /// This assumes that the header has already been read and that `dst` is
129 /// big enough to store all decompressed bytes.
130 fn decompress(&mut self) -> Result<()> {
131 while self.s < self.src.len() {
132 let byte = self.src[self.s];
133 self.s += 1;
134 if byte & 0b000000_11 == 0 {
135 let len = (byte >> 2) as usize + 1;
136 self.read_literal(len)?;
137 } else {
138 self.read_copy(byte)?;
139 }
140 }
141 if self.d != self.dst.len() {
142 return Err(Error::HeaderMismatch {
143 expected_len: self.dst.len() as u64,
144 got_len: self.d as u64,
145 });
146 }
147 Ok(())
148 }
149
150 /// Decompresses a literal from `src` starting at `s` to `dst` starting at
151 /// `d` and returns the updated values of `s` and `d`. `s` should point to
152 /// the byte immediately proceding the literal tag byte.
153 ///
154 /// `len` is the length of the literal if it's <=60. Otherwise, it's the
155 /// length tag, indicating the number of bytes needed to read a little
156 /// endian integer at `src[s..]`. i.e., `61 => 1 byte`, `62 => 2 bytes`,
157 /// `63 => 3 bytes` and `64 => 4 bytes`.
158 ///
159 /// `len` must be <=64.
160 #[inline(always)]
161 fn read_literal(&mut self, len: usize) -> Result<()> {
162 debug_assert!(len <= 64);
163 let mut len = len as u64;
164 // As an optimization for the common case, if the literal length is
165 // <=16 and we have enough room in both `src` and `dst`, copy the
166 // literal using unaligned loads and stores.
167 //
168 // We pick 16 bytes with the hope that it optimizes down to a 128 bit
169 // load/store.
170 if len <= 16
171 && self.s + 16 <= self.src.len()
172 && self.d + 16 <= self.dst.len()
173 {
174 unsafe {
175 // SAFETY: We know both src and dst have at least 16 bytes of
176 // wiggle room after s/d, even if `len` is <16, so the copy is
177 // safe.
178 let srcp = self.src.as_ptr().add(self.s);
179 let dstp = self.dst.as_mut_ptr().add(self.d);
180 // Hopefully uses SIMD registers for 128 bit load/store.
181 ptr::copy_nonoverlapping(srcp, dstp, 16);
182 }
183 self.d += len as usize;
184 self.s += len as usize;
185 return Ok(());
186 }
187 // When the length is bigger than 60, it indicates that we need to read
188 // an additional 1-4 bytes to get the real length of the literal.
189 if len >= 61 {
190 let byte_count = len as usize - 60;
191 // Only require the number of length bytes selected by the tag.
192 if self.src.len() - self.s < byte_count {
193 return Err(Error::Literal {
194 len: byte_count as u64,
195 src_len: (self.src.len() - self.s) as u64,
196 dst_len: (self.dst.len() - self.d) as u64,
197 });
198 }
199 // Keep the fast 32-bit load when it is in bounds. Near the end of
200 // the input, read only the selected 1-4 little-endian bytes.
201 if self.src.len() - self.s >= 4 {
202 len = bytes::read_u32_le(&self.src[self.s..]) as u64;
203 len = (len & (WORD_MASK[byte_count] as u64)) + 1;
204 } else {
205 len = 0;
206 for i in 0..byte_count {
207 len |= (self.src[self.s + i] as u64) << (8 * i);
208 }
209 len += 1;
210 }
211 self.s += byte_count;
212 }
213 // If there's not enough buffer left to load or store this literal,
214 // then the input is corrupt.
215 // if self.s + len > self.src.len() || self.d + len > self.dst.len() {
216 if ((self.src.len() - self.s) as u64) < len
217 || ((self.dst.len() - self.d) as u64) < len
218 {
219 return Err(Error::Literal {
220 len: len,
221 src_len: (self.src.len() - self.s) as u64,
222 dst_len: (self.dst.len() - self.d) as u64,
223 });
224 }
225 unsafe {
226 // SAFETY: We've already checked the bounds, so we know this copy
227 // is correct.
228 let srcp = self.src.as_ptr().add(self.s);
229 let dstp = self.dst.as_mut_ptr().add(self.d);
230 ptr::copy_nonoverlapping(srcp, dstp, len as usize);
231 }
232 self.s += len as usize;
233 self.d += len as usize;
234 Ok(())
235 }
236
237 /// Reads a copy from `src` and writes the decompressed bytes to `dst`. `s`
238 /// should point to the byte immediately proceding the copy tag byte.
239 #[inline(always)]
240 fn read_copy(&mut self, tag_byte: u8) -> Result<()> {
241 // Find the copy offset and len, then advance the input past the copy.
242 // The rest of this function deals with reading/writing to output only.
243 let entry = TAG_LOOKUP_TABLE.entry(tag_byte);
244 let offset = entry.offset(self.src, self.s)?;
245 let len = entry.len();
246 self.s += entry.num_tag_bytes();
247
248 // What we really care about here is whether `d == 0` or `d < offset`.
249 // To save an extra branch, use `d < offset - 1` instead. If `d` is
250 // `0`, then `offset.wrapping_sub(1)` will be usize::MAX which is also
251 // the max value of `d`.
252 if self.d <= offset.wrapping_sub(1) {
253 return Err(Error::Offset {
254 offset: offset as u64,
255 dst_pos: self.d as u64,
256 });
257 }
258 // When all is said and done, dst is advanced to end.
259 let end = self.d + len;
260 // When the copy is small and the offset is at least 8 bytes away from
261 // `d`, then we can decompress the copy with two 64 bit unaligned
262 // loads/stores.
263 if offset >= 8 && len <= 16 && self.d + 16 <= self.dst.len() {
264 unsafe {
265 // SAFETY: We know dstp points to at least 16 bytes of memory
266 // from the condition above, and we also know that dstp is
267 // preceded by at least `offset` bytes from the `d <= offset`
268 // check above.
269 //
270 // We also know that dstp and dstp-8 do not overlap from the
271 // check above, justifying the use of copy_nonoverlapping.
272 let dstp = self.dst.as_mut_ptr().add(self.d);
273 let srcp = dstp.sub(offset);
274 // We can't do a single 16 byte load/store because src/dst may
275 // overlap with each other. Namely, the second copy here may
276 // copy bytes written in the first copy!
277 ptr::copy_nonoverlapping(srcp, dstp, 8);
278 ptr::copy_nonoverlapping(srcp.add(8), dstp.add(8), 8);
279 }
280 // If we have some wiggle room, try to decompress the copy 16 bytes
281 // at a time with 128 bit unaligned loads/stores. Remember, we can't
282 // just do a memcpy because decompressing copies may require copying
283 // overlapping memory.
284 //
285 // We need the extra wiggle room to make effective use of 128 bit
286 // loads/stores. Even if the store ends up copying more data than we
287 // need, we're careful to advance `d` by the correct amount at the end.
288 } else if end + 24 <= self.dst.len() {
289 unsafe {
290 // SAFETY: We know that dstp is preceded by at least `offset`
291 // bytes from the `d <= offset` check above.
292 //
293 // We don't know whether dstp overlaps with srcp, so we start
294 // by copying from srcp to dstp until they no longer overlap.
295 // The worst case is when dstp-src = 3 and copy length = 1. The
296 // first loop will issue these copy operations before stopping:
297 //
298 // [-1, 14] -> [0, 15]
299 // [-1, 14] -> [3, 18]
300 // [-1, 14] -> [9, 24]
301 //
302 // But the copy had length 1, so it was only supposed to write
303 // to [0, 0]. But the last copy wrote to [9, 24], which is 24
304 // extra bytes in dst *beyond* the end of the copy, which is
305 // guaranteed by the conditional above.
306
307 // Save destination length here to avoid a reborrow UB violation
308 // under the Tree Borrows model.
309 let dest_len = self.dst.len();
310
311 let mut dstp = self.dst.as_mut_ptr().add(self.d);
312 let mut srcp = dstp.sub(offset);
313 loop {
314 debug_assert!(dstp >= srcp);
315 let diff = (dstp as usize) - (srcp as usize);
316 if diff >= 16 {
317 break;
318 }
319 // srcp and dstp can overlap, so use ptr::copy.
320 debug_assert!(self.d + 16 <= dest_len);
321 ptr::copy(srcp, dstp, 16);
322 self.d += diff as usize;
323 dstp = dstp.add(diff);
324 }
325 while self.d < end {
326 ptr::copy_nonoverlapping(srcp, dstp, 16);
327 srcp = srcp.add(16);
328 dstp = dstp.add(16);
329 self.d += 16;
330 }
331 // At this point, `d` is likely wrong. We correct it before
332 // returning. It's correct value is `end`.
333 }
334 } else {
335 if end > self.dst.len() {
336 return Err(Error::CopyWrite {
337 len: len as u64,
338 dst_len: (self.dst.len() - self.d) as u64,
339 });
340 }
341 // Finally, the slow byte-by-byte case, which should only be used
342 // for the last few bytes of decompression.
343 while self.d != end {
344 self.dst[self.d] = self.dst[self.d - offset];
345 self.d += 1;
346 }
347 }
348 self.d = end;
349 Ok(())
350 }
351}
352
353/// Header represents the single varint that starts every Snappy compressed
354/// block.
355#[derive(Debug)]
356struct Header {
357 /// The length of the header in bytes (i.e., the varint).
358 len: usize,
359 /// The length of the original decompressed input in bytes.
360 decompress_len: usize,
361}
362
363impl Header {
364 /// Reads the varint header from the given input.
365 ///
366 /// If there was a problem reading the header then an error is returned.
367 /// If a header is returned then it is guaranteed to be valid.
368 #[inline(always)]
369 fn read(input: &[u8]) -> Result<Header> {
370 let (decompress_len, header_len) = bytes::read_varu64(input);
371 // The uncompressed length is a uint32 varint, which uses at most 5
372 // bytes in the reference implementation.
373 if header_len == 0 || header_len > 5 {
374 return Err(Error::Header);
375 }
376 if decompress_len > MAX_INPUT_SIZE {
377 return Err(Error::TooBig {
378 given: decompress_len as u64,
379 max: MAX_INPUT_SIZE,
380 });
381 }
382 Ok(Header { len: header_len, decompress_len: decompress_len as usize })
383 }
384}
385
386/// A lookup table for quickly computing the various attributes derived from
387/// a tag byte. The attributes are most useful for the three "copy" tags
388/// and include the length of the copy, part of the offset (for copy 1-byte
389/// only) and the total number of bytes proceding the tag byte that encode
390/// the other part of the offset (1 for copy 1, 2 for copy 2 and 4 for copy 4).
391///
392/// More specifically, the keys of the table are u8s and the values are u16s.
393/// The bits of the values are laid out as follows:
394///
395/// xxaa abbb xxcc cccc
396///
397/// Where `a` is the number of bytes, `b` are the three bits of the offset
398/// for copy 1 (the other 8 bits are in the byte proceding the tag byte; for
399/// copy 2 and copy 4, `b = 0`), and `c` is the length of the copy (max of 64).
400///
401/// We could pack this in fewer bits, but the position of the three `b` bits
402/// lines up with the most significant three bits in the total offset for copy
403/// 1, which avoids an extra shift instruction.
404///
405/// In sum, this table is useful because it reduces branches and various
406/// arithmetic operations.
407struct TagLookupTable([u16; 256]);
408
409impl TagLookupTable {
410 /// Look up the tag entry given the tag `byte`.
411 #[inline(always)]
412 fn entry(&self, byte: u8) -> TagEntry {
413 TagEntry(self.0[byte as usize] as usize)
414 }
415}
416
417/// Represents a single entry in the tag lookup table.
418///
419/// See the documentation in `TagLookupTable` for the bit layout.
420///
421/// The type is a `usize` for convenience.
422struct TagEntry(usize);
423
424impl TagEntry {
425 /// Return the total number of bytes proceding this tag byte required to
426 /// encode the offset.
427 fn num_tag_bytes(&self) -> usize {
428 self.0 >> 11
429 }
430
431 /// Return the total copy length, capped at 255.
432 fn len(&self) -> usize {
433 self.0 & 0xFF
434 }
435
436 /// Return the copy offset corresponding to this copy operation. `s` should
437 /// point to the position just after the tag byte that this entry was read
438 /// from.
439 ///
440 /// This requires reading from the compressed input since the offset is
441 /// encoded in bytes proceding the tag byte.
442 fn offset(&self, src: &[u8], s: usize) -> Result<usize> {
443 let num_tag_bytes = self.num_tag_bytes();
444 let trailer =
445 // It is critical for this case to come first, since it is the
446 // fast path. We really hope that this case gets branch
447 // predicted.
448 if s + 4 <= src.len() {
449 unsafe {
450 // SAFETY: The conditional above guarantees that
451 // src[s..s+4] is valid to read from.
452 let p = src.as_ptr().add(s);
453 // We use WORD_MASK here to mask out the bits we don't
454 // need. While we're guaranteed to read 4 valid bytes,
455 // not all of those bytes are necessarily part of the
456 // offset. This is the key optimization: we don't need to
457 // branch on num_tag_bytes.
458 bytes::loadu_u32_le(p) as usize & WORD_MASK[num_tag_bytes]
459 }
460 } else if num_tag_bytes == 1 {
461 if s >= src.len() {
462 return Err(Error::CopyRead {
463 len: 1,
464 src_len: (src.len() - s) as u64,
465 });
466 }
467 src[s] as usize
468 } else if num_tag_bytes == 2 {
469 if s + 1 >= src.len() {
470 return Err(Error::CopyRead {
471 len: 2,
472 src_len: (src.len() - s) as u64,
473 });
474 }
475 bytes::read_u16_le(&src[s..]) as usize
476 } else {
477 return Err(Error::CopyRead {
478 len: num_tag_bytes as u64,
479 src_len: (src.len() - s) as u64,
480 });
481 };
482 Ok((self.0 & 0b0000_0111_0000_0000) | trailer)
483 }
484}