/src/lzo-2.10/src/lzo1x_d.ch
Line | Count | Source (jump to first uncovered line) |
1 | | /* lzo1x_d.ch -- implementation of the LZO1X decompression algorithm |
2 | | |
3 | | This file is part of the LZO real-time data compression library. |
4 | | |
5 | | Copyright (C) 1996-2017 Markus Franz Xaver Johannes Oberhumer |
6 | | All Rights Reserved. |
7 | | |
8 | | The LZO library is free software; you can redistribute it and/or |
9 | | modify it under the terms of the GNU General Public License as |
10 | | published by the Free Software Foundation; either version 2 of |
11 | | the License, or (at your option) any later version. |
12 | | |
13 | | The LZO library is distributed in the hope that it will be useful, |
14 | | but WITHOUT ANY WARRANTY; without even the implied warranty of |
15 | | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
16 | | GNU General Public License for more details. |
17 | | |
18 | | You should have received a copy of the GNU General Public License |
19 | | along with the LZO library; see the file COPYING. |
20 | | If not, write to the Free Software Foundation, Inc., |
21 | | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
22 | | |
23 | | Markus F.X.J. Oberhumer |
24 | | <markus@oberhumer.com> |
25 | | http://www.oberhumer.com/opensource/lzo/ |
26 | | */ |
27 | | |
28 | | |
29 | | #include "lzo1_d.ch" |
30 | | |
31 | | |
32 | | /*********************************************************************** |
33 | | // decompress a block of data. |
34 | | ************************************************************************/ |
35 | | |
36 | | #if defined(DO_DECOMPRESS) |
37 | | LZO_PUBLIC(int) |
38 | | DO_DECOMPRESS ( const lzo_bytep in , lzo_uint in_len, |
39 | | lzo_bytep out, lzo_uintp out_len, |
40 | | lzo_voidp wrkmem ) |
41 | | #endif |
42 | 564 | { |
43 | 564 | lzo_bytep op; |
44 | 564 | const lzo_bytep ip; |
45 | 564 | lzo_uint t; |
46 | | #if defined(COPY_DICT) |
47 | | lzo_uint m_off; |
48 | | const lzo_bytep dict_end; |
49 | | #else |
50 | 564 | const lzo_bytep m_pos; |
51 | 564 | #endif |
52 | | |
53 | 564 | const lzo_bytep const ip_end = in + in_len; |
54 | | #if defined(HAVE_ANY_OP) |
55 | | lzo_bytep const op_end = out + *out_len; |
56 | | #endif |
57 | | #if defined(LZO1Z) |
58 | | lzo_uint last_m_off = 0; |
59 | | #endif |
60 | | |
61 | 564 | LZO_UNUSED(wrkmem); |
62 | | |
63 | | #if defined(COPY_DICT) |
64 | | if (dict) |
65 | | { |
66 | | if (dict_len > M4_MAX_OFFSET) |
67 | | { |
68 | | dict += dict_len - M4_MAX_OFFSET; |
69 | | dict_len = M4_MAX_OFFSET; |
70 | | } |
71 | | dict_end = dict + dict_len; |
72 | | } |
73 | | else |
74 | | { |
75 | | dict_len = 0; |
76 | | dict_end = NULL; |
77 | | } |
78 | | #endif /* COPY_DICT */ |
79 | | |
80 | 564 | *out_len = 0; |
81 | | |
82 | 564 | op = out; |
83 | 564 | ip = in; |
84 | | |
85 | 564 | NEED_IP(1); |
86 | 564 | if (*ip > 17) |
87 | 0 | { |
88 | 0 | t = *ip++ - 17; |
89 | 0 | if (t < 4) |
90 | 0 | goto match_next; |
91 | 0 | assert(t > 0); NEED_OP(t); NEED_IP(t+3); |
92 | 0 | do *op++ = *ip++; while (--t > 0); |
93 | 0 | goto first_literal_run; |
94 | 0 | } |
95 | | |
96 | 564 | for (;;) |
97 | 69.3k | { |
98 | 69.3k | NEED_IP(3); |
99 | 69.3k | t = *ip++; |
100 | 69.3k | if (t >= 16) |
101 | 45.7k | goto match; |
102 | | /* a literal run */ |
103 | 23.6k | if (t == 0) |
104 | 7.36k | { |
105 | 61.4k | while (*ip == 0) |
106 | 54.0k | { |
107 | 54.0k | t += 255; |
108 | 54.0k | ip++; |
109 | 54.0k | TEST_IV(t); |
110 | 54.0k | NEED_IP(1); |
111 | 54.0k | } |
112 | 7.36k | t += 15 + *ip++; |
113 | 7.36k | } |
114 | | /* copy literals */ |
115 | 23.6k | assert(t > 0); NEED_OP(t+3); NEED_IP(t+6); |
116 | 23.6k | #if (LZO_OPT_UNALIGNED64) && (LZO_OPT_UNALIGNED32) |
117 | 23.6k | t += 3; |
118 | 23.6k | if (t >= 8) do |
119 | 1.79M | { |
120 | 1.79M | UA_COPY8(op,ip); |
121 | 1.79M | op += 8; ip += 8; t -= 8; |
122 | 1.79M | } while (t >= 8); |
123 | 23.6k | if (t >= 4) |
124 | 15.4k | { |
125 | 15.4k | UA_COPY4(op,ip); |
126 | 15.4k | op += 4; ip += 4; t -= 4; |
127 | 15.4k | } |
128 | 23.6k | if (t > 0) |
129 | 15.0k | { |
130 | 15.0k | *op++ = *ip++; |
131 | 15.0k | if (t > 1) { *op++ = *ip++; if (t > 2) { *op++ = *ip++; } } |
132 | 15.0k | } |
133 | | #elif (LZO_OPT_UNALIGNED32) || (LZO_ALIGNED_OK_4) |
134 | | #if !(LZO_OPT_UNALIGNED32) |
135 | | if (PTR_ALIGNED2_4(op,ip)) |
136 | | { |
137 | | #endif |
138 | | UA_COPY4(op,ip); |
139 | | op += 4; ip += 4; |
140 | | if (--t > 0) |
141 | | { |
142 | | if (t >= 4) |
143 | | { |
144 | | do { |
145 | | UA_COPY4(op,ip); |
146 | | op += 4; ip += 4; t -= 4; |
147 | | } while (t >= 4); |
148 | | if (t > 0) do *op++ = *ip++; while (--t > 0); |
149 | | } |
150 | | else |
151 | | do *op++ = *ip++; while (--t > 0); |
152 | | } |
153 | | #if !(LZO_OPT_UNALIGNED32) |
154 | | } |
155 | | else |
156 | | #endif |
157 | | #endif |
158 | | #if !(LZO_OPT_UNALIGNED32) |
159 | | { |
160 | | *op++ = *ip++; *op++ = *ip++; *op++ = *ip++; |
161 | | do *op++ = *ip++; while (--t > 0); |
162 | | } |
163 | | #endif |
164 | | |
165 | | |
166 | 23.6k | first_literal_run: |
167 | | |
168 | | |
169 | 23.6k | t = *ip++; |
170 | 23.6k | if (t >= 16) |
171 | 23.6k | goto match; |
172 | | #if defined(COPY_DICT) |
173 | | #if defined(LZO1Z) |
174 | | m_off = (1 + M2_MAX_OFFSET) + (t << 6) + (*ip++ >> 2); |
175 | | last_m_off = m_off; |
176 | | #else |
177 | | m_off = (1 + M2_MAX_OFFSET) + (t >> 2) + (*ip++ << 2); |
178 | | #endif |
179 | | NEED_OP(3); |
180 | | t = 3; COPY_DICT(t,m_off) |
181 | | #else /* !COPY_DICT */ |
182 | | #if defined(LZO1Z) |
183 | | t = (1 + M2_MAX_OFFSET) + (t << 6) + (*ip++ >> 2); |
184 | | m_pos = op - t; |
185 | | last_m_off = t; |
186 | | #else |
187 | 0 | m_pos = op - (1 + M2_MAX_OFFSET); |
188 | 0 | m_pos -= t >> 2; |
189 | 0 | m_pos -= *ip++ << 2; |
190 | 0 | #endif |
191 | 0 | TEST_LB(m_pos); NEED_OP(3); |
192 | 0 | *op++ = *m_pos++; *op++ = *m_pos++; *op++ = *m_pos; |
193 | 0 | #endif /* COPY_DICT */ |
194 | 0 | goto match_done; |
195 | | |
196 | | |
197 | | /* handle matches */ |
198 | 22.2k | for (;;) { |
199 | 91.6k | match: |
200 | 91.6k | if (t >= 64) /* a M2 match */ |
201 | 32.3k | { |
202 | | #if defined(COPY_DICT) |
203 | | #if defined(LZO1X) |
204 | | m_off = 1 + ((t >> 2) & 7) + (*ip++ << 3); |
205 | | t = (t >> 5) - 1; |
206 | | #elif defined(LZO1Y) |
207 | | m_off = 1 + ((t >> 2) & 3) + (*ip++ << 2); |
208 | | t = (t >> 4) - 3; |
209 | | #elif defined(LZO1Z) |
210 | | m_off = t & 0x1f; |
211 | | if (m_off >= 0x1c) |
212 | | m_off = last_m_off; |
213 | | else |
214 | | { |
215 | | m_off = 1 + (m_off << 6) + (*ip++ >> 2); |
216 | | last_m_off = m_off; |
217 | | } |
218 | | t = (t >> 5) - 1; |
219 | | #endif |
220 | | #else /* !COPY_DICT */ |
221 | 32.3k | #if defined(LZO1X) |
222 | 32.3k | m_pos = op - 1; |
223 | 32.3k | m_pos -= (t >> 2) & 7; |
224 | 32.3k | m_pos -= *ip++ << 3; |
225 | 32.3k | t = (t >> 5) - 1; |
226 | | #elif defined(LZO1Y) |
227 | | m_pos = op - 1; |
228 | | m_pos -= (t >> 2) & 3; |
229 | | m_pos -= *ip++ << 2; |
230 | | t = (t >> 4) - 3; |
231 | | #elif defined(LZO1Z) |
232 | | { |
233 | | lzo_uint off = t & 0x1f; |
234 | | m_pos = op; |
235 | | if (off >= 0x1c) |
236 | | { |
237 | | assert(last_m_off > 0); |
238 | | m_pos -= last_m_off; |
239 | | } |
240 | | else |
241 | | { |
242 | | off = 1 + (off << 6) + (*ip++ >> 2); |
243 | | m_pos -= off; |
244 | | last_m_off = off; |
245 | | } |
246 | | } |
247 | | t = (t >> 5) - 1; |
248 | | #endif |
249 | 32.3k | TEST_LB(m_pos); assert(t > 0); NEED_OP(t+3-1); |
250 | 32.3k | goto copy_match; |
251 | 32.3k | #endif /* COPY_DICT */ |
252 | 32.3k | } |
253 | 59.2k | else if (t >= 32) /* a M3 match */ |
254 | 53.3k | { |
255 | 53.3k | t &= 31; |
256 | 53.3k | if (t == 0) |
257 | 15.5k | { |
258 | 28.0k | while (*ip == 0) |
259 | 12.4k | { |
260 | 12.4k | t += 255; |
261 | 12.4k | ip++; |
262 | 12.4k | TEST_OV(t); |
263 | 12.4k | NEED_IP(1); |
264 | 12.4k | } |
265 | 15.5k | t += 31 + *ip++; |
266 | 15.5k | NEED_IP(2); |
267 | 15.5k | } |
268 | | #if defined(COPY_DICT) |
269 | | #if defined(LZO1Z) |
270 | | m_off = 1 + (ip[0] << 6) + (ip[1] >> 2); |
271 | | last_m_off = m_off; |
272 | | #else |
273 | | m_off = 1 + (ip[0] >> 2) + (ip[1] << 6); |
274 | | #endif |
275 | | #else /* !COPY_DICT */ |
276 | | #if defined(LZO1Z) |
277 | | { |
278 | | lzo_uint off = 1 + (ip[0] << 6) + (ip[1] >> 2); |
279 | | m_pos = op - off; |
280 | | last_m_off = off; |
281 | | } |
282 | | #elif (LZO_OPT_UNALIGNED16) && (LZO_ABI_LITTLE_ENDIAN) |
283 | | m_pos = op - 1; |
284 | 53.3k | m_pos -= UA_GET_LE16(ip) >> 2; |
285 | | #else |
286 | | m_pos = op - 1; |
287 | | m_pos -= (ip[0] >> 2) + (ip[1] << 6); |
288 | | #endif |
289 | 53.3k | #endif /* COPY_DICT */ |
290 | 53.3k | ip += 2; |
291 | 53.3k | } |
292 | 5.93k | else if (t >= 16) /* a M4 match */ |
293 | 5.93k | { |
294 | | #if defined(COPY_DICT) |
295 | | m_off = (t & 8) << 11; |
296 | | #else /* !COPY_DICT */ |
297 | 5.93k | m_pos = op; |
298 | 5.93k | m_pos -= (t & 8) << 11; |
299 | 5.93k | #endif /* COPY_DICT */ |
300 | 5.93k | t &= 7; |
301 | 5.93k | if (t == 0) |
302 | 3.43k | { |
303 | 6.88k | while (*ip == 0) |
304 | 3.44k | { |
305 | 3.44k | t += 255; |
306 | 3.44k | ip++; |
307 | 3.44k | TEST_OV(t); |
308 | 3.44k | NEED_IP(1); |
309 | 3.44k | } |
310 | 3.43k | t += 7 + *ip++; |
311 | 3.43k | NEED_IP(2); |
312 | 3.43k | } |
313 | | #if defined(COPY_DICT) |
314 | | #if defined(LZO1Z) |
315 | | m_off += (ip[0] << 6) + (ip[1] >> 2); |
316 | | #else |
317 | | m_off += (ip[0] >> 2) + (ip[1] << 6); |
318 | | #endif |
319 | | ip += 2; |
320 | | if (m_off == 0) |
321 | | goto eof_found; |
322 | | m_off += 0x4000; |
323 | | #if defined(LZO1Z) |
324 | | last_m_off = m_off; |
325 | | #endif |
326 | | #else /* !COPY_DICT */ |
327 | | #if defined(LZO1Z) |
328 | | m_pos -= (ip[0] << 6) + (ip[1] >> 2); |
329 | | #elif (LZO_OPT_UNALIGNED16) && (LZO_ABI_LITTLE_ENDIAN) |
330 | 5.93k | m_pos -= UA_GET_LE16(ip) >> 2; |
331 | | #else |
332 | | m_pos -= (ip[0] >> 2) + (ip[1] << 6); |
333 | | #endif |
334 | 5.93k | ip += 2; |
335 | 5.93k | if (m_pos == op) |
336 | 564 | goto eof_found; |
337 | 5.37k | m_pos -= 0x4000; |
338 | | #if defined(LZO1Z) |
339 | | last_m_off = pd((const lzo_bytep)op, m_pos); |
340 | | #endif |
341 | 5.37k | #endif /* COPY_DICT */ |
342 | 5.37k | } |
343 | 0 | else /* a M1 match */ |
344 | 0 | { |
345 | | #if defined(COPY_DICT) |
346 | | #if defined(LZO1Z) |
347 | | m_off = 1 + (t << 6) + (*ip++ >> 2); |
348 | | last_m_off = m_off; |
349 | | #else |
350 | | m_off = 1 + (t >> 2) + (*ip++ << 2); |
351 | | #endif |
352 | | NEED_OP(2); |
353 | | t = 2; COPY_DICT(t,m_off) |
354 | | #else /* !COPY_DICT */ |
355 | | #if defined(LZO1Z) |
356 | | t = 1 + (t << 6) + (*ip++ >> 2); |
357 | | m_pos = op - t; |
358 | | last_m_off = t; |
359 | | #else |
360 | 0 | m_pos = op - 1; |
361 | 0 | m_pos -= t >> 2; |
362 | 0 | m_pos -= *ip++ << 2; |
363 | 0 | #endif |
364 | 0 | TEST_LB(m_pos); NEED_OP(2); |
365 | 0 | *op++ = *m_pos++; *op++ = *m_pos; |
366 | 0 | #endif /* COPY_DICT */ |
367 | 0 | goto match_done; |
368 | 0 | } |
369 | | |
370 | | /* copy match */ |
371 | | #if defined(COPY_DICT) |
372 | | |
373 | | NEED_OP(t+3-1); |
374 | | t += 3-1; COPY_DICT(t,m_off) |
375 | | |
376 | | #else /* !COPY_DICT */ |
377 | | |
378 | 58.7k | TEST_LB(m_pos); assert(t > 0); NEED_OP(t+3-1); |
379 | 58.7k | #if (LZO_OPT_UNALIGNED64) && (LZO_OPT_UNALIGNED32) |
380 | 58.7k | if (op - m_pos >= 8) |
381 | 52.9k | { |
382 | 52.9k | t += (3 - 1); |
383 | 52.9k | if (t >= 8) do |
384 | 547k | { |
385 | 547k | UA_COPY8(op,m_pos); |
386 | 547k | op += 8; m_pos += 8; t -= 8; |
387 | 547k | } while (t >= 8); |
388 | 52.9k | if (t >= 4) |
389 | 27.7k | { |
390 | 27.7k | UA_COPY4(op,m_pos); |
391 | 27.7k | op += 4; m_pos += 4; t -= 4; |
392 | 27.7k | } |
393 | 52.9k | if (t > 0) |
394 | 38.0k | { |
395 | 38.0k | *op++ = m_pos[0]; |
396 | 38.0k | if (t > 1) { *op++ = m_pos[1]; if (t > 2) { *op++ = m_pos[2]; } } |
397 | 38.0k | } |
398 | 52.9k | } |
399 | 5.73k | else |
400 | | #elif (LZO_OPT_UNALIGNED32) || (LZO_ALIGNED_OK_4) |
401 | | #if !(LZO_OPT_UNALIGNED32) |
402 | | if (t >= 2 * 4 - (3 - 1) && PTR_ALIGNED2_4(op,m_pos)) |
403 | | { |
404 | | assert((op - m_pos) >= 4); /* both pointers are aligned */ |
405 | | #else |
406 | | if (t >= 2 * 4 - (3 - 1) && (op - m_pos) >= 4) |
407 | | { |
408 | | #endif |
409 | | UA_COPY4(op,m_pos); |
410 | | op += 4; m_pos += 4; t -= 4 - (3 - 1); |
411 | | do { |
412 | | UA_COPY4(op,m_pos); |
413 | | op += 4; m_pos += 4; t -= 4; |
414 | | } while (t >= 4); |
415 | | if (t > 0) do *op++ = *m_pos++; while (--t > 0); |
416 | | } |
417 | | else |
418 | | #endif |
419 | 5.73k | { |
420 | 38.0k | copy_match: |
421 | 38.0k | *op++ = *m_pos++; *op++ = *m_pos++; |
422 | 1.76M | do *op++ = *m_pos++; while (--t > 0); |
423 | 38.0k | } |
424 | | |
425 | 58.7k | #endif /* COPY_DICT */ |
426 | | |
427 | 91.0k | match_done: |
428 | | #if defined(LZO1Z) |
429 | | t = ip[-1] & 3; |
430 | | #else |
431 | 91.0k | t = ip[-2] & 3; |
432 | 91.0k | #endif |
433 | 91.0k | if (t == 0) |
434 | 68.7k | break; |
435 | | |
436 | | /* copy literals */ |
437 | 22.2k | match_next: |
438 | 22.2k | assert(t > 0); assert(t < 4); NEED_OP(t); NEED_IP(t+3); |
439 | | #if 0 |
440 | | do *op++ = *ip++; while (--t > 0); |
441 | | #else |
442 | 22.2k | *op++ = *ip++; |
443 | 22.2k | if (t > 1) { *op++ = *ip++; if (t > 2) { *op++ = *ip++; } } |
444 | 22.2k | #endif |
445 | 22.2k | t = *ip++; |
446 | 22.2k | } |
447 | 0 | } |
448 | | |
449 | 564 | eof_found: |
450 | 564 | *out_len = pd(op, out); |
451 | 564 | return (ip == ip_end ? LZO_E_OK : |
452 | 564 | (ip < ip_end ? LZO_E_INPUT_NOT_CONSUMED : LZO_E_INPUT_OVERRUN)); |
453 | | |
454 | | |
455 | | #if defined(HAVE_NEED_IP) |
456 | | input_overrun: |
457 | | *out_len = pd(op, out); |
458 | | return LZO_E_INPUT_OVERRUN; |
459 | | #endif |
460 | | |
461 | | #if defined(HAVE_NEED_OP) |
462 | | output_overrun: |
463 | | *out_len = pd(op, out); |
464 | | return LZO_E_OUTPUT_OVERRUN; |
465 | | #endif |
466 | | |
467 | | #if defined(LZO_TEST_OVERRUN_LOOKBEHIND) |
468 | | lookbehind_overrun: |
469 | | *out_len = pd(op, out); |
470 | | return LZO_E_LOOKBEHIND_OVERRUN; |
471 | | #endif |
472 | 564 | } |
473 | | |
474 | | |
475 | | /* vim:set ts=4 sw=4 et: */ |