1 /* lzo1x_d.ch -- implementation of the LZO1X decompression algorithm
3 This file is part of the LZO real-time data compression library.
5 Copyright (C) 1996-2015 Markus Franz Xaver Johannes Oberhumer
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.
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.
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.
23 Markus F.X.J. Oberhumer
24 <markus@oberhumer.com>
25 http://www.oberhumer.com/opensource/lzo/
32 /***********************************************************************
33 // decompress a block of data.
34 ************************************************************************/
36 #if defined(DO_DECOMPRESS)
38 DO_DECOMPRESS ( const lzo_bytep in , lzo_uint in_len,
39 lzo_bytep out, lzo_uintp out_len,
46 #if defined(COPY_DICT)
48 const lzo_bytep dict_end;
50 const lzo_bytep m_pos;
53 const lzo_bytep const ip_end = in + in_len;
54 #if defined(HAVE_ANY_OP)
55 lzo_bytep const op_end = out + *out_len;
58 lzo_uint last_m_off = 0;
63 #if defined(COPY_DICT)
66 if (dict_len > M4_MAX_OFFSET)
68 dict += dict_len - M4_MAX_OFFSET;
69 dict_len = M4_MAX_OFFSET;
71 dict_end = dict + dict_len;
78 #endif /* COPY_DICT */
91 assert(t > 0); NEED_OP(t); NEED_IP(t+3);
92 do *op++ = *ip++; while (--t > 0);
93 goto first_literal_run;
115 assert(t > 0); NEED_OP(t+3); NEED_IP(t+6);
116 #if (LZO_OPT_UNALIGNED64) && (LZO_OPT_UNALIGNED32)
121 op += 8; ip += 8; t -= 8;
126 op += 4; ip += 4; t -= 4;
131 if (t > 1) { *op++ = *ip++; if (t > 2) { *op++ = *ip++; } }
133 #elif (LZO_OPT_UNALIGNED32) || (LZO_ALIGNED_OK_4)
134 #if !(LZO_OPT_UNALIGNED32)
135 if (PTR_ALIGNED2_4(op,ip))
146 op += 4; ip += 4; t -= 4;
148 if (t > 0) do *op++ = *ip++; while (--t > 0);
151 do *op++ = *ip++; while (--t > 0);
153 #if !(LZO_OPT_UNALIGNED32)
158 #if !(LZO_OPT_UNALIGNED32)
160 *op++ = *ip++; *op++ = *ip++; *op++ = *ip++;
161 do *op++ = *ip++; while (--t > 0);
172 #if defined(COPY_DICT)
174 m_off = (1 + M2_MAX_OFFSET) + (t << 6) + (*ip++ >> 2);
177 m_off = (1 + M2_MAX_OFFSET) + (t >> 2) + (*ip++ << 2);
180 t = 3; COPY_DICT(t,m_off)
181 #else /* !COPY_DICT */
183 t = (1 + M2_MAX_OFFSET) + (t << 6) + (*ip++ >> 2);
187 m_pos = op - (1 + M2_MAX_OFFSET);
191 TEST_LB(m_pos); NEED_OP(3);
192 *op++ = *m_pos++; *op++ = *m_pos++; *op++ = *m_pos;
193 #endif /* COPY_DICT */
200 if (t >= 64) /* a M2 match */
202 #if defined(COPY_DICT)
204 m_off = 1 + ((t >> 2) & 7) + (*ip++ << 3);
207 m_off = 1 + ((t >> 2) & 3) + (*ip++ << 2);
215 m_off = 1 + (m_off << 6) + (*ip++ >> 2);
220 #else /* !COPY_DICT */
223 m_pos -= (t >> 2) & 7;
228 m_pos -= (t >> 2) & 3;
233 lzo_uint off = t & 0x1f;
237 assert(last_m_off > 0);
242 off = 1 + (off << 6) + (*ip++ >> 2);
249 TEST_LB(m_pos); assert(t > 0); NEED_OP(t+3-1);
251 #endif /* COPY_DICT */
253 else if (t >= 32) /* a M3 match */
268 #if defined(COPY_DICT)
270 m_off = 1 + (ip[0] << 6) + (ip[1] >> 2);
273 m_off = 1 + (ip[0] >> 2) + (ip[1] << 6);
275 #else /* !COPY_DICT */
278 lzo_uint off = 1 + (ip[0] << 6) + (ip[1] >> 2);
282 #elif (LZO_OPT_UNALIGNED16) && (LZO_ABI_LITTLE_ENDIAN)
284 m_pos -= UA_GET_LE16(ip) >> 2;
287 m_pos -= (ip[0] >> 2) + (ip[1] << 6);
289 #endif /* COPY_DICT */
292 else if (t >= 16) /* a M4 match */
294 #if defined(COPY_DICT)
295 m_off = (t & 8) << 11;
296 #else /* !COPY_DICT */
298 m_pos -= (t & 8) << 11;
299 #endif /* COPY_DICT */
313 #if defined(COPY_DICT)
315 m_off += (ip[0] << 6) + (ip[1] >> 2);
317 m_off += (ip[0] >> 2) + (ip[1] << 6);
326 #else /* !COPY_DICT */
328 m_pos -= (ip[0] << 6) + (ip[1] >> 2);
329 #elif (LZO_OPT_UNALIGNED16) && (LZO_ABI_LITTLE_ENDIAN)
330 m_pos -= UA_GET_LE16(ip) >> 2;
332 m_pos -= (ip[0] >> 2) + (ip[1] << 6);
339 last_m_off = pd((const lzo_bytep)op, m_pos);
341 #endif /* COPY_DICT */
343 else /* a M1 match */
345 #if defined(COPY_DICT)
347 m_off = 1 + (t << 6) + (*ip++ >> 2);
350 m_off = 1 + (t >> 2) + (*ip++ << 2);
353 t = 2; COPY_DICT(t,m_off)
354 #else /* !COPY_DICT */
356 t = 1 + (t << 6) + (*ip++ >> 2);
364 TEST_LB(m_pos); NEED_OP(2);
365 *op++ = *m_pos++; *op++ = *m_pos;
366 #endif /* COPY_DICT */
371 #if defined(COPY_DICT)
374 t += 3-1; COPY_DICT(t,m_off)
376 #else /* !COPY_DICT */
378 TEST_LB(m_pos); assert(t > 0); NEED_OP(t+3-1);
379 #if (LZO_OPT_UNALIGNED64) && (LZO_OPT_UNALIGNED32)
386 op += 8; m_pos += 8; t -= 8;
391 op += 4; m_pos += 4; t -= 4;
396 if (t > 1) { *op++ = m_pos[1]; if (t > 2) { *op++ = m_pos[2]; } }
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))
404 assert((op - m_pos) >= 4); /* both pointers are aligned */
406 if (t >= 2 * 4 - (3 - 1) && (op - m_pos) >= 4)
410 op += 4; m_pos += 4; t -= 4 - (3 - 1);
413 op += 4; m_pos += 4; t -= 4;
415 if (t > 0) do *op++ = *m_pos++; while (--t > 0);
421 *op++ = *m_pos++; *op++ = *m_pos++;
422 do *op++ = *m_pos++; while (--t > 0);
425 #endif /* COPY_DICT */
438 assert(t > 0); assert(t < 4); NEED_OP(t); NEED_IP(t+3);
440 do *op++ = *ip++; while (--t > 0);
443 if (t > 1) { *op++ = *ip++; if (t > 2) { *op++ = *ip++; } }
450 *out_len = pd(op, out);
451 return (ip == ip_end ? LZO_E_OK :
452 (ip < ip_end ? LZO_E_INPUT_NOT_CONSUMED : LZO_E_INPUT_OVERRUN));
455 #if defined(HAVE_NEED_IP)
457 *out_len = pd(op, out);
458 return LZO_E_INPUT_OVERRUN;
461 #if defined(HAVE_NEED_OP)
463 *out_len = pd(op, out);
464 return LZO_E_OUTPUT_OVERRUN;
467 #if defined(LZO_TEST_OVERRUN_LOOKBEHIND)
469 *out_len = pd(op, out);
470 return LZO_E_LOOKBEHIND_OVERRUN;
475 /* vim:set ts=4 sw=4 et: */