ppmd_rust/lib.rs
1//! PPMd compression / decompression. It's a port of the PPMd C-code from 7-Zip to Rust.
2//!
3//! The following variants are provided:
4//!
5//! - The PPMd7 (PPMdH) as used by the 7z archive format
6//! - The PPMd8 (PPMdI rev.1) as used by the zip archive format
7//!
8//! ## Notice
9//!
10//! There are two ways to properly bound the uncompressed data:
11//! 1. Save the uncompressed size along the compressed data and use `std::io::Read::read_exact()`
12//!    to read the data (this is what is used in the 7z archive format).
13//! 2. Encode an end marker by calling `finish(true)` on the encoder when finishing the encoder
14//!    process. You can then use `std::io::Read::read_to_end()` to read the data. You are of course
15//!    free to also use the `std::io::Read::read_exact()` if you have stored the uncompressed data
16//!    size (this is what is used in the zip archive format).
17//!
18//! Failing to do so will result in garbage symbols at the end of the actual data.
19
20//! ## Acknowledgement
21//!
22//! This port is based on the 7zip version of PPMd by Igor Pavlov, which in turn was based on the
23//! PPMd var.H (2001) / PPMd var.I (2002) code by Dmitry Shkarin. The carryless range coder of
24//! PPMd8 was originally written by Dmitry Subbotin (1999).
25//!
26//! ## License
27//!
28//! The code in this crate is in the public domain as the original code by their authors.
29mod decoder_7;
30mod encoder_7;
31
32mod decoder_8;
33mod encoder_8;
34mod internal;
35
36pub use decoder_7::Ppmd7Decoder;
37pub use decoder_8::Ppmd8Decoder;
38pub use encoder_7::Ppmd7Encoder;
39pub use encoder_8::Ppmd8Encoder;
40
41/// The minimal order PPMd7 supports.
42pub const PPMD7_MIN_ORDER: u32 = 2;
43
44/// The maximal order PPMd7 supports.
45pub const PPMD7_MAX_ORDER: u32 = 64;
46
47/// The minimal memory that PPMd7 supports.
48pub const PPMD7_MIN_MEM_SIZE: u32 = 2048;
49
50/// The maximal memory that PPMd7 supports.
51pub const PPMD7_MAX_MEM_SIZE: u32 = 4294967259;
52
53/// The minimal order PPMd8 supports.
54pub const PPMD8_MIN_ORDER: u32 = 2;
55
56/// The maximal order PPMd8 supports.
57pub const PPMD8_MAX_ORDER: u32 = 16;
58
59/// The minimal memory that PPMd8 supports.
60pub const PPMD8_MIN_MEM_SIZE: u32 = 2048;
61
62/// The maximal memory that PPMd8 supports.
63pub const PPMD8_MAX_MEM_SIZE: u32 = u32::MAX;
64
65const SYM_END: i32 = -1;
66const SYM_ERROR: i32 = -2;
67
68/// Error type of the crate.
69pub type Result<T> = core::result::Result<T, Error>;
70
71/// The restore method used in PPMd8.
72#[derive(Debug, Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash)]
73pub enum RestoreMethod {
74    Restart = 0 as _,
75    CutOff = 1 as _,
76    Unsupported = 2 as _,
77}
78
79macro_rules! impl_from_int_for_restore_method {
80    ($($int_type:ty),+ $(,)?) => {
81        $(
82            impl From<$int_type> for RestoreMethod {
83                fn from(value: $int_type) -> Self {
84                    match value {
85                        0 => RestoreMethod::Restart,
86                        1 => RestoreMethod::CutOff,
87                        _ => RestoreMethod::Unsupported,
88                    }
89                }
90            }
91        )+
92    };
93}
94
95impl_from_int_for_restore_method!(u8, u16, u32, u64, u128, usize);
96impl_from_int_for_restore_method!(i8, i16, i32, i64, i128, isize);
97
98/// Crate error type.
99pub enum Error {
100    /// The range decoder could not be properly initialized.
101    RangeDecoderInitialization,
102    /// Invalid parameters provided.
103    InvalidParameter,
104    /// General IO error.
105    IoError(std::io::Error),
106    /// The needed memory could not be allocated.
107    MemoryAllocation,
108}
109
110impl std::fmt::Debug for Error {
111    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
112        match self {
113            Error::RangeDecoderInitialization => {
114                write!(f, "Could not initialize the range decoder")
115            }
116            Error::InvalidParameter => write!(f, "Wrong PPMd parameter"),
117            Error::IoError(err) => write!(f, "Io error: {err}"),
118            Error::MemoryAllocation => write!(f, "Memory allocation error (out of memory?)"),
119        }
120    }
121}
122
123impl std::fmt::Display for Error {
124    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
125        std::fmt::Debug::fmt(self, f)
126    }
127}
128
129impl std::error::Error for Error {}