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