busybox/archival/libarchive/lzo1x_d.c
<<
>>
Prefs
   1/* 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..2008 Markus Franz Xaver Johannes Oberhumer
   6   All Rights Reserved.
   7
   8   Markus F.X.J. Oberhumer <markus@oberhumer.com>
   9   http://www.oberhumer.com/opensource/lzo/
  10
  11   The LZO library is free software; you can redistribute it and/or
  12   modify it under the terms of the GNU General Public License as
  13   published by the Free Software Foundation; either version 2 of
  14   the License, or (at your option) any later version.
  15
  16   The LZO library is distributed in the hope that it will be useful,
  17   but WITHOUT ANY WARRANTY; without even the implied warranty of
  18   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  19   GNU General Public License for more details.
  20
  21   You should have received a copy of the GNU General Public License
  22   along with the LZO library; see the file COPYING.
  23   If not, write to the Free Software Foundation, Inc.,
  24   51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  25 */
  26#include "libbb.h"
  27#include "liblzo.h"
  28
  29/***********************************************************************
  30// decompress a block of data.
  31************************************************************************/
  32/* safe decompression with overrun testing */
  33int lzo1x_decompress_safe(const uint8_t* in, unsigned in_len,
  34                uint8_t* out, unsigned* out_len,
  35                void* wrkmem UNUSED_PARAM)
  36{
  37        register uint8_t* op;
  38        register const uint8_t* ip;
  39        register unsigned t;
  40#if defined(COPY_DICT)
  41        unsigned m_off;
  42        const uint8_t* dict_end;
  43#else
  44        register const uint8_t* m_pos = NULL; /* possibly not needed */
  45#endif
  46        const uint8_t* const ip_end = in + in_len;
  47#if defined(HAVE_ANY_OP)
  48        uint8_t* const op_end = out + *out_len;
  49#endif
  50#if defined(LZO1Z)
  51        unsigned last_m_off = 0;
  52#endif
  53
  54//      LZO_UNUSED(wrkmem);
  55
  56#if defined(COPY_DICT)
  57        if (dict) {
  58                if (dict_len > M4_MAX_OFFSET) {
  59                        dict += dict_len - M4_MAX_OFFSET;
  60                        dict_len = M4_MAX_OFFSET;
  61                }
  62                dict_end = dict + dict_len;
  63        } else {
  64                dict_len = 0;
  65                dict_end = NULL;
  66        }
  67#endif /* COPY_DICT */
  68
  69        *out_len = 0;
  70
  71        op = out;
  72        ip = in;
  73
  74        if (*ip > 17) {
  75                t = *ip++ - 17;
  76                if (t < 4)
  77                        goto match_next;
  78                assert(t > 0); NEED_OP(t); NEED_IP(t+1);
  79                do *op++ = *ip++; while (--t > 0);
  80                goto first_literal_run;
  81        }
  82
  83        while (TEST_IP && TEST_OP) {
  84                t = *ip++;
  85                if (t >= 16)
  86                        goto match;
  87                /* a literal run */
  88                if (t == 0) {
  89                        NEED_IP(1);
  90                        while (*ip == 0) {
  91                                t += 255;
  92                                ip++;
  93                                NEED_IP(1);
  94                        }
  95                        TEST_IV(t);
  96                        t += 15 + *ip++;
  97                }
  98                /* copy literals */
  99                assert(t > 0);
 100                NEED_OP(t+3);
 101                NEED_IP(t+4);
 102#if defined(LZO_UNALIGNED_OK_4) || defined(LZO_ALIGNED_OK_4)
 103# if !defined(LZO_UNALIGNED_OK_4)
 104                if (PTR_ALIGNED2_4(op, ip))
 105# endif
 106                {
 107                        COPY4(op, ip);
 108                        op += 4;
 109                        ip += 4;
 110                        if (--t > 0) {
 111                                if (t >= 4) {
 112                                        do {
 113                                                COPY4(op, ip);
 114                                                op += 4;
 115                                                ip += 4;
 116                                                t -= 4;
 117                                        } while (t >= 4);
 118                                        if (t > 0)
 119                                                do *op++ = *ip++; while (--t > 0);
 120                                } else {
 121                                        do *op++ = *ip++; while (--t > 0);
 122                                }
 123                        }
 124                }
 125# if !defined(LZO_UNALIGNED_OK_4)
 126                else
 127# endif
 128#endif
 129#if !defined(LZO_UNALIGNED_OK_4)
 130                {
 131                        *op++ = *ip++;
 132                        *op++ = *ip++;
 133                        *op++ = *ip++;
 134                        do *op++ = *ip++; while (--t > 0);
 135                }
 136#endif
 137
 138 first_literal_run:
 139                t = *ip++;
 140                if (t >= 16)
 141                        goto match;
 142#if defined(COPY_DICT)
 143#if defined(LZO1Z)
 144                m_off = (1 + M2_MAX_OFFSET) + (t << 6) + (*ip++ >> 2);
 145                last_m_off = m_off;
 146#else
 147                m_off = (1 + M2_MAX_OFFSET) + (t >> 2) + (*ip++ << 2);
 148#endif
 149                NEED_OP(3);
 150                t = 3; COPY_DICT(t,m_off)
 151#else /* !COPY_DICT */
 152#if defined(LZO1Z)
 153                t = (1 + M2_MAX_OFFSET) + (t << 6) + (*ip++ >> 2);
 154                m_pos = op - t;
 155                last_m_off = t;
 156#else
 157                m_pos = op - (1 + M2_MAX_OFFSET);
 158                m_pos -= t >> 2;
 159                m_pos -= *ip++ << 2;
 160#endif
 161                TEST_LB(m_pos); NEED_OP(3);
 162                *op++ = *m_pos++;
 163                *op++ = *m_pos++;
 164                *op++ = *m_pos;
 165#endif /* COPY_DICT */
 166                goto match_done;
 167
 168                /* handle matches */
 169                do {
 170 match:
 171                        if (t >= 64) {          /* a M2 match */
 172#if defined(COPY_DICT)
 173#if defined(LZO1X)
 174                                m_off = 1 + ((t >> 2) & 7) + (*ip++ << 3);
 175                                t = (t >> 5) - 1;
 176#elif defined(LZO1Y)
 177                                m_off = 1 + ((t >> 2) & 3) + (*ip++ << 2);
 178                                t = (t >> 4) - 3;
 179#elif defined(LZO1Z)
 180                                m_off = t & 0x1f;
 181                                if (m_off >= 0x1c)
 182                                        m_off = last_m_off;
 183                                else {
 184                                        m_off = 1 + (m_off << 6) + (*ip++ >> 2);
 185                                        last_m_off = m_off;
 186                                }
 187                                t = (t >> 5) - 1;
 188#endif
 189#else /* !COPY_DICT */
 190#if defined(LZO1X)
 191                                m_pos = op - 1;
 192                                m_pos -= (t >> 2) & 7;
 193                                m_pos -= *ip++ << 3;
 194                                t = (t >> 5) - 1;
 195#elif defined(LZO1Y)
 196                                m_pos = op - 1;
 197                                m_pos -= (t >> 2) & 3;
 198                                m_pos -= *ip++ << 2;
 199                                t = (t >> 4) - 3;
 200#elif defined(LZO1Z)
 201                                {
 202                                        unsigned off = t & 0x1f;
 203                                        m_pos = op;
 204                                        if (off >= 0x1c) {
 205                                                assert(last_m_off > 0);
 206                                                m_pos -= last_m_off;
 207                                        } else {
 208                                                off = 1 + (off << 6) + (*ip++ >> 2);
 209                                                m_pos -= off;
 210                                                last_m_off = off;
 211                                        }
 212                                }
 213                                t = (t >> 5) - 1;
 214#endif
 215                                TEST_LB(m_pos); assert(t > 0); NEED_OP(t+3-1);
 216                                goto copy_match;
 217#endif /* COPY_DICT */
 218                        }
 219                        else if (t >= 32) {                     /* a M3 match */
 220                                t &= 31;
 221                                if (t == 0) {
 222                                        NEED_IP(1);
 223                                        while (*ip == 0) {
 224                                                t += 255;
 225                                                ip++;
 226                                                NEED_IP(1);
 227                                        }
 228                                        TEST_IV(t);
 229                                        t += 31 + *ip++;
 230                                }
 231#if defined(COPY_DICT)
 232#if defined(LZO1Z)
 233                                m_off = 1 + (ip[0] << 6) + (ip[1] >> 2);
 234                                last_m_off = m_off;
 235#else
 236                                m_off = 1 + (ip[0] >> 2) + (ip[1] << 6);
 237#endif
 238#else /* !COPY_DICT */
 239#if defined(LZO1Z)
 240                                {
 241                                        unsigned off = 1 + (ip[0] << 6) + (ip[1] >> 2);
 242                                        m_pos = op - off;
 243                                        last_m_off = off;
 244                                }
 245#elif defined(LZO_UNALIGNED_OK_2) && defined(LZO_ABI_LITTLE_ENDIAN)
 246                                m_pos = op - 1;
 247                                m_pos -= (* (const lzo_ushortp) ip) >> 2;
 248#else
 249                                m_pos = op - 1;
 250                                m_pos -= (ip[0] >> 2) + (ip[1] << 6);
 251#endif
 252#endif /* COPY_DICT */
 253                                ip += 2;
 254                        }
 255                        else if (t >= 16) {                     /* a M4 match */
 256#if defined(COPY_DICT)
 257                                m_off = (t & 8) << 11;
 258#else /* !COPY_DICT */
 259                                m_pos = op;
 260                                m_pos -= (t & 8) << 11;
 261#endif /* COPY_DICT */
 262                                t &= 7;
 263                                if (t == 0) {
 264                                        NEED_IP(1);
 265                                        while (*ip == 0) {
 266                                                t += 255;
 267                                                ip++;
 268                                                NEED_IP(1);
 269                                        }
 270                                        TEST_IV(t);
 271                                        t += 7 + *ip++;
 272                                }
 273#if defined(COPY_DICT)
 274#if defined(LZO1Z)
 275                                m_off += (ip[0] << 6) + (ip[1] >> 2);
 276#else
 277                                m_off += (ip[0] >> 2) + (ip[1] << 6);
 278#endif
 279                                ip += 2;
 280                                if (m_off == 0)
 281                                        goto eof_found;
 282                                m_off += 0x4000;
 283#if defined(LZO1Z)
 284                                last_m_off = m_off;
 285#endif
 286#else /* !COPY_DICT */
 287#if defined(LZO1Z)
 288                                m_pos -= (ip[0] << 6) + (ip[1] >> 2);
 289#elif defined(LZO_UNALIGNED_OK_2) && defined(LZO_ABI_LITTLE_ENDIAN)
 290                                m_pos -= (* (const lzo_ushortp) ip) >> 2;
 291#else
 292                                m_pos -= (ip[0] >> 2) + (ip[1] << 6);
 293#endif
 294                                ip += 2;
 295                                if (m_pos == op)
 296                                        goto eof_found;
 297                                m_pos -= 0x4000;
 298#if defined(LZO1Z)
 299                                last_m_off = pd((const uint8_t*)op, m_pos);
 300#endif
 301#endif /* COPY_DICT */
 302                        }
 303                        else {                          /* a M1 match */
 304#if defined(COPY_DICT)
 305#if defined(LZO1Z)
 306                                m_off = 1 + (t << 6) + (*ip++ >> 2);
 307                                last_m_off = m_off;
 308#else
 309                                m_off = 1 + (t >> 2) + (*ip++ << 2);
 310#endif
 311                                NEED_OP(2);
 312                                t = 2; COPY_DICT(t,m_off)
 313#else /* !COPY_DICT */
 314#if defined(LZO1Z)
 315                                t = 1 + (t << 6) + (*ip++ >> 2);
 316                                m_pos = op - t;
 317                                last_m_off = t;
 318#else
 319                                m_pos = op - 1;
 320                                m_pos -= t >> 2;
 321                                m_pos -= *ip++ << 2;
 322#endif
 323                                TEST_LB(m_pos); NEED_OP(2);
 324                                *op++ = *m_pos++;
 325                                *op++ = *m_pos;
 326#endif /* COPY_DICT */
 327                                goto match_done;
 328                        }
 329
 330                        /* copy match */
 331#if defined(COPY_DICT)
 332
 333                        NEED_OP(t+3-1);
 334                        t += 3-1; COPY_DICT(t,m_off)
 335
 336#else /* !COPY_DICT */
 337
 338                        TEST_LB(m_pos); assert(t > 0); NEED_OP(t+3-1);
 339#if defined(LZO_UNALIGNED_OK_4) || defined(LZO_ALIGNED_OK_4)
 340# if !defined(LZO_UNALIGNED_OK_4)
 341                        if (t >= 2 * 4 - (3 - 1) && PTR_ALIGNED2_4(op,m_pos)) {
 342                                assert((op - m_pos) >= 4);      /* both pointers are aligned */
 343# else
 344                        if (t >= 2 * 4 - (3 - 1) && (op - m_pos) >= 4) {
 345# endif
 346                                COPY4(op,m_pos);
 347                                op += 4; m_pos += 4; t -= 4 - (3 - 1);
 348                                do {
 349                                        COPY4(op,m_pos);
 350                                        op += 4; m_pos += 4; t -= 4;
 351                                } while (t >= 4);
 352                                if (t > 0)
 353                                        do *op++ = *m_pos++; while (--t > 0);
 354                        }
 355                        else
 356#endif
 357                        {
 358 copy_match:
 359                                *op++ = *m_pos++; *op++ = *m_pos++;
 360                                do *op++ = *m_pos++; while (--t > 0);
 361                        }
 362
 363#endif /* COPY_DICT */
 364
 365 match_done:
 366#if defined(LZO1Z)
 367                        t = ip[-1] & 3;
 368#else
 369                        t = ip[-2] & 3;
 370#endif
 371                        if (t == 0)
 372                                break;
 373
 374                        /* copy literals */
 375 match_next:
 376                        assert(t > 0);
 377                        assert(t < 4);
 378                        NEED_OP(t);
 379                        NEED_IP(t+1);
 380#if 0
 381                        do *op++ = *ip++; while (--t > 0);
 382#else
 383                        *op++ = *ip++;
 384                        if (t > 1) {
 385                                *op++ = *ip++;
 386                                if (t > 2)
 387                                        *op++ = *ip++;
 388                        }
 389#endif
 390                        t = *ip++;
 391                } while (TEST_IP && TEST_OP);
 392        }
 393
 394//#if defined(HAVE_TEST_IP) || defined(HAVE_TEST_OP)
 395        /* no EOF code was found */
 396        *out_len = pd(op, out);
 397        return LZO_E_EOF_NOT_FOUND;
 398//#endif
 399
 400 eof_found:
 401        assert(t == 1);
 402        *out_len = pd(op, out);
 403        return (ip == ip_end ? LZO_E_OK :
 404                   (ip < ip_end  ? LZO_E_INPUT_NOT_CONSUMED : LZO_E_INPUT_OVERRUN));
 405
 406//#if defined(HAVE_NEED_IP)
 407 input_overrun:
 408        *out_len = pd(op, out);
 409        return LZO_E_INPUT_OVERRUN;
 410//#endif
 411
 412//#if defined(HAVE_NEED_OP)
 413 output_overrun:
 414        *out_len = pd(op, out);
 415        return LZO_E_OUTPUT_OVERRUN;
 416//#endif
 417
 418//#if defined(LZO_TEST_OVERRUN_LOOKBEHIND)
 419 lookbehind_overrun:
 420        *out_len = pd(op, out);
 421        return LZO_E_LOOKBEHIND_OVERRUN;
 422//#endif
 423}
 424