1use core::fmt;
3use crate::error::{LhaResult, LhaError};
4use crate::stub_io::{Read, Take, discard_to_end};
5
6use crate::crc::Crc16;
7use crate::header::{CompressionMethod, LhaHeader};
8
9#[cfg(feature = "lz")]
10mod lzs;
11#[cfg(feature = "lz")]
12mod lz5;
13#[cfg(feature = "lh1")]
14mod lhv1;
15mod lhv2;
16
17#[cfg(feature = "lz")]
18pub use lzs::*;
19#[cfg(feature = "lz")]
20pub use lz5::*;
21#[cfg(feature = "lh1")]
22pub use lhv1::*;
23pub use lhv2::*;
24
25pub trait Decoder<R> {
27 type Error: fmt::Debug;
28 fn into_inner(self) -> R;
30 fn fill_buffer(&mut self, buf: &mut[u8]) -> Result<(), LhaError<Self::Error>>;
35}
36
37#[derive(Debug)]
57pub struct LhaDecodeReader<R> {
58 header: LhaHeader,
59 crc: Crc16,
60 output_length: u64,
61 decoder: Option<DecoderAny<Take<R>>>
62}
63
64#[derive(Debug)]
66pub struct PassthroughDecoder<R> {
67 inner: R
68}
69
70#[derive(Debug)]
73pub struct UnsupportedDecoder<R> {
74 inner: R
75}
76
77pub struct LhaDecodeError<R: Read> {
84 read: R,
85 source: LhaError<R::Error>
86}
87
88#[non_exhaustive]
89#[derive(Debug)]
90pub enum DecoderAny<R> {
91 PassthroughDecoder(PassthroughDecoder<R>),
92 UnsupportedDecoder(UnsupportedDecoder<R>),
93 #[cfg(feature = "lz")]
94 LzsDecoder(LzsDecoder<R>),
95 #[cfg(feature = "lz")]
96 Lz5Decoder(Lz5Decoder<R>),
97 #[cfg(feature = "lh1")]
98 Lh1Decoder(Lh1Decoder<R>),
99 Lh4Decoder(Lh5Decoder<R>),
100 Lh5Decoder(Lh5Decoder<R>),
101 Lh6Decoder(Lh7Decoder<R>),
102 Lh7Decoder(Lh7Decoder<R>),
103 #[cfg(feature = "lhx")]
104 LhxDecoder(LhxDecoder<R>),
105}
106
107macro_rules! decoder_any_dispatch {
108 (($model:expr)($($spec:tt)*) => $expr:expr) => {
109 match $model {
110 DecoderAny::PassthroughDecoder($($spec)*) => $expr,
111 DecoderAny::UnsupportedDecoder($($spec)*) => $expr,
112 #[cfg(feature = "lz")]
113 DecoderAny::LzsDecoder($($spec)*) => $expr,
114 #[cfg(feature = "lz")]
115 DecoderAny::Lz5Decoder($($spec)*) => $expr,
116 #[cfg(feature = "lh1")]
117 DecoderAny::Lh1Decoder($($spec)*) => $expr,
118 DecoderAny::Lh4Decoder($($spec)*)|
119 DecoderAny::Lh5Decoder($($spec)*) => $expr,
120 DecoderAny::Lh6Decoder($($spec)*)|
121 DecoderAny::Lh7Decoder($($spec)*) => $expr,
122 #[cfg(feature = "lhx")]
123 DecoderAny::LhxDecoder($($spec)*) => $expr,
124 }
125 };
126}
127
128impl<R: Read> Default for LhaDecodeReader<R> {
131 fn default() -> Self {
132 LhaDecodeReader {
133 header: Default::default(),
134 crc: Crc16::default(),
135 output_length: 0,
136 decoder: None
137 }
138 }
139}
140
141impl<R: Read> LhaDecodeReader<R> where R::Error: fmt::Debug {
142 pub fn new(mut rd: R) -> Result<LhaDecodeReader<R>, LhaDecodeError<R>> {
149 let header = match LhaHeader::read(rd.by_ref()).and_then(|h|
150 h.ok_or_else(|| LhaError::HeaderParse("a header is missing"))
151 )
152 {
153 Ok(h) => h,
154 Err(e) => return Err(wrap_err(rd, e))
155 };
156 let decoder = DecoderAny::new_from_header(&header, rd);
157 let crc = Crc16::default();
158 Ok(LhaDecodeReader {
159 header,
160 crc,
161 output_length: 0,
162 decoder: Some(decoder)
163 })
164 }
165 pub fn begin_new(&mut self, mut rd: R) -> Result<bool, LhaDecodeError<R>> {
180 let res = match LhaHeader::read(rd.by_ref()) {
181 Ok(Some(header)) => {
182 let decoder = DecoderAny::new_from_header(&header, rd);
183 self.decoder = Some(decoder);
184 self.header = header;
185 true
186 }
187 Ok(None) => {
188 let decoder = UnsupportedDecoder::new(rd.take(0));
189 self.decoder = Some(DecoderAny::UnsupportedDecoder(decoder));
190 false
191 }
192 Err(e) => return Err(wrap_err(rd, e))
193 };
194 self.crc.reset();
195 self.output_length = 0;
196 Ok(res)
197 }
198 pub fn begin_with_header_and_decoder(&mut self, header: LhaHeader, decoder: DecoderAny<Take<R>>) {
207 self.decoder = Some(decoder);
208 self.header = header;
209 self.crc.reset();
210 self.output_length = 0;
211 }
212 #[cfg(feature = "std")]
232 pub fn next_file(&mut self) -> Result<bool, LhaDecodeError<R>> {
233 self.next_file_with_sink::<{8*1024}>()
234 }
235 #[cfg(not(feature = "std"))]
236 pub fn next_file(&mut self) -> Result<bool, LhaDecodeError<R>> {
237 self.next_file_with_sink::<512>()
238 }
239 pub fn next_file_with_sink<const BUF: usize>(&mut self) -> Result<bool, LhaDecodeError<R>> {
247 let mut limited_rd = self.decoder.take().expect("decoder not empty").into_inner();
248 if limited_rd.limit() != 0 {
249 if let Err(e) = discard_to_end::<_, BUF>(&mut limited_rd).map_err(LhaError::Io) {
250 return Err(wrap_err(limited_rd.into_inner(), e))
251 }
252 }
253 self.begin_new(limited_rd.into_inner())
254 }
255 pub fn header(&self) -> &LhaHeader {
257 &self.header
258 }
259 pub fn into_inner(self) -> R {
264 self.decoder.expect("decoder not empty").into_inner().into_inner()
265 }
266 pub fn take_inner(&mut self) -> Option<R> {
270 self.header.original_size = 0;
271 self.output_length = 0;
272 self.crc.reset();
273 self.decoder.take().map(|decoder| decoder.into_inner().into_inner())
274 }
275 pub fn len(&self) -> u64 {
277 self.header.original_size - self.output_length
278 }
279 pub fn is_empty(&self) -> bool {
281 self.header.original_size == self.output_length
282 }
283 pub fn is_present(&self) -> bool {
285 self.decoder.is_some()
286 }
287 pub fn is_absent(&self) -> bool {
291 self.decoder.is_none()
292 }
293 pub fn crc_is_ok(&self) -> bool {
297 self.crc.sum16() == self.header.file_crc
298 }
299 pub fn crc_check(&self) -> LhaResult<u16, R> {
304 if self.crc_is_ok() {
305 Ok(self.header.file_crc)
306 }
307 else {
308 Err(LhaError::Checksum("crc16 mismatch"))
309 }
310 }
311 pub fn is_decoder_supported(&self) -> bool {
321 self.decoder.as_ref().map(|d| d.is_supported()).unwrap_or(false)
322 }
323}
324
325#[cfg(feature = "std")]
326impl<R: Read<Error=std::io::Error>> std::io::Read for LhaDecodeReader<R> {
327 fn read(&mut self, buf: &mut[u8]) -> std::io::Result<usize> {
328 let len = buf.len().min((self.header.original_size - self.output_length) as usize);
329 let target = &mut buf[..len];
330 self.decoder.as_mut().unwrap().fill_buffer(target)?;
331 self.output_length += len as u64;
332 self.crc.digest(target);
333 Ok(len)
334 }
335}
336
337#[cfg(not(feature = "std"))]
338impl<R: Read> Read for LhaDecodeReader<R> where R::Error: fmt::Debug {
339 type Error = LhaError<R::Error>;
340
341 fn unexpected_eof() -> Self::Error {
342 LhaError::Io(R::unexpected_eof())
343 }
344
345 fn read_all(&mut self, buf: &mut[u8]) -> Result<usize, Self::Error> {
346 let len = buf.len().min((self.header.original_size - self.output_length) as usize);
347 let target = &mut buf[..len];
348 self.decoder.as_mut().unwrap().fill_buffer(target)?;
349 self.output_length += len as u64;
350 self.crc.digest(target);
351 Ok(len)
352 }
353}
354
355impl<R: Read> DecoderAny<R> {
356 pub fn new_from_header(header: &LhaHeader, rd: R) -> DecoderAny<Take<R>> {
358 let limited_rd = rd.take(header.compressed_size);
359 match header.compression_method() {
360 Ok(compression) => DecoderAny::new_from_compression(compression, limited_rd),
361 Err(..) => DecoderAny::UnsupportedDecoder(UnsupportedDecoder::new(limited_rd))
362 }
363 }
364 pub fn new_from_compression(
366 compression: CompressionMethod,
367 rd: R
368 ) -> Self
369 {
370 match compression {
371 CompressionMethod::Pm0|
372 CompressionMethod::Lz4|
373 CompressionMethod::Lh0 => DecoderAny::PassthroughDecoder(PassthroughDecoder::new(rd)),
374 #[cfg(feature = "lz")]
375 CompressionMethod::Lzs => DecoderAny::LzsDecoder(LzsDecoder::new(rd)),
376 #[cfg(feature = "lz")]
377 CompressionMethod::Lz5 => DecoderAny::Lz5Decoder(Lz5Decoder::new(rd)),
378 #[cfg(feature = "lh1")]
379 CompressionMethod::Lh1 => DecoderAny::Lh1Decoder(Lh1Decoder::new(rd)),
380 CompressionMethod::Lh4 => DecoderAny::Lh4Decoder(Lh5Decoder::new(rd)),
381 CompressionMethod::Lh5 => DecoderAny::Lh5Decoder(Lh5Decoder::new(rd)),
382 CompressionMethod::Lh6 => DecoderAny::Lh6Decoder(Lh7Decoder::new(rd)),
383 CompressionMethod::Lh7 => DecoderAny::Lh7Decoder(Lh7Decoder::new(rd)),
384 #[cfg(feature = "lhx")]
385 CompressionMethod::Lhx => DecoderAny::LhxDecoder(LhxDecoder::new(rd)),
386 _ => DecoderAny::UnsupportedDecoder(UnsupportedDecoder::new(rd))
387 }
388 }
389 pub fn is_supported(&self) -> bool {
391 !matches!(self, DecoderAny::UnsupportedDecoder(..))
392 }
393}
394
395impl<R: Read> Decoder<R> for DecoderAny<R> where R::Error: fmt::Debug {
396 type Error = R::Error;
397
398 fn into_inner(self) -> R {
399 decoder_any_dispatch!((self)(decoder) => decoder.into_inner())
400 }
401
402 #[inline]
403 fn fill_buffer(&mut self, buf: &mut[u8]) -> Result<(), LhaError<Self::Error>> {
404 decoder_any_dispatch!((self)(decoder) => decoder.fill_buffer(buf))
405 }
406}
407
408impl<R: Read> PassthroughDecoder<R> {
409 pub fn new(inner: R) -> Self {
410 PassthroughDecoder { inner }
411 }
412}
413
414impl<R: Read> Decoder<R> for PassthroughDecoder<R> where R::Error: fmt::Debug {
415 type Error = R::Error;
416
417 fn into_inner(self) -> R {
418 self.inner
419 }
420
421 #[inline]
422 fn fill_buffer(&mut self, buf: &mut[u8]) -> Result<(), LhaError<Self::Error>> {
423 self.inner.read_exact(buf).map_err(LhaError::Io)
424 }
425}
426
427impl<R: Read> UnsupportedDecoder<R> {
428 pub fn new(inner: R) -> Self {
429 UnsupportedDecoder { inner }
430 }
431}
432
433impl<R: Read> Decoder<R> for UnsupportedDecoder<R> where R::Error: fmt::Debug {
434 type Error = R::Error;
435
436 fn into_inner(self) -> R {
437 self.inner
438 }
439
440 #[inline]
441 fn fill_buffer(&mut self, _buf: &mut[u8]) -> Result<(), LhaError<Self::Error>> {
442 Err(LhaError::Decompress("unsupported compression method"))
443 }
444}
445
446impl<R: Read> LhaDecodeError<R> {
447 pub fn get_ref(&self) -> &R {
449 &self.read
450 }
451 pub fn get_mut(&mut self) -> &mut R {
453 &mut self.read
454 }
455 pub fn into_inner(self) -> R {
457 self.read
458 }
459}
460
461#[cfg(feature = "std")]
462impl<R: Read> std::error::Error for LhaDecodeError<R>
463 where LhaError<R::Error>: std::error::Error + 'static
464{
465 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
466 Some(&self.source)
467 }
468}
469
470impl<R: Read> fmt::Debug for LhaDecodeError<R>
471 where LhaError<R::Error>: fmt::Debug
472{
473 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
474 f.debug_struct("LhaDecodeError")
475 .field("source", &self.source)
476 .finish()
477 }
478}
479
480impl<R: Read> fmt::Display for LhaDecodeError<R>
481 where LhaError<R::Error>: fmt::Display
482{
483 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
484 write!(f, "LHA decode error: {}", self.source)
485 }
486}
487
488impl<R: Read> From<LhaDecodeError<R>> for LhaError<R::Error> {
489 fn from(e: LhaDecodeError<R>) -> Self {
490 e.source
491 }
492}
493
494#[cfg(feature = "std")]
495impl<R: Read> From<LhaDecodeError<R>> for std::io::Error
496 where std::io::Error: From<LhaError<R::Error>>
497{
498 fn from(e: LhaDecodeError<R>) -> Self {
499 e.source.into()
500 }
501}
502
503fn wrap_err<R: Read>(read: R, source: LhaError<R::Error>) -> LhaDecodeError<R> {
504 LhaDecodeError { read, source }
505}
506
507
508#[cfg(feature = "std")]
509#[cfg(test)]
510mod tests {
511 use std::io;
512 use super::*;
513
514 #[test]
515 fn decode_error_works() {
516 let rd = io::Cursor::new(vec![0u8;3]);
517 let mut err = LhaDecodeReader::new(rd).unwrap_err();
518 assert_eq!(err.to_string(), "LHA decode error: while parsing LHA header: a header is missing");
519 assert_eq!(err.get_ref().get_ref(), &vec![0u8;3]);
520 assert_eq!(err.get_mut().get_mut(), &mut vec![0u8;3]);
521 let rd = err.into_inner();
522 assert_eq!(rd.position(), 1);
523 assert_eq!(rd.into_inner(), vec![0u8;3]);
524 }
525}