Mercurial > touhou
comparison src/util/lzss.rs @ 637:afa012bb8021
Hello Rust!
author | Emmanuel Gil Peyrot <linkmauve@linkmauve.fr> |
---|---|
date | Wed, 03 Jul 2019 16:27:12 +0200 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
636:4fa0a8e7d941 | 637:afa012bb8021 |
---|---|
1 //! LZSS implementation. | |
2 | |
3 use std::io; | |
4 use crate::util::bitstream::BitStream; | |
5 | |
6 /// Decompresses a LZSS-compressed file. | |
7 pub fn decompress<R: io::Read + io::Seek>(bitstream: &mut BitStream<R>, size: usize, dictionary_size: usize, offset_size: usize, length_size: usize, minimum_match_length: usize) -> io::Result<Vec<u8>> { | |
8 let mut data = vec![0; size]; | |
9 let mut dictionary = vec![0; dictionary_size]; | |
10 let mut dictionary_head = 1; | |
11 let mut ptr = 0; | |
12 | |
13 while ptr < size { | |
14 if bitstream.read_bit()? { | |
15 // The `flag` bit is set, indicating the upcoming chunk of data is a literal. | |
16 // Add it to the uncompressed file, and store it in the dictionary. | |
17 let byte = bitstream.read(8)? as u8; | |
18 dictionary[dictionary_head] = byte; | |
19 dictionary_head = (dictionary_head + 1) % dictionary_size; | |
20 data[ptr] = byte; | |
21 ptr += 1; | |
22 } else { | |
23 // The `flag` bit is not set, the upcoming chunk is a (offset, length) tuple. | |
24 let offset = bitstream.read(offset_size)?; | |
25 let length = bitstream.read(length_size)? + minimum_match_length; | |
26 if ptr + length > size { | |
27 return Err(io::Error::new(io::ErrorKind::Other, "Oh no!")); | |
28 } | |
29 if offset == 0 && length == 0 { | |
30 break; | |
31 } | |
32 for i in offset..offset + length { | |
33 data[ptr] = dictionary[i % dictionary_size]; | |
34 dictionary[dictionary_head] = dictionary[i % dictionary_size]; | |
35 dictionary_head = (dictionary_head + 1) % dictionary_size; | |
36 ptr += 1; | |
37 } | |
38 } | |
39 } | |
40 | |
41 Ok(data) | |
42 } | |
43 | |
44 #[cfg(test)] | |
45 mod tests { | |
46 use super::*; | |
47 use crate::util::SeekableSlice; | |
48 | |
49 #[test] | |
50 #[ignore] | |
51 fn bit_by_bit() { | |
52 // TODO: find actual lzss data. | |
53 let data = SeekableSlice::new(&[0, 0, 0]); | |
54 let mut bitstream = BitStream::new(data); | |
55 decompress(&mut bitstream, 3, 0x2000, 13, 4, 3).unwrap(); | |
56 } | |
57 } |