Home | History | Annotate | Download | only in src
      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-2014 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 (at) 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 {
     43     lzo_bytep op;
     44     const lzo_bytep ip;
     45     lzo_uint t;
     46 #if defined(COPY_DICT)
     47     lzo_uint m_off;
     48     const lzo_bytep dict_end;
     49 #else
     50     const lzo_bytep m_pos;
     51 #endif
     52 
     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;
     56 #endif
     57 #if defined(LZO1Z)
     58     lzo_uint last_m_off = 0;
     59 #endif
     60 
     61     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     *out_len = 0;
     81 
     82     op = out;
     83     ip = in;
     84 
     85     NEED_IP(1);
     86     if (*ip > 17)
     87     {
     88         t = *ip++ - 17;
     89         if (t < 4)
     90             goto match_next;
     91         assert(t > 0); NEED_OP(t); NEED_IP(t+3);
     92         do *op++ = *ip++; while (--t > 0);
     93         goto first_literal_run;
     94     }
     95 
     96     for (;;)
     97     {
     98         NEED_IP(3);
     99         t = *ip++;
    100         if (t >= 16)
    101             goto match;
    102         /* a literal run */
    103         if (t == 0)
    104         {
    105             while (*ip == 0)
    106             {
    107                 t += 255;
    108                 ip++;
    109                 TEST_IV(t);
    110                 NEED_IP(1);
    111             }
    112             t += 15 + *ip++;
    113         }
    114         /* copy literals */
    115         assert(t > 0); NEED_OP(t+3); NEED_IP(t+6);
    116 #if (LZO_OPT_UNALIGNED64) && (LZO_OPT_UNALIGNED32)
    117         t += 3;
    118         if (t >= 8) do
    119         {
    120             UA_COPY8(op,ip);
    121             op += 8; ip += 8; t -= 8;
    122         } while (t >= 8);
    123         if (t >= 4)
    124         {
    125             UA_COPY4(op,ip);
    126             op += 4; ip += 4; t -= 4;
    127         }
    128         if (t > 0)
    129         {
    130             *op++ = *ip++;
    131             if (t > 1) { *op++ = *ip++; if (t > 2) { *op++ = *ip++; } }
    132         }
    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 first_literal_run:
    167 
    168 
    169         t = *ip++;
    170         if (t >= 16)
    171             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         m_pos = op - (1 + M2_MAX_OFFSET);
    188         m_pos -= t >> 2;
    189         m_pos -= *ip++ << 2;
    190 #endif
    191         TEST_LB(m_pos); NEED_OP(3);
    192         *op++ = *m_pos++; *op++ = *m_pos++; *op++ = *m_pos;
    193 #endif /* COPY_DICT */
    194         goto match_done;
    195 
    196 
    197         /* handle matches */
    198         for (;;) {
    199 match:
    200             if (t >= 64)                /* a M2 match */
    201             {
    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 #if defined(LZO1X)
    222                 m_pos = op - 1;
    223                 m_pos -= (t >> 2) & 7;
    224                 m_pos -= *ip++ << 3;
    225                 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                 TEST_LB(m_pos); assert(t > 0); NEED_OP(t+3-1);
    250                 goto copy_match;
    251 #endif /* COPY_DICT */
    252             }
    253             else if (t >= 32)           /* a M3 match */
    254             {
    255                 t &= 31;
    256                 if (t == 0)
    257                 {
    258                     while (*ip == 0)
    259                     {
    260                         t += 255;
    261                         ip++;
    262                         TEST_OV(t);
    263                         NEED_IP(1);
    264                     }
    265                     t += 31 + *ip++;
    266                     NEED_IP(2);
    267                 }
    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                 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 #endif /* COPY_DICT */
    290                 ip += 2;
    291             }
    292             else if (t >= 16)           /* a M4 match */
    293             {
    294 #if defined(COPY_DICT)
    295                 m_off = (t & 8) << 11;
    296 #else /* !COPY_DICT */
    297                 m_pos = op;
    298                 m_pos -= (t & 8) << 11;
    299 #endif /* COPY_DICT */
    300                 t &= 7;
    301                 if (t == 0)
    302                 {
    303                     while (*ip == 0)
    304                     {
    305                         t += 255;
    306                         ip++;
    307                         TEST_OV(t);
    308                         NEED_IP(1);
    309                     }
    310                     t += 7 + *ip++;
    311                     NEED_IP(2);
    312                 }
    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                 m_pos -= UA_GET_LE16(ip) >> 2;
    331 #else
    332                 m_pos -= (ip[0] >> 2) + (ip[1] << 6);
    333 #endif
    334                 ip += 2;
    335                 if (m_pos == op)
    336                     goto eof_found;
    337                 m_pos -= 0x4000;
    338 #if defined(LZO1Z)
    339                 last_m_off = pd((const lzo_bytep)op, m_pos);
    340 #endif
    341 #endif /* COPY_DICT */
    342             }
    343             else                            /* a M1 match */
    344             {
    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                 m_pos = op - 1;
    361                 m_pos -= t >> 2;
    362                 m_pos -= *ip++ << 2;
    363 #endif
    364                 TEST_LB(m_pos); NEED_OP(2);
    365                 *op++ = *m_pos++; *op++ = *m_pos;
    366 #endif /* COPY_DICT */
    367                 goto match_done;
    368             }
    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             TEST_LB(m_pos); assert(t > 0); NEED_OP(t+3-1);
    379 #if (LZO_OPT_UNALIGNED64) && (LZO_OPT_UNALIGNED32)
    380             if (op - m_pos >= 8)
    381             {
    382                 t += (3 - 1);
    383                 if (t >= 8) do
    384                 {
    385                     UA_COPY8(op,m_pos);
    386                     op += 8; m_pos += 8; t -= 8;
    387                 } while (t >= 8);
    388                 if (t >= 4)
    389                 {
    390                     UA_COPY4(op,m_pos);
    391                     op += 4; m_pos += 4; t -= 4;
    392                 }
    393                 if (t > 0)
    394                 {
    395                     *op++ = m_pos[0];
    396                     if (t > 1) { *op++ = m_pos[1]; if (t > 2) { *op++ = m_pos[2]; } }
    397                 }
    398             }
    399             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             {
    420 copy_match:
    421                 *op++ = *m_pos++; *op++ = *m_pos++;
    422                 do *op++ = *m_pos++; while (--t > 0);
    423             }
    424 
    425 #endif /* COPY_DICT */
    426 
    427 match_done:
    428 #if defined(LZO1Z)
    429             t = ip[-1] & 3;
    430 #else
    431             t = ip[-2] & 3;
    432 #endif
    433             if (t == 0)
    434                 break;
    435 
    436             /* copy literals */
    437 match_next:
    438             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             *op++ = *ip++;
    443             if (t > 1) { *op++ = *ip++; if (t > 2) { *op++ = *ip++; } }
    444 #endif
    445             t = *ip++;
    446         }
    447     }
    448 
    449 eof_found:
    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));
    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 }
    473 
    474 
    475 /*
    476 vi:ts=4:et
    477 */
    478 
    479