1use crate::Error;
2use crate::byte_reader::ByteReader;
3use crate::memory::Memory;
4use ppmd_sys::{
5 CPpmd7, PPMD7_MAX_MEM_SIZE, PPMD7_MAX_ORDER, PPMD7_MIN_MEM_SIZE, PPMD7_MIN_ORDER,
6 PPMD7_SYM_END, Ppmd7_Alloc, Ppmd7_Construct, Ppmd7_Free, Ppmd7_Init, Ppmd7z_DecodeSymbol,
7 Ppmd7z_RangeDec_Init,
8};
9use std::io::Read;
10
11pub struct Ppmd7Decoder<R: Read> {
13 ppmd: CPpmd7,
14 _reader: ByteReader<R>,
15 memory: Memory,
16 finished: bool,
17}
18
19impl<R: Read> Ppmd7Decoder<R> {
20 pub fn new(reader: R, order: u32, mem_size: u32) -> crate::Result<Self> {
22 if !(PPMD7_MIN_ORDER..=PPMD7_MAX_ORDER).contains(&order)
23 || !(PPMD7_MIN_MEM_SIZE..=PPMD7_MAX_MEM_SIZE).contains(&mem_size)
24 {
25 return Err(Error::InvalidParameter);
26 }
27
28 let mut ppmd = unsafe { std::mem::zeroed::<CPpmd7>() };
29 unsafe { Ppmd7_Construct(&mut ppmd) };
30
31 let mut memory = Memory::new(mem_size);
32
33 let success = unsafe { Ppmd7_Alloc(&mut ppmd, mem_size, memory.allocation()) };
34
35 if success == 0 {
36 return Err(Error::InternalError("Failed to allocate memory"));
37 }
38
39 let mut reader = ByteReader::new(reader);
40 let range_decoder = unsafe { &mut ppmd.rc.dec };
41 range_decoder.Stream = reader.byte_in_ptr();
42
43 let success = unsafe { Ppmd7z_RangeDec_Init(&mut ppmd.rc.dec) };
44
45 if success == 0 {
46 return Err(Error::InternalError("Failed to initialize range decoder"));
47 }
48
49 unsafe { Ppmd7_Init(&mut ppmd, order) };
50
51 Ok(Self {
52 ppmd,
53 _reader: reader,
54 memory,
55 finished: false,
56 })
57 }
58}
59
60impl<R: Read> Drop for Ppmd7Decoder<R> {
61 fn drop(&mut self) {
62 unsafe { Ppmd7_Free(&mut self.ppmd, self.memory.allocation()) }
63 }
64}
65
66impl<R: Read> Read for Ppmd7Decoder<R> {
67 fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
68 if self.finished {
69 return Ok(0);
70 }
71
72 if buf.is_empty() {
73 return Ok(0);
74 }
75
76 let mut sym = 0;
77 let mut decoded = 0;
78
79 unsafe {
80 for byte in buf.iter_mut() {
81 sym = Ppmd7z_DecodeSymbol(&mut self.ppmd);
82
83 if sym < 0 {
84 break;
85 }
86
87 *byte = sym as u8;
88 decoded += 1;
89 }
90 }
91
92 let code = unsafe { self.ppmd.rc.dec.Code };
93
94 if sym >= 0 && (!self.finished || decoded != buf.len() || code == 0) {
95 return Ok(decoded);
96 }
97
98 self.finished = true;
99
100 if sym != PPMD7_SYM_END || code != 0 {
101 return Err(std::io::Error::new(
102 std::io::ErrorKind::InvalidData,
103 "Error during PPMd decoding",
104 ));
105 }
106
107 Ok(decoded)
108 }
109}
110
111#[cfg(test)]
112mod test {
113 use super::Ppmd7Decoder;
114
115 const ORDER: u32 = 8;
116 const MEM_SIZE: u32 = 262144;
117
118 #[test]
119 fn ppmd7decoder_init_drop() {
120 let reader: &[u8] = &[];
121 let decoder = Ppmd7Decoder::new(reader, ORDER, MEM_SIZE).unwrap();
122 assert!(!decoder.ppmd.Base.is_null());
123 }
124}