busybox/archival/lzop.c
<<
>>
Prefs
   1/*
   2   This file is part of the lzop file compressor.
   3
   4   Copyright (C) 1996..2003 Markus Franz Xaver Johannes Oberhumer
   5   All Rights Reserved.
   6
   7   Markus F.X.J. Oberhumer <markus@oberhumer.com>
   8   http://www.oberhumer.com/opensource/lzop/
   9
  10   lzop and the LZO library are free software; you can redistribute them
  11   and/or modify them under the terms of the GNU General Public License as
  12   published by the Free Software Foundation; either version 2 of
  13   the License, or (at your option) any later version.
  14
  15   This program is distributed in the hope that it will be useful,
  16   but WITHOUT ANY WARRANTY; without even the implied warranty of
  17   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  18   GNU General Public License for more details.
  19
  20   You should have received a copy of the GNU General Public License
  21   along with this program; see the file COPYING.
  22   If not, write to the Free Software Foundation, Inc.,
  23   59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  24
  25   "Minimalized" for busybox by Alain Knaff
  26*/
  27
  28//config:config LZOP
  29//config:       bool "lzop"
  30//config:       default y
  31//config:       help
  32//config:         Lzop compression/decompresion.
  33//config:
  34//config:config UNLZOP
  35//config:       bool "unlzop"
  36//config:       default y
  37//config:       help
  38//config:         Lzop decompresion.
  39//config:
  40//config:config LZOPCAT
  41//config:       bool "lzopcat"
  42//config:       default y
  43//config:       help
  44//config:         Alias to "unlzop -c".
  45//config:
  46//config:config LZOP_COMPR_HIGH
  47//config:       bool "lzop compression levels 7,8,9 (not very useful)"
  48//config:       default n
  49//config:       depends on LZOP || UNLZOP || LZOPCAT
  50//config:       help
  51//config:         High levels (7,8,9) of lzop compression. These levels
  52//config:         are actually slower than gzip at equivalent compression ratios
  53//config:         and take up 3.2K of code.
  54
  55//applet:IF_LZOP(APPLET(lzop, BB_DIR_BIN, BB_SUID_DROP))
  56//applet:IF_UNLZOP(APPLET_ODDNAME(unlzop, lzop, BB_DIR_USR_BIN, BB_SUID_DROP, unlzop))
  57//applet:IF_LZOPCAT(APPLET_ODDNAME(lzopcat, lzop, BB_DIR_USR_BIN, BB_SUID_DROP, lzopcat))
  58//kbuild:lib-$(CONFIG_LZOP) += lzop.o
  59//kbuild:lib-$(CONFIG_UNLZOP) += lzop.o
  60//kbuild:lib-$(CONFIG_LZOPCAT) += lzop.o
  61
  62//usage:#define lzop_trivial_usage
  63//usage:       "[-cfvd123456789CF] [FILE]..."
  64//usage:#define lzop_full_usage "\n\n"
  65//usage:       "        -1..9   Compression level"
  66//usage:     "\n        -d      Decompress"
  67//usage:     "\n        -c      Write to stdout"
  68//usage:     "\n        -f      Force"
  69//usage:     "\n        -v      Verbose"
  70//usage:     "\n        -F      Don't store or verify checksum"
  71//usage:     "\n        -C      Also write checksum of compressed block"
  72//usage:
  73//usage:#define lzopcat_trivial_usage
  74//usage:       "[-vF] [FILE]..."
  75//usage:#define lzopcat_full_usage "\n\n"
  76//usage:       "        -v      Verbose"
  77//usage:     "\n        -F      Don't verify checksum"
  78//usage:
  79//usage:#define unlzop_trivial_usage
  80//usage:       "[-cfvF] [FILE]..."
  81//usage:#define unlzop_full_usage "\n\n"
  82//usage:       "        -c      Write to stdout"
  83//usage:     "\n        -f      Force"
  84//usage:     "\n        -v      Verbose"
  85//usage:     "\n        -F      Don't verify checksum"
  86
  87#include "libbb.h"
  88#include "common_bufsiz.h"
  89#include "bb_archive.h"
  90#include "liblzo_interface.h"
  91
  92/* lzo-2.03/src/lzo_ptr.h */
  93#define pd(a,b)  ((unsigned)((a)-(b)))
  94
  95#define lzo_version()                   LZO_VERSION
  96#define lzo_sizeof_dict_t               (sizeof(uint8_t*))
  97
  98/* lzo-2.03/include/lzo/lzo1x.h */
  99#define LZO1X_1_MEM_COMPRESS    (16384 * lzo_sizeof_dict_t)
 100#define LZO1X_1_15_MEM_COMPRESS (32768 * lzo_sizeof_dict_t)
 101#define LZO1X_999_MEM_COMPRESS  (14 * 16384 * sizeof(short))
 102
 103/* lzo-2.03/src/lzo1x_oo.c */
 104#define NO_LIT UINT_MAX
 105
 106/**********************************************************************/
 107static void copy2(uint8_t* ip, const uint8_t* m_pos, unsigned off)
 108{
 109        ip[0] = m_pos[0];
 110        if (off == 1)
 111                ip[1] = m_pos[0];
 112        else
 113                ip[1] = m_pos[1];
 114}
 115
 116static void copy3(uint8_t* ip, const uint8_t* m_pos, unsigned off)
 117{
 118        ip[0] = m_pos[0];
 119        if (off == 1) {
 120                ip[2] = ip[1] = m_pos[0];
 121        }
 122        else if (off == 2) {
 123                ip[1] = m_pos[1];
 124                ip[2] = m_pos[0];
 125        }
 126        else {
 127                ip[1] = m_pos[1];
 128                ip[2] = m_pos[2];
 129        }
 130}
 131
 132/**********************************************************************/
 133// optimize a block of data.
 134/**********************************************************************/
 135#define TEST_IP         (ip < ip_end)
 136#define TEST_OP         (op <= op_end)
 137
 138static NOINLINE int lzo1x_optimize(uint8_t *in, unsigned in_len,
 139                uint8_t *out, unsigned *out_len,
 140                void* wrkmem UNUSED_PARAM)
 141{
 142        uint8_t* op;
 143        uint8_t* ip;
 144        unsigned t;
 145        uint8_t* m_pos;
 146        uint8_t* const ip_end = in + in_len;
 147        uint8_t* const op_end = out + *out_len;
 148        uint8_t* litp = NULL;
 149        unsigned lit = 0;
 150        unsigned next_lit = NO_LIT;
 151        unsigned nl;
 152        unsigned long o_m1_a = 0, o_m1_b = 0, o_m2 = 0, o_m3_a = 0, o_m3_b = 0;
 153
 154//      LZO_UNUSED(wrkmem);
 155
 156        *out_len = 0;
 157
 158        op = out;
 159        ip = in;
 160
 161        if (*ip > 17) {
 162                t = *ip++ - 17;
 163                if (t < 4)
 164                        goto match_next;
 165                goto first_literal_run;
 166        }
 167
 168        while (TEST_IP && TEST_OP) {
 169                t = *ip++;
 170                if (t >= 16)
 171                        goto match;
 172                /* a literal run */
 173                litp = ip - 1;
 174                if (t == 0) {
 175                        t = 15;
 176                        while (*ip == 0)
 177                                t += 255, ip++;
 178                        t += *ip++;
 179                }
 180                lit = t + 3;
 181                /* copy literals */
 182 copy_literal_run:
 183                *op++ = *ip++;
 184                *op++ = *ip++;
 185                *op++ = *ip++;
 186 first_literal_run:
 187                do *op++ = *ip++; while (--t > 0);
 188
 189                t = *ip++;
 190
 191                if (t >= 16)
 192                        goto match;
 193#if defined(LZO1X)
 194                m_pos = op - 1 - 0x800;
 195#elif defined(LZO1Y)
 196                m_pos = op - 1 - 0x400;
 197#endif
 198                m_pos -= t >> 2;
 199                m_pos -= *ip++ << 2;
 200                *op++ = *m_pos++;
 201                *op++ = *m_pos++;
 202                *op++ = *m_pos++;
 203                lit = 0;
 204                goto match_done;
 205
 206
 207                /* handle matches */
 208                do {
 209                        if (t < 16) { /* a M1 match */
 210                                m_pos = op - 1;
 211                                m_pos -= t >> 2;
 212                                m_pos -= *ip++ << 2;
 213
 214                                if (litp == NULL)
 215                                        goto copy_m1;
 216
 217                                nl = ip[-2] & 3;
 218                                /* test if a match follows */
 219                                if (nl == 0 && lit == 1 && ip[0] >= 16) {
 220                                        next_lit = nl;
 221                                        /* adjust length of previous short run */
 222                                        lit += 2;
 223                                        *litp = (unsigned char)((*litp & ~3) | lit);
 224                                        /* copy over the 2 literals that replace the match */
 225                                        copy2(ip-2, m_pos, pd(op, m_pos));
 226                                        o_m1_a++;
 227                                }
 228                                /* test if a literal run follows */
 229                                else
 230                                if (nl == 0
 231                                 && ip[0] < 16
 232                                 && ip[0] != 0
 233                                 && (lit + 2 + ip[0] < 16)
 234                                ) {
 235                                        t = *ip++;
 236                                        /* remove short run */
 237                                        *litp &= ~3;
 238                                        /* copy over the 2 literals that replace the match */
 239                                        copy2(ip-3+1, m_pos, pd(op, m_pos));
 240                                        /* move literals 1 byte ahead */
 241                                        litp += 2;
 242                                        if (lit > 0)
 243                                                memmove(litp+1, litp, lit);
 244                                        /* insert new length of long literal run */
 245                                        lit += 2 + t + 3;
 246                                        *litp = (unsigned char)(lit - 3);
 247
 248                                        o_m1_b++;
 249                                        *op++ = *m_pos++;
 250                                        *op++ = *m_pos++;
 251                                        goto copy_literal_run;
 252                                }
 253 copy_m1:
 254                                *op++ = *m_pos++;
 255                                *op++ = *m_pos++;
 256                        } else {
 257 match:
 258                                if (t >= 64) {                          /* a M2 match */
 259                                        m_pos = op - 1;
 260#if defined(LZO1X)
 261                                        m_pos -= (t >> 2) & 7;
 262                                        m_pos -= *ip++ << 3;
 263                                        t = (t >> 5) - 1;
 264#elif defined(LZO1Y)
 265                                        m_pos -= (t >> 2) & 3;
 266                                        m_pos -= *ip++ << 2;
 267                                        t = (t >> 4) - 3;
 268#endif
 269                                        if (litp == NULL)
 270                                                goto copy_m;
 271
 272                                        nl = ip[-2] & 3;
 273                                        /* test if in beetween two long literal runs */
 274                                        if (t == 1 && lit > 3 && nl == 0
 275                                         && ip[0] < 16 && ip[0] != 0 && (lit + 3 + ip[0] < 16)
 276                                        ) {
 277                                                t = *ip++;
 278                                                /* copy over the 3 literals that replace the match */
 279                                                copy3(ip-1-2, m_pos, pd(op, m_pos));
 280                                                /* set new length of previous literal run */
 281                                                lit += 3 + t + 3;
 282                                                *litp = (unsigned char)(lit - 3);
 283                                                o_m2++;
 284                                                *op++ = *m_pos++;
 285                                                *op++ = *m_pos++;
 286                                                *op++ = *m_pos++;
 287                                                goto copy_literal_run;
 288                                        }
 289                                } else {
 290                                        if (t >= 32) {                  /* a M3 match */
 291                                                t &= 31;
 292                                                if (t == 0) {
 293                                                        t = 31;
 294                                                        while (*ip == 0)
 295                                                                t += 255, ip++;
 296                                                        t += *ip++;
 297                                                }
 298                                                m_pos = op - 1;
 299                                                m_pos -= *ip++ >> 2;
 300                                                m_pos -= *ip++ << 6;
 301                                        } else {                                        /* a M4 match */
 302                                                m_pos = op;
 303                                                m_pos -= (t & 8) << 11;
 304                                                t &= 7;
 305                                                if (t == 0) {
 306                                                        t = 7;
 307                                                        while (*ip == 0)
 308                                                                t += 255, ip++;
 309                                                        t += *ip++;
 310                                                }
 311                                                m_pos -= *ip++ >> 2;
 312                                                m_pos -= *ip++ << 6;
 313                                                if (m_pos == op)
 314                                                        goto eof_found;
 315                                                m_pos -= 0x4000;
 316                                        }
 317                                        if (litp == NULL)
 318                                                goto copy_m;
 319
 320                                        nl = ip[-2] & 3;
 321                                        /* test if in beetween two matches */
 322                                        if (t == 1 && lit == 0 && nl == 0 && ip[0] >= 16) {
 323                                                next_lit = nl;
 324                                                /* make a previous short run */
 325                                                lit += 3;
 326                                                *litp = (unsigned char)((*litp & ~3) | lit);
 327                                                /* copy over the 3 literals that replace the match */
 328                                                copy3(ip-3, m_pos, pd(op, m_pos));
 329                                                o_m3_a++;
 330                                        }
 331                                        /* test if a literal run follows */
 332                                        else if (t == 1 && lit <= 3 && nl == 0
 333                                         && ip[0] < 16 && ip[0] != 0 && (lit + 3 + ip[0] < 16)
 334                                        ) {
 335                                                t = *ip++;
 336                                                /* remove short run */
 337                                                *litp &= ~3;
 338                                                /* copy over the 3 literals that replace the match */
 339                                                copy3(ip-4+1, m_pos, pd(op, m_pos));
 340                                                /* move literals 1 byte ahead */
 341                                                litp += 2;
 342                                                if (lit > 0)
 343                                                        memmove(litp+1,litp,lit);
 344                                                /* insert new length of long literal run */
 345                                                lit += 3 + t + 3;
 346                                                *litp = (unsigned char)(lit - 3);
 347
 348                                                o_m3_b++;
 349                                                *op++ = *m_pos++;
 350                                                *op++ = *m_pos++;
 351                                                *op++ = *m_pos++;
 352                                                goto copy_literal_run;
 353                                        }
 354                                }
 355 copy_m:
 356                                *op++ = *m_pos++;
 357                                *op++ = *m_pos++;
 358                                do *op++ = *m_pos++; while (--t > 0);
 359                        }
 360
 361 match_done:
 362                        if (next_lit == NO_LIT) {
 363                                t = ip[-2] & 3;
 364                                lit = t;
 365                                litp = ip - 2;
 366                        }
 367                        else
 368                                t = next_lit;
 369                        next_lit = NO_LIT;
 370                        if (t == 0)
 371                                break;
 372                        /* copy literals */
 373 match_next:
 374                        do *op++ = *ip++; while (--t > 0);
 375                        t = *ip++;
 376                } while (TEST_IP && TEST_OP);
 377        }
 378
 379        /* no EOF code was found */
 380        *out_len = pd(op, out);
 381        return LZO_E_EOF_NOT_FOUND;
 382
 383 eof_found:
 384//      LZO_UNUSED(o_m1_a); LZO_UNUSED(o_m1_b); LZO_UNUSED(o_m2);
 385//      LZO_UNUSED(o_m3_a); LZO_UNUSED(o_m3_b);
 386        *out_len = pd(op, out);
 387        return (ip == ip_end ? LZO_E_OK :
 388                (ip < ip_end ? LZO_E_INPUT_NOT_CONSUMED : LZO_E_INPUT_OVERRUN));
 389}
 390
 391/**********************************************************************/
 392#define F_OS F_OS_UNIX
 393#define F_CS F_CS_NATIVE
 394
 395/**********************************************************************/
 396#define ADLER32_INIT_VALUE 1
 397#define CRC32_INIT_VALUE   0
 398
 399/**********************************************************************/
 400enum {
 401        M_LZO1X_1    = 1,
 402        M_LZO1X_1_15 = 2,
 403        M_LZO1X_999  = 3,
 404};
 405
 406/**********************************************************************/
 407/* header flags */
 408#define F_ADLER32_D     0x00000001L
 409#define F_ADLER32_C     0x00000002L
 410#define F_H_EXTRA_FIELD 0x00000040L
 411#define F_H_GMTDIFF     0x00000080L
 412#define F_CRC32_D       0x00000100L
 413#define F_CRC32_C       0x00000200L
 414#define F_H_FILTER      0x00000800L
 415#define F_H_CRC32       0x00001000L
 416#define F_MASK          0x00003FFFL
 417
 418/* operating system & file system that created the file [mostly unused] */
 419#define F_OS_UNIX       0x03000000L
 420#define F_OS_SHIFT      24
 421#define F_OS_MASK       0xff000000L
 422
 423/* character set for file name encoding [mostly unused] */
 424#define F_CS_NATIVE     0x00000000L
 425#define F_CS_SHIFT      20
 426#define F_CS_MASK       0x00f00000L
 427
 428/* these bits must be zero */
 429#define F_RESERVED      ((F_MASK | F_OS_MASK | F_CS_MASK) ^ 0xffffffffL)
 430
 431typedef struct chksum_t {
 432        uint32_t f_adler32;
 433        uint32_t f_crc32;
 434} chksum_t;
 435
 436typedef struct header_t {
 437        unsigned version;
 438        unsigned lib_version;
 439        unsigned version_needed_to_extract;
 440        uint32_t flags;
 441        uint32_t mode;
 442        uint32_t mtime;
 443        uint32_t gmtdiff;
 444        uint32_t header_checksum;
 445
 446        uint32_t extra_field_len;
 447        uint32_t extra_field_checksum;
 448
 449        unsigned char method;
 450        unsigned char level;
 451
 452        /* info */
 453        char name[255+1];
 454} header_t;
 455
 456struct globals {
 457        /*const uint32_t *lzo_crc32_table;*/
 458        chksum_t chksum_in;
 459        chksum_t chksum_out;
 460} FIX_ALIASING;
 461#define G (*(struct globals*)bb_common_bufsiz1)
 462#define INIT_G() do { setup_common_bufsiz(); } while (0)
 463//#define G (*ptr_to_globals)
 464//#define INIT_G() do {
 465//      SET_PTR_TO_GLOBALS(xzalloc(sizeof(G)));
 466//} while (0)
 467
 468
 469/**********************************************************************/
 470#define LZOP_VERSION            0x1010
 471//#define LZOP_VERSION_STRING     "1.01"
 472//#define LZOP_VERSION_DATE       "Apr 27th 2003"
 473
 474#define OPTION_STRING "cfvqdt123456789CF"
 475
 476/* Note: must be kept in sync with archival/bbunzip.c */
 477enum {
 478        OPT_STDOUT      = (1 << 0),
 479        OPT_FORCE       = (1 << 1),
 480        OPT_VERBOSE     = (1 << 2),
 481        OPT_QUIET       = (1 << 3),
 482        OPT_DECOMPRESS  = (1 << 4),
 483        OPT_TEST        = (1 << 5),
 484        OPT_1           = (1 << 6),
 485        OPT_2           = (1 << 7),
 486        OPT_3           = (1 << 8),
 487        OPT_4           = (1 << 9),
 488        OPT_5           = (1 << 10),
 489        OPT_6           = (1 << 11),
 490        OPT_789         = (7 << 12),
 491        OPT_7           = (1 << 13),
 492        OPT_8           = (1 << 14),
 493        OPT_C           = (1 << 15),
 494        OPT_F           = (1 << 16),
 495};
 496
 497/**********************************************************************/
 498// adler32 checksum
 499// adapted from free code by Mark Adler <madler@alumni.caltech.edu>
 500// see http://www.zlib.org/
 501/**********************************************************************/
 502static FAST_FUNC uint32_t
 503lzo_adler32(uint32_t adler, const uint8_t* buf, unsigned len)
 504{
 505        enum {
 506                LZO_BASE = 65521, /* largest prime smaller than 65536 */
 507                /* NMAX is the largest n such that
 508                 * 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1 */
 509                LZO_NMAX = 5552,
 510        };
 511        uint32_t s1 = adler & 0xffff;
 512        uint32_t s2 = (adler >> 16) & 0xffff;
 513        unsigned k;
 514
 515        if (buf == NULL)
 516                return 1;
 517
 518        while (len > 0) {
 519                k = len < LZO_NMAX ? (unsigned) len : LZO_NMAX;
 520                len -= k;
 521                if (k != 0) do {
 522                        s1 += *buf++;
 523                        s2 += s1;
 524                } while (--k > 0);
 525                s1 %= LZO_BASE;
 526                s2 %= LZO_BASE;
 527        }
 528        return (s2 << 16) | s1;
 529}
 530
 531static FAST_FUNC uint32_t
 532lzo_crc32(uint32_t c, const uint8_t* buf, unsigned len)
 533{
 534        //if (buf == NULL) - impossible
 535        //      return 0;
 536
 537        return ~crc32_block_endian0(~c, buf, len, global_crc32_table);
 538}
 539
 540/**********************************************************************/
 541static void init_chksum(chksum_t *ct)
 542{
 543        ct->f_adler32 = ADLER32_INIT_VALUE;
 544        ct->f_crc32 = CRC32_INIT_VALUE;
 545}
 546
 547static void add_bytes_to_chksum(chksum_t *ct, const void* buf, int cnt)
 548{
 549        /* We need to handle the two checksums at once, because at the
 550         * beginning of the header, we don't know yet which one we'll
 551         * eventually need */
 552        ct->f_adler32 = lzo_adler32(ct->f_adler32, (const uint8_t*)buf, cnt);
 553        ct->f_crc32 = lzo_crc32(ct->f_crc32, (const uint8_t*)buf, cnt);
 554}
 555
 556static uint32_t chksum_getresult(chksum_t *ct, const header_t *h)
 557{
 558        return (h->flags & F_H_CRC32) ? ct->f_crc32 : ct->f_adler32;
 559}
 560
 561/**********************************************************************/
 562static uint32_t read32(void)
 563{
 564        uint32_t v;
 565        xread(0, &v, 4);
 566        return ntohl(v);
 567}
 568
 569static void write32(uint32_t v)
 570{
 571        v = htonl(v);
 572        xwrite(1, &v, 4);
 573}
 574
 575static void f_write(const void* buf, int cnt)
 576{
 577        xwrite(1, buf, cnt);
 578        add_bytes_to_chksum(&G.chksum_out, buf, cnt);
 579}
 580
 581static void f_read(void* buf, int cnt)
 582{
 583        xread(0, buf, cnt);
 584        add_bytes_to_chksum(&G.chksum_in, buf, cnt);
 585}
 586
 587static int f_read8(void)
 588{
 589        uint8_t v;
 590        f_read(&v, 1);
 591        return v;
 592}
 593
 594static void f_write8(uint8_t v)
 595{
 596        f_write(&v, 1);
 597}
 598
 599static unsigned f_read16(void)
 600{
 601        uint16_t v;
 602        f_read(&v, 2);
 603        return ntohs(v);
 604}
 605
 606static void f_write16(uint16_t v)
 607{
 608        v = htons(v);
 609        f_write(&v, 2);
 610}
 611
 612static uint32_t f_read32(void)
 613{
 614        uint32_t v;
 615        f_read(&v, 4);
 616        return ntohl(v);
 617}
 618
 619static void f_write32(uint32_t v)
 620{
 621        v = htonl(v);
 622        f_write(&v, 4);
 623}
 624
 625/**********************************************************************/
 626static int lzo_get_method(header_t *h)
 627{
 628        /* check method */
 629        if (h->method == M_LZO1X_1) {
 630                if (h->level == 0)
 631                        h->level = 3;
 632        } else if (h->method == M_LZO1X_1_15) {
 633                if (h->level == 0)
 634                        h->level = 1;
 635        } else if (h->method == M_LZO1X_999) {
 636                if (h->level == 0)
 637                        h->level = 9;
 638        } else
 639                return -1;              /* not a LZO method */
 640
 641        /* check compression level */
 642        if (h->level < 1 || h->level > 9)
 643                return 15;
 644
 645        return 0;
 646}
 647
 648/**********************************************************************/
 649#define LZO_BLOCK_SIZE  (256 * 1024l)
 650#define MAX_BLOCK_SIZE  (64 * 1024l * 1024l)    /* DO NOT CHANGE */
 651
 652/* LZO may expand uncompressible data by a small amount */
 653#define MAX_COMPRESSED_SIZE(x)  ((x) + (x) / 16 + 64 + 3)
 654
 655/**********************************************************************/
 656// compress a file
 657/**********************************************************************/
 658static NOINLINE int lzo_compress(const header_t *h)
 659{
 660        unsigned block_size = LZO_BLOCK_SIZE;
 661        int r = 0; /* LZO_E_OK */
 662        uint8_t *const b1 = xzalloc(block_size);
 663        uint8_t *const b2 = xzalloc(MAX_COMPRESSED_SIZE(block_size));
 664        unsigned src_len = 0, dst_len = 0;
 665        uint32_t d_adler32 = ADLER32_INIT_VALUE;
 666        uint32_t d_crc32 = CRC32_INIT_VALUE;
 667        int l;
 668        uint8_t *wrk_mem = NULL;
 669
 670        if (h->method == M_LZO1X_1)
 671                wrk_mem = xzalloc(LZO1X_1_MEM_COMPRESS);
 672        else if (h->method == M_LZO1X_1_15)
 673                wrk_mem = xzalloc(LZO1X_1_15_MEM_COMPRESS);
 674        else if (h->method == M_LZO1X_999)
 675                wrk_mem = xzalloc(LZO1X_999_MEM_COMPRESS);
 676
 677        for (;;) {
 678                /* read a block */
 679                l = full_read(0, b1, block_size);
 680                src_len = (l > 0 ? l : 0);
 681
 682                /* write uncompressed block size */
 683                write32(src_len);
 684
 685                /* exit if last block */
 686                if (src_len == 0)
 687                        break;
 688
 689                /* compute checksum of uncompressed block */
 690                if (h->flags & F_ADLER32_D)
 691                        d_adler32 = lzo_adler32(ADLER32_INIT_VALUE, b1, src_len);
 692                if (h->flags & F_CRC32_D)
 693                        d_crc32 = lzo_crc32(CRC32_INIT_VALUE, b1, src_len);
 694
 695                /* compress */
 696                if (h->method == M_LZO1X_1)
 697                        r = lzo1x_1_compress(b1, src_len, b2, &dst_len, wrk_mem);
 698                else if (h->method == M_LZO1X_1_15)
 699                        r = lzo1x_1_15_compress(b1, src_len, b2, &dst_len, wrk_mem);
 700#if ENABLE_LZOP_COMPR_HIGH
 701                else if (h->method == M_LZO1X_999)
 702                        r = lzo1x_999_compress_level(b1, src_len, b2, &dst_len,
 703                                                wrk_mem, h->level);
 704#endif
 705                else
 706                        bb_error_msg_and_die("internal error");
 707
 708                if (r != 0) /* not LZO_E_OK */
 709                        bb_error_msg_and_die("internal error - compression failed");
 710
 711                /* write compressed block size */
 712                if (dst_len < src_len) {
 713                        /* optimize */
 714                        if (h->method == M_LZO1X_999) {
 715                                unsigned new_len = src_len;
 716                                r = lzo1x_optimize(b2, dst_len, b1, &new_len, NULL);
 717                                if (r != 0 /*LZO_E_OK*/ || new_len != src_len)
 718                                        bb_error_msg_and_die("internal error - optimization failed");
 719                        }
 720                        write32(dst_len);
 721                } else {
 722                        /* data actually expanded => store data uncompressed */
 723                        write32(src_len);
 724                }
 725
 726                /* write checksum of uncompressed block */
 727                if (h->flags & F_ADLER32_D)
 728                        write32(d_adler32);
 729                if (h->flags & F_CRC32_D)
 730                        write32(d_crc32);
 731
 732                if (dst_len < src_len) {
 733                        /* write checksum of compressed block */
 734                        if (h->flags & F_ADLER32_C)
 735                                write32(lzo_adler32(ADLER32_INIT_VALUE, b2, dst_len));
 736                        if (h->flags & F_CRC32_C)
 737                                write32(lzo_crc32(CRC32_INIT_VALUE, b2, dst_len));
 738                        /* write compressed block data */
 739                        xwrite(1, b2, dst_len);
 740                } else {
 741                        /* write uncompressed block data */
 742                        xwrite(1, b1, src_len);
 743                }
 744        }
 745
 746        free(wrk_mem);
 747        free(b1);
 748        free(b2);
 749        return 1;
 750}
 751
 752static FAST_FUNC void lzo_check(
 753                uint32_t init,
 754                uint8_t* buf, unsigned len,
 755                uint32_t FAST_FUNC (*fn)(uint32_t, const uint8_t*, unsigned),
 756                uint32_t ref)
 757{
 758        /* This function, by having the same order of parameters
 759         * as fn, and by being marked FAST_FUNC (same as fn),
 760         * saves a dozen bytes of code.
 761         */
 762        uint32_t c = fn(init, buf, len);
 763        if (c != ref)
 764                bb_error_msg_and_die("checksum error");
 765}
 766
 767/**********************************************************************/
 768// decompress a file
 769/**********************************************************************/
 770static NOINLINE int lzo_decompress(const header_t *h)
 771{
 772        unsigned block_size = LZO_BLOCK_SIZE;
 773        int r;
 774        uint32_t src_len, dst_len;
 775        uint32_t c_adler32 = ADLER32_INIT_VALUE;
 776        uint32_t d_adler32 = ADLER32_INIT_VALUE;
 777        uint32_t c_crc32 = CRC32_INIT_VALUE, d_crc32 = CRC32_INIT_VALUE;
 778        uint8_t *b1;
 779        uint32_t mcs_block_size = MAX_COMPRESSED_SIZE(block_size);
 780        uint8_t *b2 = NULL;
 781
 782        for (;;) {
 783                uint8_t *dst;
 784
 785                /* read uncompressed block size */
 786                dst_len = read32();
 787
 788                /* exit if last block */
 789                if (dst_len == 0)
 790                        break;
 791
 792                /* error if split file */
 793                if (dst_len == 0xffffffffL)
 794                        /* should not happen - not yet implemented */
 795                        bb_error_msg_and_die("this file is a split lzop file");
 796
 797                if (dst_len > MAX_BLOCK_SIZE)
 798                        bb_error_msg_and_die("corrupted data");
 799
 800                /* read compressed block size */
 801                src_len = read32();
 802                if (src_len <= 0 || src_len > dst_len)
 803                        bb_error_msg_and_die("corrupted data");
 804
 805                if (dst_len > block_size) {
 806                        if (b2) {
 807                                free(b2);
 808                                b2 = NULL;
 809                        }
 810                        block_size = dst_len;
 811                        mcs_block_size = MAX_COMPRESSED_SIZE(block_size);
 812                }
 813
 814                /* read checksum of uncompressed block */
 815                if (h->flags & F_ADLER32_D)
 816                        d_adler32 = read32();
 817                if (h->flags & F_CRC32_D)
 818                        d_crc32 = read32();
 819
 820                /* read checksum of compressed block */
 821                if (src_len < dst_len) {
 822                        if (h->flags & F_ADLER32_C)
 823                                c_adler32 = read32();
 824                        if (h->flags & F_CRC32_C)
 825                                c_crc32 = read32();
 826                }
 827
 828                if (b2 == NULL)
 829                        b2 = xzalloc(mcs_block_size);
 830                /* read the block into the end of our buffer */
 831                b1 = b2 + mcs_block_size - src_len;
 832                xread(0, b1, src_len);
 833
 834                if (src_len < dst_len) {
 835                        unsigned d = dst_len;
 836
 837                        if (!(option_mask32 & OPT_F)) {
 838                                /* verify checksum of compressed block */
 839                                if (h->flags & F_ADLER32_C)
 840                                        lzo_check(ADLER32_INIT_VALUE,
 841                                                        b1, src_len,
 842                                                        lzo_adler32, c_adler32);
 843                                if (h->flags & F_CRC32_C)
 844                                        lzo_check(CRC32_INIT_VALUE,
 845                                                        b1, src_len,
 846                                                        lzo_crc32, c_crc32);
 847                        }
 848
 849                        /* decompress */
 850//                      if (option_mask32 & OPT_F)
 851//                              r = lzo1x_decompress(b1, src_len, b2, &d, NULL);
 852//                      else
 853                                r = lzo1x_decompress_safe(b1, src_len, b2, &d, NULL);
 854
 855                        if (r != 0 /*LZO_E_OK*/ || dst_len != d) {
 856                                bb_error_msg_and_die("corrupted data");
 857                        }
 858                        dst = b2;
 859                } else {
 860                        /* "stored" block => no decompression */
 861                        dst = b1;
 862                }
 863
 864                if (!(option_mask32 & OPT_F)) {
 865                        /* verify checksum of uncompressed block */
 866                        if (h->flags & F_ADLER32_D)
 867                                lzo_check(ADLER32_INIT_VALUE,
 868                                        dst, dst_len,
 869                                        lzo_adler32, d_adler32);
 870                        if (h->flags & F_CRC32_D)
 871                                lzo_check(CRC32_INIT_VALUE,
 872                                        dst, dst_len,
 873                                        lzo_crc32, d_crc32);
 874                }
 875
 876                /* write uncompressed block data */
 877                xwrite(1, dst, dst_len);
 878        }
 879
 880        free(b2);
 881        return 1;
 882}
 883
 884/**********************************************************************/
 885// lzop file signature (shamelessly borrowed from PNG)
 886/**********************************************************************/
 887/*
 888 * The first nine bytes of a lzop file always contain the following values:
 889 *
 890 *                                 0   1   2   3   4   5   6   7   8
 891 *                               --- --- --- --- --- --- --- --- ---
 892 * (hex)                          89  4c  5a  4f  00  0d  0a  1a  0a
 893 * (decimal)                     137  76  90  79   0  13  10  26  10
 894 * (C notation - ASCII)         \211   L   Z   O  \0  \r  \n \032 \n
 895 */
 896
 897/* (vda) comparison with lzop v1.02rc1 ("lzop -1 <FILE" cmd):
 898 * Only slight differences in header:
 899 * -00000000  89 4c 5a 4f 00 0d 0a 1a 0a 10 20 20 20 09 40 02
 900 * +00000000  89 4c 5a 4f 00 0d 0a 1a 0a 10 10 20 30 09 40 02
 901 *                                       ^^^^^ ^^^^^
 902 *                                     version lib_version
 903 * -00000010  01 03 00 00 0d 00 00 81 a4 49 f7 a6 3f 00 00 00
 904 * +00000010  01 03 00 00 01 00 00 00 00 00 00 00 00 00 00 00
 905 *               ^^^^^^^^^^^ ^^^^^^^^^^^ ^^^^^^^^^^^
 906 *               flags       mode        mtime
 907 * -00000020  00 00 2d 67 04 17 00 04 00 00 00 03 ed ec 9d 6d
 908 * +00000020  00 00 10 5f 00 c1 00 04 00 00 00 03 ed ec 9d 6d
 909 *                  ^^^^^^^^^^^
 910 *                  chksum_out
 911 * The rest is identical.
 912*/
 913static const unsigned char lzop_magic[9] ALIGN1 = {
 914        0x89, 0x4c, 0x5a, 0x4f, 0x00, 0x0d, 0x0a, 0x1a, 0x0a
 915};
 916
 917/* This coding is derived from Alexander Lehmann's pngcheck code. */
 918static void check_magic(void)
 919{
 920        unsigned char magic[sizeof(lzop_magic)];
 921        xread(0, magic, sizeof(magic));
 922        if (memcmp(magic, lzop_magic, sizeof(lzop_magic)) != 0)
 923                bb_error_msg_and_die("bad magic number");
 924}
 925
 926/**********************************************************************/
 927// lzop file header
 928/**********************************************************************/
 929static void write_header(const header_t *h)
 930{
 931        int l;
 932
 933        xwrite(1, lzop_magic, sizeof(lzop_magic));
 934
 935        init_chksum(&G.chksum_out);
 936
 937        f_write16(h->version);
 938        f_write16(h->lib_version);
 939        f_write16(h->version_needed_to_extract);
 940        f_write8(h->method);
 941        f_write8(h->level);
 942        f_write32(h->flags);
 943        f_write32(h->mode);
 944        f_write32(h->mtime);
 945        f_write32(h->gmtdiff);
 946
 947        l = (int) strlen(h->name);
 948        f_write8(l);
 949        if (l)
 950                f_write(h->name, l);
 951
 952        f_write32(chksum_getresult(&G.chksum_out, h));
 953}
 954
 955static int read_header(header_t *h)
 956{
 957        int r;
 958        int l;
 959        uint32_t checksum;
 960
 961        memset(h, 0, sizeof(*h));
 962        h->version_needed_to_extract = 0x0900;  /* first lzop version */
 963        h->level = 0;
 964
 965        init_chksum(&G.chksum_in);
 966
 967        h->version = f_read16();
 968        if (h->version < 0x0900)
 969                return 3;
 970        h->lib_version = f_read16();
 971        if (h->version >= 0x0940) {
 972                h->version_needed_to_extract = f_read16();
 973                if (h->version_needed_to_extract > LZOP_VERSION)
 974                        return 16;
 975                if (h->version_needed_to_extract < 0x0900)
 976                        return 3;
 977        }
 978        h->method = f_read8();
 979        if (h->version >= 0x0940)
 980                h->level = f_read8();
 981        h->flags = f_read32();
 982        if (h->flags & F_H_FILTER)
 983                return 16; /* filter not supported */
 984        h->mode = f_read32();
 985        h->mtime = f_read32();
 986        if (h->version >= 0x0940)
 987                h->gmtdiff = f_read32();
 988
 989        l = f_read8();
 990        if (l > 0)
 991                f_read(h->name, l);
 992        h->name[l] = 0;
 993
 994        checksum = chksum_getresult(&G.chksum_in, h);
 995        h->header_checksum = f_read32();
 996        if (h->header_checksum != checksum)
 997                return 2;
 998
 999        if (h->method <= 0)
1000                return 14;
1001        r = lzo_get_method(h);
1002        if (r != 0)
1003                return r;
1004
1005        /* check reserved flags */
1006        if (h->flags & F_RESERVED)
1007                return -13;
1008
1009        /* skip extra field [not used yet] */
1010        if (h->flags & F_H_EXTRA_FIELD) {
1011                uint32_t k;
1012
1013                /* note: the checksum also covers the length */
1014                init_chksum(&G.chksum_in);
1015                h->extra_field_len = f_read32();
1016                for (k = 0; k < h->extra_field_len; k++)
1017                        f_read8();
1018                checksum = chksum_getresult(&G.chksum_in, h);
1019                h->extra_field_checksum = f_read32();
1020                if (h->extra_field_checksum != checksum)
1021                        return 3;
1022        }
1023
1024        return 0;
1025}
1026
1027static void p_header(header_t *h)
1028{
1029        int r;
1030
1031        r = read_header(h);
1032        if (r == 0)
1033                return;
1034        bb_error_msg_and_die("header_error %d", r);
1035}
1036
1037/**********************************************************************/
1038// compress
1039/**********************************************************************/
1040static void lzo_set_method(header_t *h)
1041{
1042        int level = 1;
1043
1044        if (option_mask32 & OPT_1) {
1045                h->method = M_LZO1X_1_15;
1046        } else if (option_mask32 & OPT_789) {
1047#if ENABLE_LZOP_COMPR_HIGH
1048                h->method = M_LZO1X_999;
1049                if (option_mask32 & OPT_7)
1050                        level = 7;
1051                else if (option_mask32 & OPT_8)
1052                        level = 8;
1053                else
1054                        level = 9;
1055#else
1056                bb_error_msg_and_die("high compression not compiled in");
1057#endif
1058        } else { /* levels 2..6 or none (defaults to level 3) */
1059                h->method = M_LZO1X_1;
1060                level = 5; /* levels 2-6 are actually the same */
1061        }
1062
1063        h->level = level;
1064}
1065
1066static int do_lzo_compress(void)
1067{
1068        header_t header;
1069
1070#define h (&header)
1071        memset(h, 0, sizeof(*h));
1072
1073        lzo_set_method(h);
1074
1075        h->version = (LZOP_VERSION & 0xffff);
1076        h->version_needed_to_extract = 0x0940;
1077        h->lib_version = lzo_version() & 0xffff;
1078
1079        h->flags = (F_OS & F_OS_MASK) | (F_CS & F_CS_MASK);
1080
1081        if (!(option_mask32 & OPT_F) || h->method == M_LZO1X_999) {
1082                h->flags |= F_ADLER32_D;
1083                if (option_mask32 & OPT_C)
1084                        h->flags |= F_ADLER32_C;
1085        }
1086        write_header(h);
1087        return lzo_compress(h);
1088#undef h
1089}
1090
1091/**********************************************************************/
1092// decompress
1093/**********************************************************************/
1094static int do_lzo_decompress(void)
1095{
1096        header_t header;
1097
1098        check_magic();
1099        p_header(&header);
1100        return lzo_decompress(&header);
1101}
1102
1103static char* FAST_FUNC make_new_name_lzop(char *filename, const char *expected_ext UNUSED_PARAM)
1104{
1105        if (option_mask32 & OPT_DECOMPRESS) {
1106                char *extension = strrchr(filename, '.');
1107                if (!extension || strcmp(extension + 1, "lzo") != 0)
1108                        return xasprintf("%s.out", filename);
1109                *extension = '\0';
1110                return filename;
1111        }
1112        return xasprintf("%s.lzo", filename);
1113}
1114
1115static IF_DESKTOP(long long) int FAST_FUNC pack_lzop(transformer_state_t *xstate UNUSED_PARAM)
1116{
1117        if (option_mask32 & OPT_DECOMPRESS)
1118                return do_lzo_decompress();
1119        return do_lzo_compress();
1120}
1121
1122int lzop_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
1123int lzop_main(int argc UNUSED_PARAM, char **argv)
1124{
1125        getopt32(argv, OPTION_STRING);
1126        argv += optind;
1127        /* lzopcat? */
1128        if (ENABLE_LZOPCAT && applet_name[4] == 'c')
1129                option_mask32 |= (OPT_STDOUT | OPT_DECOMPRESS);
1130        /* unlzop? */
1131        if (ENABLE_UNLZOP && applet_name[4] == 'o')
1132                option_mask32 |= OPT_DECOMPRESS;
1133
1134        global_crc32_table = crc32_filltable(NULL, 0);
1135        return bbunpack(argv, pack_lzop, make_new_name_lzop, /*unused:*/ NULL);
1136}
1137