lzxpress/
data.rs

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        // Check whether the bit specified by flag_count is set or not
67        // set in flags. For example, if flag_count has value 4
68        // check whether the 4th bit of the value in flags is set.
69        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    // Flag placeholder
182    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        // search for the longest match in the window for the lookahead buffer
201        for offset in 1..=max_off {
202            let mut len = 0;
203            str2_off = str1_off - offset;
204
205            // maximum len we can encode into metadata
206            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            // We check if len is better than the value found before, including the
216            // sequence of identical bytes
217            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                // Classical meta-data
250                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}