use super::{LzfError, LzfResult};
pub fn decompress(data: &[u8], out_len_should: usize) -> LzfResult<Vec<u8>> {
let mut current_offset = 0;
let in_len = data.len();
if in_len == 0 {
return Err(LzfError::DataCorrupted);
}
let mut output = vec![0; out_len_should];
let mut out_len: usize = 0;
while current_offset < in_len {
let mut ctrl = data[current_offset] as usize;
current_offset += 1;
if ctrl < (1 << 5) {
ctrl += 1;
if out_len + ctrl > out_len_should {
return Err(LzfError::BufferTooSmall);
}
if current_offset + ctrl > in_len {
return Err(LzfError::DataCorrupted);
}
output[out_len..(out_len + ctrl)]
.copy_from_slice(&data[current_offset..(current_offset + ctrl)]);
current_offset += ctrl;
out_len += ctrl;
} else {
let mut len = ctrl >> 5;
let mut ref_offset = (((ctrl & 0x1f) << 8) + 1) as i32;
if current_offset >= in_len {
return Err(LzfError::DataCorrupted);
}
if len == 7 {
len += data[current_offset] as usize;
current_offset += 1;
if current_offset >= in_len {
return Err(LzfError::DataCorrupted);
}
}
ref_offset += data[current_offset] as i32;
current_offset += 1;
if out_len + len + 2 > out_len_should {
return Err(LzfError::BufferTooSmall);
}
let mut ref_pos = (out_len as i32) - ref_offset;
if ref_pos < 0 {
return Err(LzfError::DataCorrupted);
}
let c = output[ref_pos as usize];
output[out_len] = c;
out_len += 1;
ref_pos += 1;
let c = output[ref_pos as usize];
output[out_len] = c;
out_len += 1;
ref_pos += 1;
while len > 0 {
let c = output[ref_pos as usize];
output[out_len] = c;
out_len += 1;
ref_pos += 1;
len -= 1;
}
}
}
unsafe { output.set_len(out_len) };
Ok(output)
}
#[test]
fn test_decompress_lorem() {
use super::compress;
let lorem = "Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod \
tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At \
vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, \
no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit \
amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut \
labore et dolore magna aliquyam erat, sed diam voluptua.";
let compressed = compress(lorem.as_bytes()).unwrap();
let decompressed = decompress(&compressed[..], lorem.len()).unwrap();
assert_eq!(lorem.as_bytes(), &decompressed[..]);
let decompressed = decompress(&compressed[..], 1000).unwrap();
assert_eq!(lorem.len(), decompressed.len());
}
#[test]
fn test_decompress_fails_with_short_buffer() {
use super::compress;
let lorem = "Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod \
tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At \
vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, \
no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit \
amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut \
labore et dolore magna aliquyam erat, sed diam voluptua.";
let compressed = match compress(lorem.as_bytes()) {
Ok(c) => c,
Err(err) => panic!("Compression failed with error {:?}", err),
};
match decompress(&compressed, 10) {
Ok(_) => panic!("Decompression worked. That should not happen"),
Err(err) => assert_eq!(LzfError::BufferTooSmall, err),
}
}
#[test]
fn test_decompress_fails_for_corrupted_data() {
let lorem = "Lorem ipsum dolor sit amet";
match decompress(lorem.as_bytes(), lorem.len()) {
Ok(_) => panic!("Decompression worked. That should not happen"),
Err(err) => assert_eq!(LzfError::DataCorrupted, err),
}
}
#[test]
fn test_alice_wonderland() {
use super::compress;
let alice = "\r\n\r\n\r\n\r\n ALICE'S ADVENTURES IN WONDERLAND\r\n";
let compressed = match compress(alice.as_bytes()) {
Ok(c) => c,
Err(err) => panic!("Compression failed with error {:?}", err),
};
match decompress(&compressed, alice.len()) {
Ok(decompressed) => {
assert_eq!(alice.len(), decompressed.len());
assert_eq!(alice.as_bytes(), &decompressed[..]);
}
Err(err) => panic!("Decompression failed with error {:?}", err),
}
}
#[test]
fn easily_compressible() {
let data = vec![1, 97, 97, 224, 187, 0, 1, 97, 97];
let real_length = 200;
let text = decompress(&data, real_length).unwrap();
assert_eq!(200, text.len());
assert_eq!(97, text[0]);
assert_eq!(97, text[199]);
}
#[test]
fn test_empty() {
assert_eq!(LzfError::DataCorrupted, decompress(&[], 10).unwrap_err());
}