msg_tool\utils/
lzss.rs

1//! LZSS Stream
2use crate::ext::io::*;
3use std::io::{Read, Result};
4
5/// A Lzss Reader
6pub struct LzssReader<T: Read> {
7    reader: T,
8    buf: Vec<u8>,
9    buf_pos: usize,
10    frame: Vec<u8>,
11    frame_mask: usize,
12    frame_pos: usize,
13    tmp: u8,
14    tmp_used: bool,
15}
16
17impl<T: Read> LzssReader<T> {
18    pub fn new(reader: T) -> Self {
19        Self::new2(reader, 0x1000, 0, 0xfee)
20    }
21    pub fn new2(reader: T, frame_size: usize, frame_fill: u8, frame_init_pos: usize) -> Self {
22        Self {
23            reader,
24            buf: Vec::new(),
25            buf_pos: 0,
26            frame: vec![frame_fill; frame_size],
27            frame_mask: frame_size - 1,
28            frame_pos: frame_init_pos,
29            tmp: 0,
30            tmp_used: false,
31        }
32    }
33    fn push(&mut self, buf: &mut MemWriterRef, data: u8) -> Result<()> {
34        if buf.is_eof() {
35            self.buf.push(data);
36        } else {
37            buf.write_u8(data)?;
38        }
39        Ok(())
40    }
41    fn unpack(&mut self, buf: &mut MemWriterRef) -> Result<()> {
42        let mut bu = [0; 1];
43        let mut readed = if self.tmp_used {
44            bu[0] = self.tmp;
45            self.tmp_used = false;
46            1
47        } else {
48            self.reader.read(&mut bu)?
49        };
50        if readed == 0 {
51            // eof
52            return Ok(());
53        }
54        let ctl = bu[0];
55        let mut bit = 1;
56        readed = self.reader.read(&mut bu)?;
57        while bit != 0x100 && readed > 0 {
58            if ((ctl as u32) & bit) != 0 {
59                let b = bu[0];
60                self.frame[self.frame_pos] = b;
61                self.frame_pos += 1;
62                self.frame_pos &= self.frame_mask;
63                self.push(buf, b)?;
64            } else {
65                let lo = bu[0];
66                readed = self.reader.read(&mut bu)?;
67                if readed == 0 {
68                    return Ok(());
69                }
70                let hi = bu[0];
71                let mut offset = (((hi as usize) & 0xF0) << 4) | (lo as usize);
72                let mut count = 3 + (hi & 0xF);
73                while count != 0 {
74                    let v = self.frame[offset];
75                    offset += 1;
76                    offset &= self.frame_mask;
77                    self.frame[self.frame_pos] = v;
78                    self.frame_pos += 1;
79                    self.frame_pos &= self.frame_mask;
80                    self.push(buf, v)?;
81                    count -= 1;
82                }
83            }
84            bit <<= 1;
85            readed = self.reader.read(&mut bu)?;
86        }
87        if readed > 0 {
88            self.tmp = bu[0];
89            self.tmp_used = true;
90        }
91        Ok(())
92    }
93}
94
95impl<R: Read> Read for LzssReader<R> {
96    fn read(&mut self, buf: &mut [u8]) -> Result<usize> {
97        if !self.buf.is_empty() && self.buf_pos < self.buf.len() {
98            let readed = buf.len().min(self.buf.len() - self.buf_pos);
99            buf[..readed].copy_from_slice(&self.buf[self.buf_pos..self.buf_pos + readed]);
100            self.buf_pos += readed;
101            if self.buf_pos == self.buf.len() {
102                self.buf.clear();
103                self.buf_pos = 0;
104            }
105            return Ok(readed);
106        }
107        let mut writer = MemWriterRef::new(buf);
108        self.unpack(&mut writer)?;
109        Ok(writer.pos)
110    }
111}
112
113#[cfg(test)]
114mod tests {
115    use super::*;
116
117    #[test]
118    fn test_literal_only() {
119        let data = [0xFF, 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70, 0x80];
120        let mut reader = LzssReader::new(&data[..]);
121        let mut result = Vec::new();
122        reader.read_to_end(&mut result).unwrap();
123        assert_eq!(result, vec![0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70, 0x80]);
124    }
125
126    #[test]
127    fn test_back_ref() {
128        // "ABCABCABCABCABCABC": 3 literals + 5 back-refs (offset=0, count=3)
129        let data = [0x07, b'A', b'B', b'C', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
130        let mut reader = LzssReader::new2(&data[..], 256, 0, 0);
131        let mut result = Vec::new();
132        reader.read_to_end(&mut result).unwrap();
133        assert_eq!(result, b"ABCABCABCABCABCABC");
134    }
135
136    #[test]
137    fn test_chunked_read() {
138        let data = [0x07, b'A', b'B', b'C', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
139        let mut reader = LzssReader::new2(&data[..], 256, 0, 0);
140        let mut buf = [0u8; 5];
141        let mut result = Vec::new();
142        loop {
143            let n = reader.read(&mut buf).unwrap();
144            if n == 0 {
145                break;
146            }
147            result.extend_from_slice(&buf[..n]);
148        }
149        assert_eq!(result, b"ABCABCABCABCABCABC");
150    }
151
152    #[test]
153    fn test_run_length() {
154        // "AAAAA" via literal 'A' + back-ref (offset=0, count=4) for expanding run
155        let data = [0x01, b'A', 0, 0x01];
156        let mut reader = LzssReader::new2(&data[..], 256, 0, 0);
157        let mut result = Vec::new();
158        reader.read_to_end(&mut result).unwrap();
159        assert_eq!(result, b"AAAAA");
160    }
161
162    #[test]
163    fn test_back_ref_offset() {
164        // "XXXXXABCDEABCDE": literals + back-ref at non-zero offset
165        let data = [
166            0xFF, b'X', b'X', b'X', b'X', b'X', b'A', b'B', b'C', 0x03, b'D', b'E', 0x05, 0x02,
167        ];
168        let mut reader = LzssReader::new2(&data[..], 256, 0, 0);
169        let mut result = Vec::new();
170        reader.read_to_end(&mut result).unwrap();
171        assert_eq!(result, b"XXXXXABCDEABCDE");
172    }
173
174    #[test]
175    fn test_multi_control_byte() {
176        // 16 literals across 2 control bytes
177        let data = [
178            0xFF, b'A', b'B', b'C', b'D', b'E', b'F', b'G', b'H', 0xFF, b'I', b'J', b'K', b'L',
179            b'M', b'N', b'O', b'P',
180        ];
181        let mut reader = LzssReader::new(&data[..]);
182        let mut result = Vec::new();
183        reader.read_to_end(&mut result).unwrap();
184        assert_eq!(result, b"ABCDEFGHIJKLMNOP");
185    }
186}