lzma_rust2/lzip/
reader.rs1use alloc::vec::Vec;
2
3use super::{LzipHeader, LzipTrailer, CRC32, HEADER_SIZE, TRAILER_SIZE};
4use crate::{error_invalid_data, error_invalid_input, CountingReader, LzmaReader, Read, Result};
5
6pub struct LzipReader<R> {
8 inner: Option<R>,
9 lzma_reader: Option<LzmaReader<CountingReader<R>>>,
10 current_header: Option<LzipHeader>,
11 finished: bool,
12 trailer_buf: Vec<u8>,
13 crc_digest: Option<crc::Digest<'static, u32, crc::Table<16>>>,
14 data_size: u64,
15}
16
17impl<R> LzipReader<R> {
18 pub fn into_inner(mut self) -> R {
20 if let Some(lzma_reader) = self.lzma_reader.take() {
21 return lzma_reader.into_inner().inner;
22 }
23
24 self.inner.take().expect("inner reader not set")
25 }
26
27 pub fn inner(&self) -> &R {
29 self.lzma_reader
30 .as_ref()
31 .map(|reader| reader.inner().inner())
32 .unwrap_or_else(|| self.inner.as_ref().expect("inner reader not set"))
33 }
34
35 pub fn inner_mut(&mut self) -> &mut R {
37 self.lzma_reader
38 .as_mut()
39 .map(|reader| reader.inner_mut().inner_mut())
40 .unwrap_or_else(|| self.inner.as_mut().expect("inner reader not set"))
41 }
42}
43
44impl<R: Read> LzipReader<R> {
45 pub fn new(inner: R) -> Self {
47 Self {
48 inner: Some(inner),
49 lzma_reader: None,
50 current_header: None,
51 finished: false,
52 trailer_buf: Vec::with_capacity(TRAILER_SIZE),
53 crc_digest: None,
54 data_size: 0,
55 }
56 }
57
58 fn start_next_member(&mut self) -> Result<bool> {
61 let mut reader = self.inner.take().expect("inner reader not set");
62
63 let header = match LzipHeader::parse(&mut reader) {
64 Ok(header) => header,
65 Err(_) => {
66 self.inner = Some(reader);
69 return Ok(false);
70 }
71 };
72
73 if header.version != 1 {
74 return Err(error_invalid_input("unsupported LZIP version"));
75 }
76
77 let counting_reader = CountingReader::new(reader);
78
79 let lzma_reader =
85 LzmaReader::new(counting_reader, u64::MAX, 3, 0, 2, header.dict_size, None)?;
86
87 self.current_header = Some(header);
88 self.lzma_reader = Some(lzma_reader);
89 self.trailer_buf.clear();
90 self.crc_digest = Some(CRC32.digest());
91 self.data_size = 0;
92
93 Ok(true)
94 }
95
96 fn finish_current_member(&mut self) -> Result<()> {
97 let lzma_reader = self.lzma_reader.take().expect("lzma reader not set");
98
99 let counting_reader = lzma_reader.into_inner();
100 let compressed_bytes = counting_reader.bytes_read();
101
102 let mut inner_reader = counting_reader.inner;
103 let trailer = LzipTrailer::parse(&mut inner_reader)?;
104
105 let computed_crc = self.crc_digest.take().expect("no CRC digest").finalize();
106
107 if computed_crc != trailer.crc32 {
108 self.inner = Some(inner_reader);
109 return Err(error_invalid_data("LZIP CRC32 mismatch"));
110 }
111
112 if self.data_size != trailer.data_size {
113 self.inner = Some(inner_reader);
114 return Err(error_invalid_data("LZIP data size mismatch"));
115 }
116
117 let actual_member_size = HEADER_SIZE as u64 + compressed_bytes + TRAILER_SIZE as u64;
118 if actual_member_size != trailer.member_size {
119 self.inner = Some(inner_reader);
120 return Err(error_invalid_data("LZIP member size mismatch"));
121 }
122
123 self.inner = Some(inner_reader);
125
126 Ok(())
127 }
128}
129
130impl<R: Read> Read for LzipReader<R> {
131 fn read(&mut self, buf: &mut [u8]) -> Result<usize> {
132 if buf.is_empty() {
133 return Ok(0);
134 }
135
136 loop {
137 if let Some(ref mut lzma_reader) = self.lzma_reader {
139 match lzma_reader.read(buf) {
140 Ok(0) => {
141 self.finish_current_member()?;
143
144 if !self.start_next_member()? {
145 self.finished = true;
147 return Ok(0);
148 }
149
150 continue;
152 }
153 Ok(bytes_read) => {
154 if let Some(ref mut crc_digest) = self.crc_digest {
156 crc_digest.update(&buf[..bytes_read]);
157 self.data_size += bytes_read as u64;
158 }
159 return Ok(bytes_read);
160 }
161 Err(e) => {
162 return Err(e);
163 }
164 }
165 } else if self.finished {
166 return Ok(0);
168 } else {
169 if !self.start_next_member()? {
171 self.finished = true;
173 return Ok(0);
174 }
175 }
176 }
177 }
178}