Skip to main content

rar_stream/decompress/
mod.rs

1//! RAR decompression algorithms.
2//!
3//! Implements LZSS + Huffman decompression for RAR archives.
4//! Pure Rust implementation for WASM compatibility.
5
6// Work-in-progress: PPM and RAR29 decompression not fully integrated yet
7#![allow(dead_code)]
8
9mod bit_reader;
10mod huffman;
11mod lzss;
12mod ppm;
13mod rar29;
14mod vm;
15
16#[cfg(test)]
17mod tests;
18
19pub use bit_reader::BitReader;
20pub use huffman::{HuffmanDecoder, HuffmanTable};
21pub use lzss::LzssDecoder;
22pub use ppm::PpmModel;
23pub use rar29::Rar29Decoder;
24pub use vm::RarVM;
25
26use std::fmt;
27use std::io;
28
29/// Decompression errors.
30#[derive(Debug)]
31pub enum DecompressError {
32    UnexpectedEof,
33    InvalidHuffmanCode,
34    InvalidBackReference { offset: u32, position: u32 },
35    BufferOverflow,
36    UnsupportedMethod(u8),
37    Io(io::Error),
38}
39
40impl fmt::Display for DecompressError {
41    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
42        match self {
43            Self::UnexpectedEof => write!(f, "Unexpected end of data"),
44            Self::InvalidHuffmanCode => write!(f, "Invalid Huffman code"),
45            Self::InvalidBackReference { offset, position } => {
46                write!(f, "Invalid back reference: offset {} exceeds window position {}", offset, position)
47            }
48            Self::BufferOverflow => write!(f, "Decompression buffer overflow"),
49            Self::UnsupportedMethod(m) => write!(f, "Unsupported compression method: {}", m),
50            Self::Io(e) => write!(f, "I/O error: {}", e),
51        }
52    }
53}
54
55impl std::error::Error for DecompressError {
56    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
57        match self {
58            Self::Io(e) => Some(e),
59            _ => None,
60        }
61    }
62}
63
64impl From<io::Error> for DecompressError {
65    fn from(e: io::Error) -> Self {
66        Self::Io(e)
67    }
68}
69
70pub type Result<T> = std::result::Result<T, DecompressError>;
71
72/// Compression methods used in RAR.
73#[derive(Debug, Clone, Copy, PartialEq, Eq)]
74#[repr(u8)]
75pub enum CompressionMethod {
76    /// Store (no compression)
77    Store = 0x30,
78    /// Fastest compression
79    Fastest = 0x31,
80    /// Fast compression  
81    Fast = 0x32,
82    /// Normal compression
83    Normal = 0x33,
84    /// Good compression
85    Good = 0x34,
86    /// Best compression
87    Best = 0x35,
88}
89
90impl CompressionMethod {
91    pub fn from_u8(v: u8) -> Option<Self> {
92        match v {
93            0x30 => Some(Self::Store),
94            0x31 => Some(Self::Fastest),
95            0x32 => Some(Self::Fast),
96            0x33 => Some(Self::Normal),
97            0x34 => Some(Self::Good),
98            0x35 => Some(Self::Best),
99            _ => None,
100        }
101    }
102
103    /// Whether this method requires decompression.
104    pub fn needs_decompression(&self) -> bool {
105        *self != Self::Store
106    }
107}