ages_prs/
decompress.rs

1//! Decompression of PRS buffers.
2
3use crate::Variant;
4
5use std::collections::VecDeque;
6use std::io::{self, Cursor, Read, Write};
7
8/// An IO source for decoding a PRS stream.
9pub struct PrsDecoder<R: Read, V: Variant> {
10    inner: R,
11    cmds: u8,
12    rem: u8,
13    copy_buf: VecDeque<u8>,
14    eof: bool,
15    pd: std::marker::PhantomData<V>,
16}
17
18// LZ77 commands
19#[derive(Debug)]
20enum Cmd {
21    Literal(u8),
22    Pointer(usize, usize),
23}
24
25impl<R: Read, V: Variant> PrsDecoder<R, V> {
26    pub fn new(inner: R) -> PrsDecoder<R, V> {
27        PrsDecoder {
28            inner,
29            cmds: 0,
30            rem: 0,
31            copy_buf: VecDeque::with_capacity(8191),
32            eof: false,
33            pd: std::marker::PhantomData,
34        }
35    }
36
37    fn read_bit(&mut self) -> io::Result<bool> {
38        if self.rem == 0 {
39            let mut buf = [0; 1];
40            self.inner.read_exact(&mut buf)?;
41            self.cmds = buf[0];
42            self.rem = 8;
43        }
44
45        let ret = self.cmds & 1;
46        self.cmds >>= 1;
47        self.rem -= 1;
48
49        match ret { 0 => Ok(false), _ => Ok(true) }
50    }
51
52    fn next_cmd(&mut self) -> io::Result<Option<Cmd>> {
53        if self.read_bit()? {
54            // literal
55            let mut buf = [0; 1];
56            self.inner.read_exact(&mut buf)?;
57            return Ok(Some(Cmd::Literal(buf[0])));
58        }
59
60        if self.read_bit()? {
61            // long ptr
62            let mut buf = [0; 2];
63            self.inner.read_exact(&mut buf)?;
64            let mut offset = i16::from_le_bytes(buf) as i32;
65
66            if offset == 0 {
67                return Ok(None);
68            }
69
70            let mut size = (offset & 0b111) as usize;
71            offset >>= 3;
72
73            if size == 0 {
74                // next byte is real size
75                self.inner.read_exact(&mut buf[..1])?;
76                size = buf[0] as usize;
77                // it's probably the minimum long-long-copy size
78                size += V::MIN_LONG_COPY_LENGTH as usize;
79            } else {
80                size += 2;
81            }
82            offset |= -8192i32;
83
84            Ok(Some(Cmd::Pointer((-offset) as usize, size)))
85        } else {
86            // short ptr
87            let mut buf = [0; 1];
88            let flag = if self.read_bit()? { 1 } else { 0 };
89            let bit = if self.read_bit()? { 1 } else { 0 };
90            let size = (bit | (flag << 1)) + 2;
91            self.inner.read_exact(&mut buf)?;
92            let offset = buf[0] as i32;
93            let offset = offset | -256i32;
94            
95            Ok(Some(Cmd::Pointer((-offset) as usize, size)))
96        }
97    }
98}
99
100impl<R: Read, V: Variant> Read for PrsDecoder<R, V> {
101    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
102        // first, fill the copy buffer as much as possible
103        while self.copy_buf.len() < 8191 + buf.len() && !self.eof {
104            match self.next_cmd()? {
105                None => {
106                    self.eof = true;
107                    break;
108                },
109                Some(Cmd::Literal(b)) => {
110                    self.copy_buf.push_back(b);
111                },
112                Some(Cmd::Pointer(offset, size)) => {
113                    for _ in 0..size {
114                        if offset == 0 || self.copy_buf.len() < offset {
115                            return Err(io::Error::new(
116                                io::ErrorKind::InvalidData,
117                                "bad pointer copy in stream"
118                            ));
119                        }
120                        self.copy_buf.push_back(self.copy_buf[self.copy_buf.len() - offset]);
121                    }
122                },
123            }
124        }
125
126        // then, drain the amount of the copy buffer that is necessary to read
127        let bytes_read = std::cmp::min(buf.len(), self.copy_buf.len());
128        let mut cursor = Cursor::new(buf);
129        self.copy_buf.drain(..bytes_read).for_each(|b| { cursor.write_all(&[b]).unwrap(); });
130
131        Ok(bytes_read)
132    }
133}