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