Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions examples/decompress_block.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
fn main() {
use lz4_flex::{compress_prepend_size, decompress_size_prepended};
let input: &[u8] = b"Hello people, what's up?";
let compressed = compress_prepend_size(input);
let uncompressed = decompress_size_prepended(&compressed).unwrap();
assert_eq!(input, uncompressed);
}
23 changes: 9 additions & 14 deletions src/block/decompress_safe.rs
Original file line number Diff line number Diff line change
Expand Up @@ -119,17 +119,18 @@ pub(crate) fn decompress_internal<const USE_DICT: bool>(
if does_token_fit(token) && input_pos <= safe_input_pos && output.pos() < safe_output_pos {
let literal_length = (token >> 4) as usize;

if literal_length > input.len() - input_pos {
return Err(DecompressError::LiteralOutOfBounds);
}
// casting to [u8;u16] doesn't seem to make a difference vs &[u8] (same assembly)
let input: &[u8; 16] = input[input_pos..input_pos + 16].try_into().unwrap();

// Copy the literal
// The literal is at max 14 bytes, and the is_safe_distance check assures
// that we are far away enough from the end so we can safely copy 16 bytes
output.extend_from_slice_wild(&input[input_pos..input_pos + 16], literal_length);
output.extend_from_slice_wild(input, literal_length);
input_pos += literal_length;

let offset = read_u16(input, &mut input_pos)? as usize;
// clone as we don't want to mutate
let offset = read_u16(input, &mut literal_length.clone())? as usize;
input_pos += 2;

let mut match_length = MINMATCH + (token & 0xF) as usize;

Expand All @@ -146,10 +147,7 @@ pub(crate) fn decompress_internal<const USE_DICT: bool>(
// In this branch we know that match_length is at most 18 (14 + MINMATCH).
// But the blocks can overlap, so make sure they are at least 18 bytes apart
// to enable an optimized copy of 18 bytes.
let (start, did_overflow) = output.pos().overflowing_sub(offset);
if did_overflow {
return Err(DecompressError::OffsetOutOfBounds);
}
let start = output.pos() - offset;
if offset >= match_length {
output.extend_from_within(start, 18, match_length);
} else {
Expand Down Expand Up @@ -261,10 +259,7 @@ fn duplicate_slice(
if match_length > offset {
duplicate_overlapping_slice(output, offset, match_length)?;
} else {
let (start, did_overflow_1) = output.pos().overflowing_sub(offset);
if did_overflow_1 {
return Err(DecompressError::OffsetOutOfBounds);
}
let start = output.pos() - offset;
match match_length {
0..=32 if output.pos() + 32 <= output.capacity() => {
output.extend_from_within(start, 32, match_length)
Expand Down Expand Up @@ -292,7 +287,7 @@ fn duplicate_overlapping_slice(
return Err(DecompressError::OffsetOutOfBounds);
}
if offset == 1 {
let val = sink.filled_slice()[start];
let val = sink.output[start];
sink.extend_with_fill(val, match_length);
} else {
sink.extend_from_within_overlapping(start, match_length);
Expand Down
22 changes: 5 additions & 17 deletions src/sink.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,9 +52,9 @@ pub fn vec_sink_for_decompression(
/// - Bytes `[..pos()]` are always initialized.
pub struct SliceSink<'a> {
/// The working slice, which may contain uninitialized bytes
output: &'a mut [u8],
pub output: &'a mut [u8],
/// Number of bytes in start of `output` guaranteed to be initialized
pos: usize,
pub pos: usize,
}

impl<'a> SliceSink<'a> {
Expand Down Expand Up @@ -91,12 +91,6 @@ impl<'a> SliceSink<'a> {
self.output.as_mut_ptr()
}

#[inline]
#[cfg(any(feature = "safe-decode"))]
pub(crate) fn filled_slice(&self) -> &[u8] {
&self.output[..self.pos]
}

#[inline]
pub(crate) fn pos(&self) -> usize {
self.pos
Expand Down Expand Up @@ -138,16 +132,14 @@ impl<'a> SliceSink<'a> {
/// # Panics
/// Panics if `start` >= `pos`.
#[inline]
#[cfg(any(feature = "safe-decode"))]
#[cfg(feature = "safe-decode")]
pub(crate) fn extend_from_within(&mut self, start: usize, wild_len: usize, copy_len: usize) {
assert!(copy_len <= wild_len);
assert!(start + copy_len <= self.pos);
self.output.copy_within(start..start + wild_len, self.pos);
self.pos += copy_len;
}

#[inline]
#[cfg(any(feature = "safe-decode"))]
#[cfg(feature = "safe-decode")]
pub(crate) fn extend_from_within_overlapping(&mut self, start: usize, num_bytes: usize) {
let offset = self.pos - start;
for i in start + offset..start + offset + num_bytes {
Expand All @@ -167,12 +159,8 @@ mod tests {
use crate::sink::SliceSink;
let mut data = Vec::new();
data.resize(5, 0);
let mut sink = SliceSink::new(&mut data, 1);
let sink = SliceSink::new(&mut data, 1);
assert_eq!(sink.pos(), 1);
assert_eq!(sink.capacity(), 5);
assert_eq!(sink.filled_slice(), &[0]);
sink.extend_from_slice(&[1, 2, 3]);
assert_eq!(sink.pos(), 4);
assert_eq!(sink.filled_slice(), &[0, 1, 2, 3]);
}
}