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). These authors put the original code
25//! into the public domain.
26//!
27//! ## License
28//!
29//! Licensed under [CC-0](https://spdx.org/licenses/CC0-1.0) or
30//! [MIT-0](https://spdx.org/licenses/MIT-0), at your option.
31
32mod internal;
33
34mod decoder_7;
35mod decoder_8;
36mod encoder_7;
37mod encoder_8;
38
39pub use decoder_7::Ppmd7Decoder;
40pub use decoder_8::Ppmd8Decoder;
41pub use encoder_7::Ppmd7Encoder;
42pub use encoder_8::Ppmd8Encoder;
43
44/// The minimal order PPMd7 supports.
45pub const PPMD7_MIN_ORDER: u32 = 2;
46
47/// The maximal order PPMd7 supports.
48pub const PPMD7_MAX_ORDER: u32 = 64;
49
50/// The minimal memory that PPMd7 supports.
51pub const PPMD7_MIN_MEM_SIZE: u32 = 2048;
52
53#[cfg(feature = "unstable-tagged-offsets")]
54/// The maximal memory that PPMd7 supports (512 MiB).
55pub const PPMD7_MAX_MEM_SIZE: u32 = 1 << 29;
56#[cfg(not(feature = "unstable-tagged-offsets"))]
57/// The maximal memory that PPMd7 supports (~4 GiB).
58pub const PPMD7_MAX_MEM_SIZE: u32 = u32::MAX - 36;
59
60/// The minimal order PPMd8 supports.
61pub const PPMD8_MIN_ORDER: u32 = 2;
62
63/// The maximal order PPMd8 supports.
64pub const PPMD8_MAX_ORDER: u32 = 16;
65
66/// The minimal memory that PPMd8 supports.
67pub const PPMD8_MIN_MEM_SIZE: u32 = 2048;
68
69#[cfg(feature = "unstable-tagged-offsets")]
70/// The maximal memory that PPMd8 supports (512 MiB).
71pub const PPMD8_MAX_MEM_SIZE: u32 = 1 << 29;
72#[cfg(not(feature = "unstable-tagged-offsets"))]
73/// The maximal memory that PPMd8 supports (4 GiB).
74pub const PPMD8_MAX_MEM_SIZE: u32 = u32::MAX;
75
76const SYM_END: i32 = -1;
77const SYM_ERROR: i32 = -2;
78
79/// Error type of the crate.
80pub type Result<T> = core::result::Result<T, Error>;
81
82/// The restore method used in PPMd8.
83#[derive(Debug, Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash)]
84pub enum RestoreMethod {
85 Restart = 0 as _,
86 CutOff = 1 as _,
87 Unsupported = 2 as _,
88}
89
90macro_rules! impl_from_int_for_restore_method {
91 ($($int_type:ty),+ $(,)?) => {
92 $(
93 impl From<$int_type> for RestoreMethod {
94 fn from(value: $int_type) -> Self {
95 match value {
96 0 => RestoreMethod::Restart,
97 1 => RestoreMethod::CutOff,
98 _ => RestoreMethod::Unsupported,
99 }
100 }
101 }
102 )+
103 };
104}
105
106impl_from_int_for_restore_method!(u8, u16, u32, u64, u128, usize);
107impl_from_int_for_restore_method!(i8, i16, i32, i64, i128, isize);
108
109/// Crate error type.
110pub enum Error {
111 /// The range decoder could not be properly initialized.
112 RangeDecoderInitialization,
113 /// Invalid parameters provided.
114 InvalidParameter,
115 /// General IO error.
116 IoError(std::io::Error),
117 /// The needed memory could not be allocated.
118 MemoryAllocation,
119}
120
121impl std::fmt::Debug for Error {
122 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
123 match self {
124 Error::RangeDecoderInitialization => {
125 write!(f, "Could not initialize the range decoder")
126 }
127 Error::InvalidParameter => write!(f, "Wrong PPMd parameter"),
128 Error::IoError(err) => write!(f, "Io error: {err}"),
129 Error::MemoryAllocation => write!(f, "Memory allocation error (out of memory?)"),
130 }
131 }
132}
133
134impl std::fmt::Display for Error {
135 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
136 std::fmt::Debug::fmt(self, f)
137 }
138}
139
140impl std::error::Error for Error {}