1use std::mem;
2use std::cmp;
3
4pub use crate::error::Error;
5
6macro_rules! store32le{
7 ($dst:expr,$idx:expr,$val:expr)=>{
8 {
9 $dst[$idx + 0] = $val as u8;
10 $dst[$idx + 1] = ($val >> 8) as u8;
11 $dst[$idx + 2] = ($val >> 16) as u8;
12 $dst[$idx + 3] = ($val >> 24) as u8;
13 }
14 }
15 }
16
17macro_rules! load16le{
18 ($dst:expr,$src:expr,$idx:expr)=>{
19 {
20 $dst = (u32::from($src[$idx + 1]) << 8
21 | u32::from($src[$idx])) as usize;
22 }
23 }
24}
25
26macro_rules! load32le{
27 ($dst:expr,$src:expr,$idx:expr)=>{
28 {
29 $dst = ((u32::from($src[$idx + 3]) << 24)
30 | (u32::from($src[$idx + 2]) << 16)
31 | (u32::from($src[$idx + 1]) << 8)
32 | u32::from($src[$idx])) as usize;
33 }
34 }
35}
36
37pub fn decompress(
38 in_buf: &[u8]
39) -> Result<Vec<u8>, Error>
40{
41 let mut out_idx: usize = 0;
42 let mut in_idx: usize = 0;
43 let mut nibble_idx: usize = 0;
44
45 let mut flags: usize = 0;
46 let mut flag_count: usize = 0;
47
48 let mut length: usize;
49 let mut offset: usize;
50
51 let mut out_buf: Vec<u8> = Vec::new();
52
53 while in_idx < in_buf.len() {
54 if flag_count == 0 {
55 if (in_idx + 3) >= in_buf.len() {
56 return Err(Error::MemLimit);
57 }
58
59 load32le!(flags, in_buf, in_idx);
60 in_idx += mem::size_of::<u32>();
61 flag_count = 32;
62 }
63
64 flag_count -= 1;
65
66 if (flags & (1 << flag_count)) == 0 {
70 if in_idx >= in_buf.len() {
71 return Err(Error::MemLimit);
72 }
73 out_buf.push(in_buf[in_idx]);
74
75 in_idx += mem::size_of::<u8>();
76 out_idx += mem::size_of::<u8>();
77 } else {
78 if (in_idx + 1) >= in_buf.len() {
79 return Err(Error::MemLimit);
80 }
81
82 load16le!(length, in_buf, in_idx);
83 in_idx += mem::size_of::<u16>();
84
85 offset = (length / 8) + 1;
86 length = length % 8;
87
88 if length == 7 {
89 if nibble_idx == 0 {
90 if in_idx >= in_buf.len() {
91 return Err(Error::MemLimit);
92 }
93
94 length = (in_buf[in_idx] % 16).into();
95 nibble_idx = in_idx;
96 in_idx += mem::size_of::<u8>();
97 } else {
98 if nibble_idx >= in_buf.len() {
99 return Err(Error::MemLimit);
100 }
101
102 length = (in_buf[nibble_idx] / 16).into();
103 nibble_idx = 0;
104 }
105
106 if length == 15 {
107 if in_idx >= in_buf.len() {
108 return Err(Error::MemLimit);
109 }
110
111 length = in_buf[in_idx].into();
112 in_idx += mem::size_of::<u8>();
113
114 if length == 255 {
115 if (in_idx + 1) >= in_buf.len() {
116 return Err(Error::MemLimit);
117 }
118
119 load16le!(length, in_buf, in_idx);
120 in_idx += mem::size_of::<u16>();
121
122 if length == 0 {
123 load32le!(length, in_buf, in_idx);
124 in_idx += mem::size_of::<u32>();
125 }
126
127 if length < 15 + 7 {
128 return Err(Error::CorruptedData);
129 }
130 length -= 15 + 7;
131 }
132 length += 15;
133 }
134 length += 7;
135 }
136 length += 3;
137
138 for _i in 0..length {
139 if offset > out_idx {
140 return Err(Error::CorruptedData);
141 }
142
143 out_buf.push(out_buf[out_idx - offset]);
144 out_idx += mem::size_of::<u8>();
145 }
146 }
147 }
148
149 Ok(out_buf)
150}
151
152pub fn compress(
153 in_buf: &[u8]
154) -> Result<Vec<u8>, Error>
155{
156
157 let mut in_idx: usize = 0;
158 let mut out_idx: usize;
159 let mut byte_left: usize;
160
161 let mut max_off: usize;
162 let mut match_off: usize;
163
164 let mut max_len: usize;
165 let mut best_len: usize;
166
167 let mut flags: u32 = 0;
168 let mut flag_count: u32 = 0;
169 let mut flag_out_off: usize = 0;
170 let mut nibble_index: usize = 0;
171
172 let mut metadata_size: usize;
173 let mut metadata: usize;
174 let mut _dest_off: usize;
175
176 let mut str1_off: usize;
177 let mut str2_off: usize;
178
179 let mut out_buf: Vec<u8> = Vec::new();
180
181 out_buf.push(0);
183 out_buf.push(0);
184 out_buf.push(0);
185 out_buf.push(0);
186 out_idx = mem::size_of::<u32>();
187
188 while in_idx < in_buf.len() {
189 let mut found: bool = false;
190 byte_left = in_buf.len() - in_idx;
191 max_off = in_idx;
192
193 str1_off = in_idx;
194
195 best_len = 2;
196 match_off = 0;
197
198 max_off = cmp::min(8192, max_off);
199
200 for offset in 1..=max_off {
202 let mut len = 0;
203 str2_off = str1_off - offset;
204
205 max_len = cmp::min(8192, byte_left);
207
208 for i in 0..max_len {
209 if in_buf[str1_off + i] != in_buf[str2_off + i] {
210 break;
211 }
212 len = i + 1;
213 }
214
215 if len > best_len {
218 found = true;
219 best_len = len;
220 match_off = offset;
221 }
222 }
223
224 if !found {
225 out_buf.push(in_buf[in_idx]);
226 out_idx += 1;
227 in_idx += 1;
228
229 flags <<= 1;
230 flag_count += 1;
231 if flag_count == 32 {
232 store32le!(out_buf, flag_out_off, flags);
233 flag_count = 0;
234 flag_out_off = out_idx;
235 out_buf.push(0);
236 out_buf.push(0);
237 out_buf.push(0);
238 out_buf.push(0);
239 out_idx += mem::size_of::<u32>();
240 }
241 } else {
242 let mut match_len = best_len;
243 metadata_size = 0;
244
245 match_len -= 3;
246 match_off -= 1;
247
248 if match_len < 7 {
249 metadata = (match_off << 3) + match_len;
251 out_buf.push(metadata as u8);
252 out_buf.push((metadata >> 8) as u8);
253 metadata_size += mem::size_of::<u16>();
254 } else {
255 let mut has_extra_len: bool = false;
256
257 metadata = (match_off << 3) | 7;
258 out_buf.push(metadata as u8);
259 out_buf.push((metadata >> 8) as u8);
260 metadata_size += mem::size_of::<u16>();
261
262 match_len -= 7;
263
264 if nibble_index == 0 {
265 nibble_index = out_idx;
266 if match_len < 15 {
267 out_buf.push(match_len as u8);
268 metadata_size += mem::size_of::<u8>();
269 } else {
270 out_buf.push(15);
271 metadata_size += mem::size_of::<u8>();
272
273 has_extra_len = true;
274 }
275 } else {
276 if match_len < 15 {
277 out_buf[nibble_index] |= (match_len << 4) as u8;
278 nibble_index = 0;
279 } else {
280 out_buf[nibble_index] |= (15 << 4) as u8;
281 nibble_index = 0;
282
283 has_extra_len = true;
284 }
285 }
286
287 if has_extra_len {
288 match_len -= 15;
289
290 if match_len < 255 {
291 out_buf.push(match_len as u8);
292 metadata_size += mem::size_of::<u8>();
293 } else {
294 out_buf.push(255);
295 metadata_size += mem::size_of::<u8>();
296
297 match_len += 7 + 15;
298
299 if match_len < (1 << 16) {
300 out_buf.push(match_len as u8);
301 out_buf.push((match_len >> 8) as u8);
302 metadata_size += mem::size_of::<u16>();
303 } else {
304 out_buf.push(0);
305 out_buf.push(0);
306 metadata_size += mem::size_of::<u16>();
307 out_buf.push(match_len as u8);
308 out_buf.push((match_len >> 8) as u8);
309 out_buf.push((match_len >> 16) as u8);
310 out_buf.push((match_len >> 24) as u8);
311 metadata_size += mem::size_of::<u32>();
312 }
313 }
314 }
315 }
316
317 flags = (flags << 1) | 1;
318 flag_count += 1;
319 if flag_count == 32 {
320 store32le!(out_buf, flag_out_off, flags);
321 flag_count = 0;
322 flag_out_off = out_idx;
323 out_buf.push(0);
324 out_buf.push(0);
325 out_buf.push(0);
326 out_buf.push(0);
327 out_idx += mem::size_of::<u32>();
328 }
329
330 out_idx += metadata_size;
331 in_idx += best_len;
332 }
333 }
334
335 flags <<= 32 - flag_count;
336 flags |= (1 << (32 - flag_count)) - 1;
337 store32le!(out_buf, flag_out_off, flags);
338
339 Ok(out_buf)
340}