rust_lzss/
lib.rs

1//! Decompresses LZSS types implemented by Nintendo based on https://github.com/magical/nlzss
2
3extern crate bit_vec;
4extern crate byteorder;
5
6use bit_vec::BitVec;
7use byteorder::{BigEndian, ReadBytesExt};
8use std::io::{Error, ErrorKind, Read, Seek};
9use std::mem::transmute;
10
11/// Parses an LZSS header and data block returning the decompressed result
12///
13/// Assumes LZSS is constructed properly
14///
15/// # Panics
16/// Will panic if the size in the data header is incorrect
17///
18/// # Errors
19/// Returns an Error if the type is invalid or the size is wrong
20///
21/// # Examples
22///
23/// ```
24/// use rust_lzss::decompress;
25/// use std::io::Cursor;
26///
27/// let lzss10: [u8; 11] = [ 0x10, 0x14, 0x00, 0x00, 0x08, 0x61, 0x62, 0x63, 0x64, 0xD0, 0x03, ]; // abcdabcdabcdabcdabcdabcd
28/// let decoded = decompress(&mut Cursor::new(lzss10));
29/// ```
30pub fn decompress<T: Read + Seek>(data: &mut T) -> Result<Vec<u8>, Error> {
31    let lz_type = data.read_u8()?;
32    let mut data_size_tmp: [u8; 4] = [0; 4];
33    data.read_exact(&mut data_size_tmp[0..3])?;
34    let data_size = unsafe { transmute::<[u8; 4], u32>(data_size_tmp) };
35
36    match lz_type {
37        0x10 => decompress_lzss10(data, data_size as usize),
38        0x11 => decompress_lzss11(data, data_size as usize),
39        _ => Err(Error::new(ErrorKind::InvalidInput, "Invalid header")),
40    }
41}
42
43fn decompress_lzss10<T: Read + Seek>(data: &mut T, size: usize) -> Result<Vec<u8>, Error> {
44    let mut decompress_data: Vec<u8> = Vec::new();
45    let disp_extra = 1;
46    while decompress_data.len() < size {
47        let b = data.read_u8()?;
48        let bits = BitVec::from_bytes(&[b]);
49        for bit in bits.iter() {
50            if bit {
51                let val = data.read_u16::<BigEndian>()?;
52                let count = (val >> 0xC) + 3;
53                let disp = (val & 0xFFF) + disp_extra;
54                for _ in 0..count {
55                    let len = decompress_data.len();
56                    let copy_data = decompress_data[len - disp as usize];
57                    decompress_data.push(copy_data);
58                }
59            } else {
60                decompress_data.push(data.read_u8()?);
61            }
62
63            if size <= decompress_data.len() {
64                break;
65            }
66        }
67    }
68
69    if size == decompress_data.len() {
70        Ok(decompress_data)
71    } else {
72        Err(Error::new(
73            ErrorKind::InvalidData,
74            "Decompressed size does not match expected size.",
75        ))
76    }
77}
78
79fn decompress_lzss11<T: Read + Seek>(data: &mut T, size: usize) -> Result<Vec<u8>, Error> {
80    let mut decompress_data: Vec<u8> = Vec::new();
81    while decompress_data.len() < size {
82        let b = data.read_u8()?;
83        let bits = BitVec::from_bytes(&[b]);
84        for bit in bits.iter() {
85            if bit {
86                let mut val = data.read_u8()?;
87                let indicator = val >> 4;
88                let mut count: u16;
89                match indicator {
90                    0 => {
91                        count = u16::from(val) << 4;
92                        val = data.read_u8()?;
93                        count += u16::from(val) >> 4;
94                        count += 0x11
95                    }
96                    1 => {
97                        count = (u16::from(val) & 0xF) << 12;
98                        val = data.read_u8()?;
99                        count += u16::from(val) << 4;
100                        val = data.read_u8()?;
101                        count += u16::from(val) >> 4;
102                        count += 0x111;
103                    }
104                    _ => {
105                        count = indicator.into();
106                        count += 1;
107                    }
108                }
109                let mut disp: u16 = (u16::from(val) & 0xF) << 8;
110                val = data.read_u8()?;
111                disp += u16::from(val) + 1;
112
113                for _ in 0..count {
114                    let len = decompress_data.len();
115                    let copy_data = decompress_data[len - disp as usize];
116                    decompress_data.push(copy_data);
117                }
118            } else {
119                decompress_data.push(data.read_u8()?);
120            }
121
122            if size <= decompress_data.len() {
123                break;
124            }
125        }
126    }
127
128    if size == decompress_data.len() {
129        Ok(decompress_data)
130    } else {
131        Err(Error::new(
132            ErrorKind::InvalidData,
133            "Decompressed size does not match expected size.",
134        ))
135    }
136}
137
138#[cfg(test)]
139mod tests {
140    use super::*;
141    use std::io::Cursor;
142
143    #[test]
144    fn decompresses() {
145        let lzss10: [u8; 11] = [
146            0x10, 0x14, 0x00, 0x00, 0x08, 0x61, 0x62, 0x63, 0x64, 0xD0, 0x03,
147        ]; // abcdabcdabcdabcdabcdabcd
148        let lzss11: [u8; 11] = [
149            0x11, 0x14, 0x00, 0x00, 0x08, 0x61, 0x62, 0x63, 0x64, 0xF0, 0x03,
150        ]; // abcdabcdabcdabcdabcdabcd
151        let type_bad: [u8; 11] = [
152            0x13, 0x10, 0x00, 0x00, 0x08, 0x61, 0x62, 0x63, 0x64, 0xF0, 0x03,
153        ]; // abcdabcdabcdabcdabcdabcd
154
155        let mut result_lzss10: Vec<u8> = Vec::new();
156        let mut result_lzss11: Vec<u8> = Vec::new();
157        for _ in 0..5 {
158            result_lzss10.push(0x61);
159            result_lzss10.push(0x62);
160            result_lzss10.push(0x63);
161            result_lzss10.push(0x64);
162
163            result_lzss11.push(0x61);
164            result_lzss11.push(0x62);
165            result_lzss11.push(0x63);
166            result_lzss11.push(0x64);
167        }
168
169        assert_eq!(result_lzss10, decompress(&mut Cursor::new(lzss10)).unwrap());
170        assert_eq!(result_lzss11, decompress(&mut Cursor::new(lzss11)).unwrap());
171        assert!(
172            decompress(&mut Cursor::new(type_bad)).is_err(),
173            "Should error on invalid type header"
174        );
175    }
176
177    #[test]
178    fn decompresses_lzss10() {
179        let test1: [u8; 1] = [0x00];
180        let test2: [u8; 9] = [0x00, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68]; // abcdefgh
181        let test3: [u8; 7] = [0x08, 0x61, 0x62, 0x63, 0x64, 0xD0, 0x03]; // abcdabcdabcdabcdabcdabcd
182        let test4_bad: [u8; 11] = [
183            0x10, 0x10, 0x00, 0x00, 0x08, 0x61, 0x62, 0x63, 0x64, 0xD0, 0x03,
184        ]; // abcdabcdabcdabcdabcdabcd
185        let mut result3: Vec<u8> = Vec::new();
186        for _ in 0..5 {
187            result3.push(0x61);
188            result3.push(0x62);
189            result3.push(0x63);
190            result3.push(0x64);
191        }
192        assert_eq!(
193            0,
194            decompress_lzss10(&mut Cursor::new(test1), 0).unwrap().len()
195        );
196        assert_eq!(
197            &[0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68],
198            decompress_lzss10(&mut Cursor::new(test2), 8)
199                .unwrap()
200                .as_slice()
201        );
202        assert_eq!(
203            result3,
204            decompress_lzss10(&mut Cursor::new(test3), 20).unwrap()
205        );
206        assert!(
207            decompress(&mut Cursor::new(test4_bad)).is_err(),
208            "Should error on wrong size."
209        );
210    }
211
212    #[test]
213    fn decompresses_lzss11() {
214        let test1: [u8; 1] = [0x00];
215        let test2: [u8; 9] = [0x00, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68]; // abcdefgh
216        let test3: [u8; 7] = [0x08, 0x61, 0x62, 0x63, 0x64, 0xF0, 0x03]; // abcdabcdabcdabcdabcdabcd
217        let test4: [u8; 8] = [0x08, 0x61, 0x62, 0x63, 0x64, 0x01, 0x30, 0x03]; // abcdabcdabcdabcdabcdabcd
218        let test5: [u8; 9] = [0x08, 0x61, 0x62, 0x63, 0x64, 0x10, 0x07, 0xB0, 0x03]; // abcdabcdabcdabcdabcdabcd
219        let test6_bad: [u8; 11] = [
220            0x11, 0x10, 0x00, 0x00, 0x08, 0x61, 0x62, 0x63, 0x64, 0xF0, 0x03,
221        ]; // abcdabcdabcdabcdabcdabcd
222        let mut result3: Vec<u8> = Vec::new();
223        let mut result4: Vec<u8> = Vec::new();
224        let mut result5: Vec<u8> = Vec::new();
225
226        for _ in 0..5 {
227            result3.push(0x61);
228            result3.push(0x62);
229            result3.push(0x63);
230            result3.push(0x64);
231        }
232        for _ in 0..10 {
233            result4.push(0x61);
234            result4.push(0x62);
235            result4.push(0x63);
236            result4.push(0x64);
237        }
238        for _ in 0..100 {
239            result5.push(0x61);
240            result5.push(0x62);
241            result5.push(0x63);
242            result5.push(0x64);
243        }
244
245        assert_eq!(
246            0,
247            decompress_lzss11(&mut Cursor::new(test1), 0).unwrap().len()
248        );
249        assert_eq!(
250            &[0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68],
251            decompress_lzss11(&mut Cursor::new(test2), 8)
252                .unwrap()
253                .as_slice()
254        );
255        assert_eq!(
256            result3,
257            decompress_lzss11(&mut Cursor::new(test3), 20).unwrap()
258        );
259        assert_eq!(
260            result4,
261            decompress_lzss11(&mut Cursor::new(test4), 40).unwrap()
262        );
263        assert_eq!(
264            result5,
265            decompress_lzss11(&mut Cursor::new(test5), 400).unwrap()
266        );
267        assert!(
268            decompress(&mut Cursor::new(test6_bad)).is_err(),
269            "Should error on wrong size."
270        );
271    }
272}