diff 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
line wrap: on
line diff
new file mode 100644
--- /dev/null
+++ b/src/util/lzss.rs
@@ -0,0 +1,57 @@
+//! LZSS implementation.
+
+use std::io;
+use crate::util::bitstream::BitStream;
+
+/// Decompresses a LZSS-compressed file.
+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>> {
+    let mut data = vec![0; size];
+    let mut dictionary = vec![0; dictionary_size];
+    let mut dictionary_head = 1;
+    let mut ptr = 0;
+
+    while ptr < size {
+        if bitstream.read_bit()? {
+            // The `flag` bit is set, indicating the upcoming chunk of data is a literal.
+            // Add it to the uncompressed file, and store it in the dictionary.
+            let byte = bitstream.read(8)? as u8;
+            dictionary[dictionary_head] = byte;
+            dictionary_head = (dictionary_head + 1) % dictionary_size;
+            data[ptr] = byte;
+            ptr += 1;
+        } else {
+            // The `flag` bit is not set, the upcoming chunk is a (offset, length) tuple.
+            let offset = bitstream.read(offset_size)?;
+            let length = bitstream.read(length_size)? + minimum_match_length;
+            if ptr + length > size {
+                return Err(io::Error::new(io::ErrorKind::Other, "Oh no!"));
+            }
+            if offset == 0 && length == 0 {
+                break;
+            }
+            for i in offset..offset + length {
+                data[ptr] = dictionary[i % dictionary_size];
+                dictionary[dictionary_head] = dictionary[i % dictionary_size];
+                dictionary_head = (dictionary_head + 1) % dictionary_size;
+                ptr += 1;
+            }
+        }
+    }
+
+    Ok(data)
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+    use crate::util::SeekableSlice;
+
+    #[test]
+    #[ignore]
+    fn bit_by_bit() {
+        // TODO: find actual lzss data.
+        let data = SeekableSlice::new(&[0, 0, 0]);
+        let mut bitstream = BitStream::new(data);
+        decompress(&mut bitstream, 3, 0x2000, 13, 4, 3).unwrap();
+    }
+}