1use std::io::Write;
2
3use crate::{
4 internal::ppmd8::{PPMd8, RangeEncoder},
5 Error, RestoreMethod, PPMD8_MAX_MEM_SIZE, PPMD8_MAX_ORDER, PPMD8_MIN_MEM_SIZE, PPMD8_MIN_ORDER,
6 SYM_END,
7};
8
9pub struct Ppmd8Encoder<W: Write> {
11 ppmd: PPMd8<RangeEncoder<W>>,
12}
13
14impl<W: Write> Ppmd8Encoder<W> {
15 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 || !(PPMD8_MIN_MEM_SIZE..=PPMD8_MAX_MEM_SIZE).contains(&mem_size)
27 {
28 return Err(Error::InvalidParameter);
29 }
30
31 let ppmd = PPMd8::new_encoder(writer, order, mem_size, restore_method)?;
32
33 Ok(Self { ppmd })
34 }
35
36 pub fn get_ref(&self) -> &W {
38 self.ppmd.get_ref()
39 }
40
41 pub fn get_mut(&mut self) -> &mut W {
46 self.ppmd.get_mut()
47 }
48
49 pub fn into_inner(self) -> W {
51 self.ppmd.into_inner()
52 }
53
54 pub fn finish(mut self, with_end_marker: bool) -> std::io::Result<W> {
58 if with_end_marker {
59 self.ppmd.encode_symbol(SYM_END)?;
60 }
61 self.ppmd.flush_range_encoder()?;
62 Ok(self.into_inner())
63 }
64}
65
66impl<W: Write> Write for Ppmd8Encoder<W> {
67 fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
68 if buf.is_empty() {
69 return Ok(0);
70 }
71
72 for &byte in buf.iter() {
73 self.ppmd.encode_symbol(byte as i32)?;
74 }
75
76 Ok(buf.len())
77 }
78
79 fn flush(&mut self) -> std::io::Result<()> {
82 self.ppmd.get_mut().flush()
83 }
84}
85
86#[cfg(test)]
87mod test {
88 use std::io::{Read, Write};
89
90 use super::{super::decoder_8::Ppmd8Decoder, Ppmd8Encoder, RestoreMethod};
91
92 const ORDER: u32 = 8;
93 const MEM_SIZE: u32 = 262144;
94 const RESTORE_METHOD: RestoreMethod = RestoreMethod::Restart;
95
96 #[test]
97 fn ppmd8encoder_without_end_marker() {
98 let test_data = include_str!("../tests/fixtures/text/apache2.txt");
99
100 let mut writer = Vec::new();
101 {
102 let mut encoder =
103 Ppmd8Encoder::new(&mut writer, ORDER, MEM_SIZE, RESTORE_METHOD).unwrap();
104 encoder.write_all(test_data.as_bytes()).unwrap();
105 encoder.finish(false).unwrap();
106 }
107
108 let mut decoder =
109 Ppmd8Decoder::new(writer.as_slice(), ORDER, MEM_SIZE, RESTORE_METHOD).unwrap();
110
111 let mut decoded = vec![0; test_data.len()];
112 decoder.read_exact(&mut decoded).unwrap();
113
114 let decoded_data = String::from_utf8(decoded).unwrap();
115 assert_eq!(decoded_data, test_data);
116 }
117
118 #[test]
119 fn ppmd8encoder_with_end_marker() {
120 let test_data = include_str!("../tests/fixtures/text/apache2.txt");
121
122 let mut writer = Vec::new();
123 {
124 let mut encoder =
125 Ppmd8Encoder::new(&mut writer, ORDER, MEM_SIZE, RESTORE_METHOD).unwrap();
126 encoder.write_all(test_data.as_bytes()).unwrap();
127 encoder.finish(true).unwrap();
128 }
129
130 let mut decoder =
131 Ppmd8Decoder::new(writer.as_slice(), ORDER, MEM_SIZE, RESTORE_METHOD).unwrap();
132
133 let mut decoded = Vec::new();
134 decoder.read_to_end(&mut decoded).unwrap();
135
136 let decoded_data = String::from_utf8(decoded).unwrap();
137 assert_eq!(decoded_data, test_data);
138 }
139
140 #[test]
141 fn ppmd8encoder_flush_between_writes() {
142 let test_data = include_str!("../tests/fixtures/text/apache2.txt");
143 let (first, second) = test_data.as_bytes().split_at(test_data.len() / 2);
144
145 let encode = |flush: bool| {
146 let mut data = Vec::new();
147 {
148 let mut encoder =
149 Ppmd8Encoder::new(&mut data, ORDER, MEM_SIZE, RESTORE_METHOD).unwrap();
150 encoder.write_all(first).unwrap();
151 if flush {
152 encoder.flush().unwrap();
153 }
154 encoder.write_all(second).unwrap();
155 encoder.finish(true).unwrap();
156 }
157 data
158 };
159
160 let data = encode(true);
161 assert_eq!(data, encode(false));
162
163 let mut decoder =
164 Ppmd8Decoder::new(data.as_slice(), ORDER, MEM_SIZE, RESTORE_METHOD).unwrap();
165
166 let mut decoded = Vec::new();
167 decoder.read_to_end(&mut decoded).unwrap();
168
169 let decoded_data = String::from_utf8(decoded).unwrap();
170 assert_eq!(decoded_data, test_data);
171 }
172}