Skip to main content

sit/
algos.rs

1use std::{
2    io::{self, Seek},
3    rc::Rc,
4};
5
6use sit_algos::huffman::HuffmanReader;
7use sit_algos::huffman_fixed::HuffmanReader as HuffmanFixedReader;
8use sit_algos::lmzw::LmzwReader;
9use sit_algos::lz_huffman::LzHuffmanReader;
10use sit_algos::lzah::LzahReader;
11use sit_algos::lzw::LzwReader;
12use sit_algos::none::NoneReader;
13use sit_algos::rle90::Rle90Reader;
14use sit_algos::{arsenic::ArsenicReader, installer::InstallerReader};
15
16use crate::{Error, VerifyingEntryReader, structs::Algorithm};
17
18pub(crate) enum EntryReader<'a, R: io::Read + io::Seek> {
19    None {
20        reader: NoneReader<&'a mut R>,
21    },
22    Rle {
23        reader: Rle90Reader<NoneReader<&'a mut R>>,
24    },
25    Lzw {
26        reader: Box<LzwReader<NoneReader<&'a mut R>>>,
27    },
28    Huffman {
29        reader: HuffmanReader<NoneReader<&'a mut R>>,
30    },
31    Lzah {
32        reader: Box<LzahReader<NoneReader<&'a mut R>>>,
33    },
34    HuffmanFixed {
35        reader: Box<HuffmanFixedReader<NoneReader<&'a mut R>>>,
36    },
37    Lmzw {
38        reader: Box<LmzwReader<NoneReader<&'a mut R>>>,
39    },
40    LzHuffman {
41        reader: Box<LzHuffmanReader<NoneReader<&'a mut R>>>,
42    },
43    Installer {
44        reader: Box<InstallerReader<NoneReader<&'a mut R>>>,
45    },
46    Arsenic {
47        reader: Box<ArsenicReader<'a, NoneReader<&'a mut R>>>,
48    },
49}
50
51impl<'a, R: io::Read + io::Seek> EntryReader<'a, R> {
52    pub(crate) fn try_from(
53        reader: &'a mut Rc<R>,
54        algo: Algorithm,
55        uncompressed_size: u64,
56        compressed_size: usize,
57        offset: u64,
58    ) -> Result<Self, Error> {
59        unsafe { Rc::get_mut_unchecked(reader).seek(io::SeekFrom::Start(offset))? };
60
61        unsafe {
62            Ok(match algo {
63                Algorithm::None => EntryReader::None {
64                    reader: NoneReader::with_length(
65                        Rc::get_mut_unchecked(reader),
66                        offset,
67                        compressed_size as u64,
68                    ),
69                },
70                Algorithm::RLE => EntryReader::Rle {
71                    reader: Rle90Reader::new(
72                        NoneReader::with_length(
73                            Rc::get_mut_unchecked(reader),
74                            offset,
75                            compressed_size as u64,
76                        ),
77                        uncompressed_size,
78                    ),
79                },
80                Algorithm::LZW => EntryReader::Lzw {
81                    reader: Box::new(LzwReader::new(
82                        NoneReader::with_length(
83                            Rc::get_mut_unchecked(reader),
84                            offset,
85                            compressed_size as u64,
86                        ),
87                        uncompressed_size,
88                    )),
89                },
90                Algorithm::Huffman => EntryReader::Huffman {
91                    reader: HuffmanReader::try_from(
92                        NoneReader::with_length(
93                            Rc::get_mut_unchecked(reader),
94                            offset,
95                            compressed_size as u64,
96                        ),
97                        uncompressed_size,
98                    )?,
99                },
100                Algorithm::LZAH => EntryReader::Lzah {
101                    reader: Box::new(LzahReader::new(
102                        NoneReader::with_length(
103                            Rc::get_mut_unchecked(reader),
104                            offset,
105                            compressed_size as u64,
106                        ),
107                        uncompressed_size,
108                    )),
109                },
110                Algorithm::HuffmanFixed => EntryReader::HuffmanFixed {
111                    reader: Box::new(HuffmanFixedReader::try_from(
112                        NoneReader::with_length(
113                            Rc::get_mut_unchecked(reader),
114                            offset,
115                            compressed_size as u64,
116                        ),
117                        uncompressed_size,
118                    )?),
119                },
120                Algorithm::LZMW => EntryReader::Lmzw {
121                    reader: Box::new(LmzwReader::new(
122                        NoneReader::with_length(
123                            Rc::get_mut_unchecked(reader),
124                            offset,
125                            compressed_size as u64,
126                        ),
127                        uncompressed_size,
128                    )),
129                },
130                Algorithm::LzHuffman => EntryReader::LzHuffman {
131                    reader: Box::new(LzHuffmanReader::new(
132                        NoneReader::with_length(
133                            Rc::get_mut_unchecked(reader),
134                            offset,
135                            compressed_size as u64,
136                        ),
137                        uncompressed_size,
138                    )),
139                },
140                Algorithm::Installer => EntryReader::Installer {
141                    reader: Box::new(InstallerReader::try_new(NoneReader::with_length(
142                        Rc::get_mut_unchecked(reader),
143                        offset,
144                        compressed_size as u64,
145                    ))?),
146                },
147                Algorithm::Arsenic => EntryReader::Arsenic {
148                    reader: Box::new(ArsenicReader::try_from(
149                        NoneReader::with_length(
150                            Rc::get_mut_unchecked(reader),
151                            offset,
152                            compressed_size as u64,
153                        ),
154                        uncompressed_size,
155                    )?),
156                },
157                Algorithm::Unknown(id) => {
158                    return Err(Error::UnsupportedFeature(
159                        crate::error::UnsupportedFeature::Algorithm(Algorithm::Unknown(id)),
160                    ));
161                }
162            })
163        }
164    }
165
166    pub fn verifying(self, checksum: u16) -> VerifyingEntryReader<'a, R> {
167        // Arsenic compression uses 32-bit checksums interleaved with the compressed blocks
168        // so it get's special treatment
169        let is_arsenic = matches!(self, EntryReader::Arsenic { .. });
170
171        VerifyingEntryReader::new(self, checksum, is_arsenic)
172    }
173
174    pub(crate) fn ended(&mut self) -> Result<bool, io::Error> {
175        Ok(self.stream_position()? >= self.stream_len()?)
176    }
177}
178
179impl<'a, R: io::Read + io::Seek> io::Read for EntryReader<'a, R> {
180    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
181        match self {
182            EntryReader::None { reader, .. } => reader.read(buf),
183            EntryReader::Rle { reader, .. } => reader.read(buf),
184            EntryReader::Lzw { reader, .. } => reader.read(buf),
185            EntryReader::Huffman { reader, .. } => reader.read(buf),
186            EntryReader::Lzah { reader, .. } => reader.read(buf),
187            EntryReader::HuffmanFixed { reader, .. } => reader.read(buf),
188            EntryReader::Lmzw { reader, .. } => reader.read(buf),
189            EntryReader::LzHuffman { reader, .. } => reader.read(buf),
190            EntryReader::Installer { reader } => reader.read(buf),
191            EntryReader::Arsenic { reader, .. } => reader.read(buf),
192        }
193    }
194}
195
196impl<'a, R: io::Read + io::Seek> io::Seek for EntryReader<'a, R> {
197    #[inline]
198    fn seek(&mut self, pos: io::SeekFrom) -> io::Result<u64> {
199        match self {
200            EntryReader::None { reader, .. } => reader.seek(pos),
201            EntryReader::Rle { reader, .. } => reader.seek(pos),
202            EntryReader::Lzw { reader, .. } => reader.seek(pos),
203            EntryReader::Huffman { reader, .. } => reader.seek(pos),
204            EntryReader::Lzah { reader, .. } => reader.seek(pos),
205            EntryReader::HuffmanFixed { reader, .. } => reader.seek(pos),
206            EntryReader::Lmzw { reader, .. } => reader.seek(pos),
207            EntryReader::LzHuffman { reader, .. } => reader.seek(pos),
208            EntryReader::Installer { reader } => reader.seek(pos),
209            EntryReader::Arsenic { reader, .. } => reader.seek(pos),
210        }
211    }
212
213    #[inline]
214    fn stream_position(&mut self) -> io::Result<u64> {
215        match self {
216            EntryReader::None { reader, .. } => reader.stream_position(),
217            EntryReader::Rle { reader, .. } => reader.stream_position(),
218            EntryReader::Lzw { reader, .. } => reader.stream_position(),
219            EntryReader::Huffman { reader, .. } => reader.stream_position(),
220            EntryReader::Lzah { reader, .. } => reader.stream_position(),
221            EntryReader::HuffmanFixed { reader, .. } => reader.stream_position(),
222            EntryReader::Lmzw { reader, .. } => reader.stream_position(),
223            EntryReader::LzHuffman { reader, .. } => reader.stream_position(),
224            EntryReader::Installer { reader, .. } => reader.stream_position(),
225            EntryReader::Arsenic { reader, .. } => reader.stream_position(),
226        }
227    }
228
229    #[inline]
230    fn stream_len(&mut self) -> io::Result<u64> {
231        match self {
232            EntryReader::None { reader, .. } => reader.stream_len(),
233            EntryReader::Rle { reader, .. } => reader.stream_len(),
234            EntryReader::Lzw { reader, .. } => reader.stream_len(),
235            EntryReader::Huffman { reader, .. } => reader.stream_len(),
236            EntryReader::Lzah { reader, .. } => reader.stream_len(),
237            EntryReader::HuffmanFixed { reader, .. } => reader.stream_len(),
238            EntryReader::Lmzw { reader, .. } => reader.stream_len(),
239            EntryReader::LzHuffman { reader, .. } => reader.stream_len(),
240            EntryReader::Installer { reader, .. } => reader.stream_len(),
241            EntryReader::Arsenic { reader, .. } => reader.stream_len(),
242        }
243    }
244}