1use crate::byte_writer::ByteWriter;
2use crate::memory::Memory;
3use crate::{Error, RestoreMethod};
4use ppmd_sys::{
5 CPpmd8, PPMD8_MAX_ORDER, PPMD8_MIN_ORDER, Ppmd8_Alloc, Ppmd8_Construct, Ppmd8_EncodeSymbol,
6 Ppmd8_Flush_RangeEnc, Ppmd8_Init,
7};
8use std::io::Write;
9
10pub struct Ppmd8Encoder<W: Write> {
12 ppmd: CPpmd8,
13 writer: ByteWriter<W>,
14 _memory: Memory,
15}
16
17impl<W: Write> Ppmd8Encoder<W> {
18 pub fn new(
20 writer: W,
21 order: u32,
22 mem_size: u32,
23 restore_method: RestoreMethod,
24 ) -> crate::Result<Self> {
25 if !(PPMD8_MIN_ORDER..=PPMD8_MAX_ORDER).contains(&order) {
26 return Err(Error::InvalidParameter);
27 }
28
29 let mut ppmd = unsafe { std::mem::zeroed::<CPpmd8>() };
30 unsafe { Ppmd8_Construct(&mut ppmd) };
31
32 let mut memory = Memory::new(mem_size);
33
34 let success = unsafe { Ppmd8_Alloc(&mut ppmd, mem_size, memory.allocation()) };
35
36 if success == 0 {
37 return Err(Error::InternalError("Failed to allocate memory"));
38 }
39
40 let mut writer = ByteWriter::new(writer);
41 ppmd.Stream.Out = writer.byte_out_ptr();
42
43 ppmd.Low = 0;
45 ppmd.Range = 0xFFFFFFFF;
46
47 unsafe { Ppmd8_Init(&mut ppmd, order, restore_method as _) };
48
49 Ok(Self {
50 ppmd,
51 writer,
52 _memory: memory,
53 })
54 }
55
56 fn inner_flush(&mut self) {
57 unsafe { Ppmd8_Flush_RangeEnc(&mut self.ppmd) };
58 self.writer.flush();
59 }
60}
61
62impl<W: Write> Write for Ppmd8Encoder<W> {
63 fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
64 if buf.is_empty() {
65 return Ok(0);
66 }
67
68 buf.iter()
69 .for_each(|byte| unsafe { Ppmd8_EncodeSymbol(&mut self.ppmd as *mut _, *byte as _) });
70
71 Ok(buf.len())
72 }
73
74 fn flush(&mut self) -> std::io::Result<()> {
75 self.inner_flush();
76 Ok(())
77 }
78}
79
80#[cfg(test)]
81mod test {
82 use super::Ppmd8Encoder;
83 use crate::{Ppmd8Decoder, RestoreMethod};
84 use std::io::{Read, Write};
85
86 const ORDER: u32 = 8;
87 const MEM_SIZE: u32 = 262144;
88 const RESTORE_METHOD: RestoreMethod = RestoreMethod::Restart;
89
90 #[test]
91 fn ppmd8encoder_init_drop() {
92 let writer = Vec::new();
93 let encoder = Ppmd8Encoder::new(writer, ORDER, MEM_SIZE, RESTORE_METHOD).unwrap();
94 assert!(!encoder.ppmd.Base.is_null());
95 }
96
97 #[test]
98 fn ppmd8encoder_encode_decode() {
99 let test_data = "Lorem ipsum dolor sit amet. ";
100
101 let mut writer = Vec::new();
102 {
103 let mut encoder =
104 Ppmd8Encoder::new(&mut writer, ORDER, MEM_SIZE, RESTORE_METHOD).unwrap();
105 encoder.write_all(test_data.as_bytes()).unwrap();
106 encoder.flush().unwrap();
107 }
108
109 let mut decoder =
110 Ppmd8Decoder::new(writer.as_slice(), ORDER, MEM_SIZE, RESTORE_METHOD).unwrap();
111
112 let mut decoded = vec![0; test_data.len()];
113 decoder.read_exact(&mut decoded).unwrap();
114
115 assert_eq!(decoded.as_slice(), test_data.as_bytes());
116
117 let decoded_data = String::from_utf8(decoded).unwrap();
118
119 assert_eq!(decoded_data, test_data);
120 }
121}