lzop: new applet. Busyboxed by Alain Knaff. +7700 bytes.
authorDenis Vlasenko <vda.linux@googlemail.com>
Wed, 29 Apr 2009 12:01:51 +0000 (12:01 -0000)
committerDenis Vlasenko <vda.linux@googlemail.com>
Wed, 29 Apr 2009 12:01:51 +0000 (12:01 -0000)
12 files changed:
archival/Config.in
archival/Kbuild
archival/liblzo.h [new file with mode: 0644]
archival/liblzo_interface.h [new file with mode: 0644]
archival/lzo1x_1.c [new file with mode: 0644]
archival/lzo1x_1o.c [new file with mode: 0644]
archival/lzo1x_9x.c [new file with mode: 0644]
archival/lzo1x_c.c [new file with mode: 0644]
archival/lzo1x_d.c [new file with mode: 0644]
archival/lzop.c [new file with mode: 0644]
include/applets.h
include/usage.h

index e0d43c0ee5eda4925a3a3bb90429ba45169d1d1c..a983e44336e8ce83afe4d66e2463d7befa9cdd0d 100644 (file)
@@ -165,6 +165,21 @@ config GZIP
          gzip is used to compress files.
          It's probably the most widely used UNIX compression program.
 
+config LZOP
+       bool "lzop"
+       default n
+       help
+         Lzop compression/decompresion.
+
+config LZOP_COMPR_HIGH
+       bool "lzop complession levels 7,8,9 (not very useful)"
+       default n
+       depends on LZOP
+       help
+         High levels (7,8,9) of lzop compression. These levels
+         are actually slower than gzip at equivalent compression ratios
+         and take up 3.2K of code.
+
 config RPM2CPIO
        bool "rpm2cpio"
        default n
index 72dbdda0e76d5397571a4ea0d4e6e9a8f6defb3e..de0ca43151dac5f05fa4f3cfdfaef6b9a6572d1a 100644 (file)
@@ -16,6 +16,8 @@ lib-$(CONFIG_DPKG)            += dpkg.o
 lib-$(CONFIG_DPKG_DEB)         += dpkg_deb.o
 lib-$(CONFIG_GUNZIP)           += bbunzip.o
 lib-$(CONFIG_GZIP)             += gzip.o bbunzip.o
+lib-$(CONFIG_LZOP)             += lzop.o lzo1x_1.o lzo1x_1o.o lzo1x_d.o
+lib-$(CONFIG_LZOP_COMPR_HIGH)  += lzo1x_9x.o
 lib-$(CONFIG_RPM2CPIO)         += rpm2cpio.o
 lib-$(CONFIG_RPM)              += rpm.o
 lib-$(CONFIG_TAR)              += tar.o
diff --git a/archival/liblzo.h b/archival/liblzo.h
new file mode 100644 (file)
index 0000000..843997c
--- /dev/null
@@ -0,0 +1,93 @@
+/*
+   This file is part of the LZO real-time data compression library.
+
+   Copyright (C) 1996..2008 Markus Franz Xaver Johannes Oberhumer
+   All Rights Reserved.
+
+   Markus F.X.J. Oberhumer <markus@oberhumer.com>
+   http://www.oberhumer.com/opensource/lzo/
+
+   The LZO library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU General Public License as
+   published by the Free Software Foundation; either version 2 of
+   the License, or (at your option) any later version.
+
+   The LZO library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with the LZO library; see the file COPYING.
+   If not, write to the Free Software Foundation, Inc.,
+   51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "liblzo_interface.h"
+
+/* lzo-2.03/src/config1x.h */
+#define M2_MIN_LEN      3
+#define M2_MAX_LEN      8
+#define M3_MAX_LEN      33
+#define M4_MAX_LEN      9
+#define M1_MAX_OFFSET   0x0400
+#define M2_MAX_OFFSET   0x0800
+#define M3_MAX_OFFSET   0x4000
+#define M4_MAX_OFFSET   0xbfff
+#define M1_MARKER       0
+#define M3_MARKER       32
+#define M4_MARKER       16
+
+#define MX_MAX_OFFSET   (M1_MAX_OFFSET + M2_MAX_OFFSET)
+#define MIN_LOOKAHEAD   (M2_MAX_LEN + 1)
+
+#define LZO_EOF_CODE
+
+/* lzo-2.03/src/lzo_dict.h */
+#define GINDEX(m_pos,m_off,dict,dindex,in)    m_pos = dict[dindex]
+#define DX2(p,s1,s2) \
+        (((((unsigned)((p)[2]) << (s2)) ^ (p)[1]) << (s1)) ^ (p)[0])
+//#define DA3(p,s1,s2,s3) ((DA2((p)+1,s2,s3) << (s1)) + (p)[0])
+//#define DS3(p,s1,s2,s3) ((DS2((p)+1,s2,s3) << (s1)) - (p)[0])
+#define DX3(p,s1,s2,s3) ((DX2((p)+1,s2,s3) << (s1)) ^ (p)[0])
+
+#define D_SIZE        (1U << D_BITS)
+#define D_MASK        ((1U << D_BITS) - 1)
+#define D_HIGH        ((D_MASK >> 1) + 1)
+
+#define LZO_CHECK_MPOS_NON_DET(m_pos,m_off,in,ip,max_offset) \
+    ( \
+        m_pos = ip - (unsigned)(ip - m_pos), \
+        ((uintptr_t)m_pos < (uintptr_t)in \
+       || (m_off = (unsigned)(ip - m_pos)) <= 0 \
+       || m_off > max_offset) \
+    )
+
+#define DENTRY(p,in)                      (p)
+#define UPDATE_I(dict,drun,index,p,in)    dict[index] = DENTRY(p,in)
+
+#define DMS(v,s)  ((unsigned) (((v) & (D_MASK >> (s))) << (s)))
+#define DM(v)     ((unsigned) ((v) & D_MASK))
+#define DMUL(a,b) ((unsigned) ((a) * (b)))
+
+/* lzo-2.03/src/lzo_ptr.h */
+#define pd(a,b)  ((unsigned)((a)-(b)))
+
+#    define TEST_IP             (ip < ip_end)
+#    define NEED_IP(x) \
+            if ((unsigned)(ip_end - ip) < (unsigned)(x))  goto input_overrun
+
+#    undef TEST_OP              /* don't need both of the tests here */
+#    define TEST_OP             1
+#    define NEED_OP(x) \
+            if ((unsigned)(op_end - op) < (unsigned)(x))  goto output_overrun
+
+#define HAVE_ANY_OP 1
+
+//#if defined(LZO_TEST_OVERRUN_LOOKBEHIND)
+#  define TEST_LB(m_pos)        if (m_pos < out || m_pos >= op) goto lookbehind_overrun
+//#  define TEST_LBO(m_pos,o)     if (m_pos < out || m_pos >= op - (o)) goto lookbehind_overrun
+//#else
+//#  define TEST_LB(m_pos)        ((void) 0)
+//#  define TEST_LBO(m_pos,o)     ((void) 0)
+//#endif
diff --git a/archival/liblzo_interface.h b/archival/liblzo_interface.h
new file mode 100644 (file)
index 0000000..9a84c0b
--- /dev/null
@@ -0,0 +1,71 @@
+/*
+   This file is part of the LZO real-time data compression library.
+
+   Copyright (C) 1996..2008 Markus Franz Xaver Johannes Oberhumer
+   All Rights Reserved.
+
+   Markus F.X.J. Oberhumer <markus@oberhumer.com>
+   http://www.oberhumer.com/opensource/lzo/
+
+   The LZO library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU General Public License as
+   published by the Free Software Foundation; either version 2 of
+   the License, or (at your option) any later version.
+
+   The LZO library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with the LZO library; see the file COPYING.
+   If not, write to the Free Software Foundation, Inc.,
+   51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#define LZO1X
+#undef LZO1Y
+
+#undef assert
+/*
+static void die_at(int line)
+{
+        bb_error_msg_and_die("internal error at %d", line);
+}
+#define assert(v) if (!(v)) die_at(__LINE__)
+*/
+#define assert(v) ((void)0)
+
+int lzo1x_1_compress(const uint8_t* src, unsigned src_len,
+               uint8_t* dst, unsigned* dst_len,
+               void* wrkmem);
+int lzo1x_1_15_compress(const uint8_t* src, unsigned src_len,
+               uint8_t* dst, unsigned* dst_len,
+               void* wrkmem);
+int lzo1x_999_compress_level(const uint8_t* in, unsigned in_len,
+               uint8_t* out, unsigned* out_len,
+               void* wrkmem,
+               int compression_level);
+
+/* decompression */
+//int lzo1x_decompress(const uint8_t* src, unsigned src_len,
+//             uint8_t* dst, unsigned* dst_len,
+//             void* wrkmem /* NOT USED */);
+/* safe decompression with overrun testing */
+int lzo1x_decompress_safe(const uint8_t* src, unsigned src_len,
+               uint8_t* dst, unsigned* dst_len,
+               void* wrkmem /* NOT USED */);
+
+#define LZO_E_OK                    0
+#define LZO_E_ERROR                 (-1)
+#define LZO_E_OUT_OF_MEMORY         (-2)    /* [not used right now] */
+#define LZO_E_NOT_COMPRESSIBLE      (-3)    /* [not used right now] */
+#define LZO_E_INPUT_OVERRUN         (-4)
+#define LZO_E_OUTPUT_OVERRUN        (-5)
+#define LZO_E_LOOKBEHIND_OVERRUN    (-6)
+#define LZO_E_EOF_NOT_FOUND         (-7)
+#define LZO_E_INPUT_NOT_CONSUMED    (-8)
+#define LZO_E_NOT_YET_IMPLEMENTED   (-9)    /* [not used right now] */
+
+/* lzo-2.03/include/lzo/lzoconf.h */
+#define LZO_VERSION   0x2030
diff --git a/archival/lzo1x_1.c b/archival/lzo1x_1.c
new file mode 100644 (file)
index 0000000..a888398
--- /dev/null
@@ -0,0 +1,35 @@
+/* LZO1X-1 compression
+
+   This file is part of the LZO real-time data compression library.
+
+   Copyright (C) 1996..2008 Markus Franz Xaver Johannes Oberhumer
+   All Rights Reserved.
+
+   Markus F.X.J. Oberhumer <markus@oberhumer.com>
+   http://www.oberhumer.com/opensource/lzo/
+
+   The LZO library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU General Public License as
+   published by the Free Software Foundation; either version 2 of
+   the License, or (at your option) any later version.
+
+   The LZO library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with the LZO library; see the file COPYING.
+   If not, write to the Free Software Foundation, Inc.,
+   51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+#include "libbb.h"
+#include "liblzo.h"
+
+#define D_BITS          14
+#define D_INDEX1(d,p)   d = DM(DMUL(0x21,DX3(p,5,5,6)) >> 5)
+#define D_INDEX2(d,p)   d = (d & (D_MASK & 0x7ff)) ^ (D_HIGH | 0x1f)
+
+#define DO_COMPRESS     lzo1x_1_compress
+
+#include "lzo1x_c.c"
diff --git a/archival/lzo1x_1o.c b/archival/lzo1x_1o.c
new file mode 100644 (file)
index 0000000..3c61253
--- /dev/null
@@ -0,0 +1,35 @@
+/* LZO1X-1(15) compression
+
+   This file is part of the LZO real-time data compression library.
+
+   Copyright (C) 1996..2008 Markus Franz Xaver Johannes Oberhumer
+   All Rights Reserved.
+
+   Markus F.X.J. Oberhumer <markus@oberhumer.com>
+   http://www.oberhumer.com/opensource/lzo/
+
+   The LZO library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU General Public License as
+   published by the Free Software Foundation; either version 2 of
+   the License, or (at your option) any later version.
+
+   The LZO library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with the LZO library; see the file COPYING.
+   If not, write to the Free Software Foundation, Inc.,
+   51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+#include "libbb.h"
+#include "liblzo.h"
+
+#define D_BITS          15
+#define D_INDEX1(d,p)   d = DM(DMUL(0x21,DX3(p,5,5,6)) >> 5)
+#define D_INDEX2(d,p)   d = (d & (D_MASK & 0x7ff)) ^ (D_HIGH | 0x1f)
+
+#define DO_COMPRESS     lzo1x_1_15_compress
+
+#include "lzo1x_c.c"
diff --git a/archival/lzo1x_9x.c b/archival/lzo1x_9x.c
new file mode 100644 (file)
index 0000000..d30e2e7
--- /dev/null
@@ -0,0 +1,920 @@
+/* lzo1x_9x.c -- implementation of the LZO1X-999 compression algorithm
+
+   This file is part of the LZO real-time data compression library.
+
+   Copyright (C) 2008 Markus Franz Xaver Johannes Oberhumer
+   Copyright (C) 2007 Markus Franz Xaver Johannes Oberhumer
+   Copyright (C) 2006 Markus Franz Xaver Johannes Oberhumer
+   Copyright (C) 2005 Markus Franz Xaver Johannes Oberhumer
+   Copyright (C) 2004 Markus Franz Xaver Johannes Oberhumer
+   Copyright (C) 2003 Markus Franz Xaver Johannes Oberhumer
+   Copyright (C) 2002 Markus Franz Xaver Johannes Oberhumer
+   Copyright (C) 2001 Markus Franz Xaver Johannes Oberhumer
+   Copyright (C) 2000 Markus Franz Xaver Johannes Oberhumer
+   Copyright (C) 1999 Markus Franz Xaver Johannes Oberhumer
+   Copyright (C) 1998 Markus Franz Xaver Johannes Oberhumer
+   Copyright (C) 1997 Markus Franz Xaver Johannes Oberhumer
+   Copyright (C) 1996 Markus Franz Xaver Johannes Oberhumer
+   All Rights Reserved.
+
+   The LZO library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU General Public License as
+   published by the Free Software Foundation; either version 2 of
+   the License, or (at your option) any later version.
+
+   The LZO library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with the LZO library; see the file COPYING.
+   If not, write to the Free Software Foundation, Inc.,
+   51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+   Markus F.X.J. Oberhumer
+   <markus@oberhumer.com>
+   http://www.oberhumer.com/opensource/lzo/
+*/
+#include "libbb.h"
+
+/* The following is probably only safe on Intel-compatible processors ... */
+#define LZO_UNALIGNED_OK_2
+#define LZO_UNALIGNED_OK_4
+
+#include "liblzo.h"
+
+#define LZO_MAX(a,b)        ((a) >= (b) ? (a) : (b))
+#define LZO_MIN(a,b)        ((a) <= (b) ? (a) : (b))
+#define LZO_MAX3(a,b,c)     ((a) >= (b) ? LZO_MAX(a,c) : LZO_MAX(b,c))
+
+/***********************************************************************
+//
+************************************************************************/
+#define SWD_N           M4_MAX_OFFSET   /* size of ring buffer */
+#define SWD_F           2048           /* upper limit for match length */
+
+#define SWD_BEST_OFF    (LZO_MAX3(M2_MAX_LEN, M3_MAX_LEN, M4_MAX_LEN) + 1)
+
+typedef struct {
+       int init;
+
+       unsigned look;          /* bytes in lookahead buffer */
+
+       unsigned m_len;
+       unsigned m_off;
+
+       const uint8_t *bp;
+       const uint8_t *ip;
+       const uint8_t *in;
+       const uint8_t *in_end;
+       uint8_t *out;
+
+       unsigned r1_lit;
+
+} lzo1x_999_t;
+
+#define getbyte(c)  ((c).ip < (c).in_end ? *((c).ip)++ : (-1))
+
+/* lzo_swd.c -- sliding window dictionary */
+
+/***********************************************************************
+//
+************************************************************************/
+#define SWD_UINT_MAX      USHRT_MAX
+
+#ifndef SWD_HSIZE
+#  define SWD_HSIZE         16384
+#endif
+#ifndef SWD_MAX_CHAIN
+#  define SWD_MAX_CHAIN     2048
+#endif
+
+#define HEAD3(b, p) \
+       ( ((0x9f5f * ((((b[p]<<5)^b[p+1])<<5) ^ b[p+2])) >> 5) & (SWD_HSIZE-1) )
+
+#if defined(LZO_UNALIGNED_OK_2)
+#  define HEAD2(b,p)      (* (uint16_t *) &(b[p]))
+#else
+#  define HEAD2(b,p)      (b[p] ^ ((unsigned)b[p+1]<<8))
+#endif
+#define NIL2              SWD_UINT_MAX
+
+typedef struct lzo_swd {
+       /* public - "built-in" */
+
+       /* public - configuration */
+       unsigned max_chain;
+       int use_best_off;
+
+       /* public - output */
+       unsigned m_len;
+       unsigned m_off;
+       unsigned look;
+       int b_char;
+#if defined(SWD_BEST_OFF)
+       unsigned best_off[SWD_BEST_OFF];
+#endif
+
+       /* semi public */
+       lzo1x_999_t *c;
+       unsigned m_pos;
+#if defined(SWD_BEST_OFF)
+       unsigned best_pos[SWD_BEST_OFF];
+#endif
+
+       /* private */
+       unsigned ip;                /* input pointer (lookahead) */
+       unsigned bp;                /* buffer pointer */
+       unsigned rp;                /* remove pointer */
+
+       unsigned node_count;
+       unsigned first_rp;
+
+       uint8_t b[SWD_N + SWD_F];
+       uint8_t b_wrap[SWD_F]; /* must follow b */
+       uint16_t head3[SWD_HSIZE];
+       uint16_t succ3[SWD_N + SWD_F];
+       uint16_t best3[SWD_N + SWD_F];
+       uint16_t llen3[SWD_HSIZE];
+#ifdef HEAD2
+       uint16_t head2[65536L];
+#endif
+} lzo_swd_t, *lzo_swd_p;
+
+#define SIZEOF_LZO_SWD_T    (sizeof(lzo_swd_t))
+
+
+/* Access macro for head3.
+ * head3[key] may be uninitialized, but then its value will never be used.
+ */
+#define s_get_head3(s,key)    s->head3[key]
+
+
+/***********************************************************************
+//
+************************************************************************/
+#define B_SIZE (SWD_N + SWD_F)
+
+static int swd_init(lzo_swd_p s)
+{
+       /* defaults */
+       s->node_count = SWD_N;
+
+       memset(s->llen3, 0, sizeof(s->llen3[0]) * (unsigned)SWD_HSIZE);
+#ifdef HEAD2
+       memset(s->head2, 0xff, sizeof(s->head2[0]) * 65536L);
+       assert(s->head2[0] == NIL2);
+#endif
+
+       s->ip = 0;
+       s->bp = s->ip;
+       s->first_rp = s->ip;
+
+       assert(s->ip + SWD_F <= B_SIZE);
+       s->look = (unsigned) (s->c->in_end - s->c->ip);
+       if (s->look > 0) {
+               if (s->look > SWD_F)
+                       s->look = SWD_F;
+               memcpy(&s->b[s->ip],s->c->ip,s->look);
+               s->c->ip += s->look;
+               s->ip += s->look;
+       }
+       if (s->ip == B_SIZE)
+               s->ip = 0;
+
+       s->rp = s->first_rp;
+       if (s->rp >= s->node_count)
+               s->rp -= s->node_count;
+       else
+               s->rp += B_SIZE - s->node_count;
+
+       return LZO_E_OK;
+}
+
+#define swd_pos2off(s,pos) \
+       (s->bp > (pos) ? s->bp - (pos) : B_SIZE - ((pos) - s->bp))
+
+
+/***********************************************************************
+//
+************************************************************************/
+static void swd_getbyte(lzo_swd_p s)
+{
+       int c;
+
+       if ((c = getbyte(*(s->c))) < 0) {
+               if (s->look > 0)
+                       --s->look;
+       } else {
+               s->b[s->ip] = c;
+               if (s->ip < SWD_F)
+                       s->b_wrap[s->ip] = c;
+       }
+       if (++s->ip == B_SIZE)
+               s->ip = 0;
+       if (++s->bp == B_SIZE)
+               s->bp = 0;
+       if (++s->rp == B_SIZE)
+               s->rp = 0;
+}
+
+
+/***********************************************************************
+// remove node from lists
+************************************************************************/
+static void swd_remove_node(lzo_swd_p s, unsigned node)
+{
+       if (s->node_count == 0) {
+               unsigned key;
+
+               key = HEAD3(s->b,node);
+               assert(s->llen3[key] > 0);
+               --s->llen3[key];
+
+#ifdef HEAD2
+               key = HEAD2(s->b,node);
+               assert(s->head2[key] != NIL2);
+               if ((unsigned) s->head2[key] == node)
+                       s->head2[key] = NIL2;
+#endif
+       } else
+               --s->node_count;
+}
+
+
+/***********************************************************************
+//
+************************************************************************/
+static void swd_accept(lzo_swd_p s, unsigned n)
+{
+       assert(n <= s->look);
+
+       while (n--) {
+               unsigned key;
+
+               swd_remove_node(s,s->rp);
+
+               /* add bp into HEAD3 */
+               key = HEAD3(s->b,s->bp);
+               s->succ3[s->bp] = s_get_head3(s,key);
+               s->head3[key] = s->bp;
+               s->best3[s->bp] = SWD_F + 1;
+               s->llen3[key]++;
+               assert(s->llen3[key] <= SWD_N);
+
+#ifdef HEAD2
+               /* add bp into HEAD2 */
+               key = HEAD2(s->b,s->bp);
+               s->head2[key] = s->bp;
+#endif
+
+               swd_getbyte(s);
+       }
+}
+
+
+/***********************************************************************
+//
+************************************************************************/
+static void swd_search(lzo_swd_p s, unsigned node, unsigned cnt)
+{
+       const uint8_t *p1;
+       const uint8_t *p2;
+       const uint8_t *px;
+       unsigned m_len = s->m_len;
+       const uint8_t *b  = s->b;
+       const uint8_t *bp = s->b + s->bp;
+       const uint8_t *bx = s->b + s->bp + s->look;
+       unsigned char scan_end1;
+
+       assert(s->m_len > 0);
+
+       scan_end1 = bp[m_len - 1];
+       for ( ; cnt-- > 0; node = s->succ3[node]) {
+               p1 = bp;
+               p2 = b + node;
+               px = bx;
+
+               assert(m_len < s->look);
+
+               if (p2[m_len - 1] == scan_end1 &&
+                   p2[m_len] == p1[m_len] &&
+                   p2[0] == p1[0] &&
+                   p2[1] == p1[1]) {
+                       unsigned i;
+                       assert(lzo_memcmp(bp,&b[node],3) == 0);
+                               
+                       p1 += 2; p2 += 2;
+                       do {} while (++p1 < px && *p1 == *++p2);
+                       i = p1-bp;
+
+                       assert(lzo_memcmp(bp,&b[node],i) == 0);
+
+#if defined(SWD_BEST_OFF)
+                       if (i < SWD_BEST_OFF) {
+                               if (s->best_pos[i] == 0)
+                                       s->best_pos[i] = node + 1;
+                       }
+#endif
+                       if (i > m_len) {
+                               s->m_len = m_len = i;
+                               s->m_pos = node;
+                               if (m_len == s->look)
+                                       return;
+                               if (m_len >= SWD_F)
+                                       return;
+                               if (m_len > (unsigned) s->best3[node])
+                                       return;
+                               scan_end1 = bp[m_len - 1];
+                       }
+               }
+       }
+}
+
+
+/***********************************************************************
+//
+************************************************************************/
+#ifdef HEAD2
+
+static int swd_search2(lzo_swd_p s)
+{
+       unsigned key;
+
+       assert(s->look >= 2);
+       assert(s->m_len > 0);
+
+       key = s->head2[ HEAD2(s->b,s->bp) ];
+       if (key == NIL2)
+               return 0;
+       assert(lzo_memcmp(&s->b[s->bp],&s->b[key],2) == 0);
+#if defined(SWD_BEST_OFF)
+       if (s->best_pos[2] == 0)
+               s->best_pos[2] = key + 1;
+#endif
+
+       if (s->m_len < 2) {
+               s->m_len = 2;
+               s->m_pos = key;
+       }
+       return 1;
+}
+
+#endif
+
+
+/***********************************************************************
+//
+************************************************************************/
+static void swd_findbest(lzo_swd_p s)
+{
+       unsigned key;
+       unsigned cnt, node;
+       unsigned len;
+
+       assert(s->m_len > 0);
+
+       /* get current head, add bp into HEAD3 */
+       key = HEAD3(s->b,s->bp);
+       node = s->succ3[s->bp] = s_get_head3(s,key);
+       cnt = s->llen3[key]++;
+       assert(s->llen3[key] <= SWD_N + SWD_F);
+       if (cnt > s->max_chain)
+               cnt = s->max_chain;
+       s->head3[key] = s->bp;
+
+       s->b_char = s->b[s->bp];
+       len = s->m_len;
+       if (s->m_len >= s->look) {
+               if (s->look == 0)
+                       s->b_char = -1;
+               s->m_off = 0;
+               s->best3[s->bp] = SWD_F + 1;
+       } else {
+#ifdef HEAD2
+               if (swd_search2(s))
+#endif
+                       if (s->look >= 3)
+                               swd_search(s,node,cnt);
+               if (s->m_len > len)
+                       s->m_off = swd_pos2off(s,s->m_pos);
+               s->best3[s->bp] = s->m_len;
+
+#if defined(SWD_BEST_OFF)
+               if (s->use_best_off) {
+                       int i;
+                       for (i = 2; i < SWD_BEST_OFF; i++)
+                               if (s->best_pos[i] > 0)
+                                       s->best_off[i] = swd_pos2off(s,s->best_pos[i]-1);
+                               else
+                                       s->best_off[i] = 0;
+               }
+#endif
+       }
+
+       swd_remove_node(s,s->rp);
+
+#ifdef HEAD2
+       /* add bp into HEAD2 */
+       key = HEAD2(s->b,s->bp);
+       s->head2[key] = s->bp;
+#endif
+}
+
+#undef HEAD3
+#undef HEAD2
+#undef s_get_head3
+
+
+/***********************************************************************
+//
+************************************************************************/
+static int init_match(lzo1x_999_t *c, lzo_swd_p s, uint32_t use_best_off)
+{
+       int r;
+
+       assert(!c->init);
+       c->init = 1;
+
+       s->c = c;
+
+       r = swd_init(s);
+       if (r != 0)
+               return r;
+
+       s->use_best_off = use_best_off;
+       return r;
+}
+
+
+/***********************************************************************
+//
+************************************************************************/
+static int find_match(lzo1x_999_t *c, lzo_swd_p s,
+               unsigned this_len, unsigned skip)
+{
+       assert(c->init);
+
+       if (skip > 0) {
+               assert(this_len >= skip);
+               swd_accept(s, this_len - skip);
+       } else {
+               assert(this_len <= 1);
+       }
+
+       s->m_len = 1;
+       s->m_len = 1;
+#ifdef SWD_BEST_OFF
+       if (s->use_best_off)
+               memset(s->best_pos,0,sizeof(s->best_pos));
+#endif
+       swd_findbest(s);
+       c->m_len = s->m_len;
+       c->m_off = s->m_off;
+
+       swd_getbyte(s);
+
+       if (s->b_char < 0) {
+               c->look = 0;
+               c->m_len = 0;
+       } else {
+               c->look = s->look + 1;
+       }
+       c->bp = c->ip - c->look;
+
+       return LZO_E_OK;
+}
+
+/* this is a public functions, but there is no prototype in a header file */
+static int lzo1x_999_compress_internal(const uint8_t *in , unsigned in_len,
+               uint8_t *out, unsigned *out_len,
+               void *wrkmem,
+               unsigned good_length,
+               unsigned max_lazy,
+               unsigned max_chain,
+               uint32_t use_best_off);
+
+
+/***********************************************************************
+//
+************************************************************************/
+static uint8_t *code_match(lzo1x_999_t *c,
+               uint8_t *op, unsigned m_len, unsigned m_off)
+{
+       assert(op > c->out);
+       if (m_len == 2) {
+               assert(m_off <= M1_MAX_OFFSET);
+               assert(c->r1_lit > 0); assert(c->r1_lit < 4);
+               m_off -= 1;
+               *op++ = M1_MARKER | ((m_off & 3) << 2);
+               *op++ = m_off >> 2;
+       } else if (m_len <= M2_MAX_LEN && m_off <= M2_MAX_OFFSET) {
+               assert(m_len >= 3);
+               m_off -= 1;
+               *op++ = ((m_len - 1) << 5) | ((m_off & 7) << 2);
+               *op++ = m_off >> 3;
+               assert(op[-2] >= M2_MARKER);
+       } else if (m_len == M2_MIN_LEN && m_off <= MX_MAX_OFFSET && c->r1_lit >= 4) {
+               assert(m_len == 3);
+               assert(m_off > M2_MAX_OFFSET);
+               m_off -= 1 + M2_MAX_OFFSET;
+               *op++ = M1_MARKER | ((m_off & 3) << 2);
+               *op++ = m_off >> 2;
+       } else if (m_off <= M3_MAX_OFFSET) {
+               assert(m_len >= 3);
+               m_off -= 1;
+               if (m_len <= M3_MAX_LEN)
+                       *op++ = M3_MARKER | (m_len - 2);
+               else {
+                       m_len -= M3_MAX_LEN;
+                       *op++ = M3_MARKER | 0;
+                       while (m_len > 255)
+                               {
+                                       m_len -= 255;
+                                       *op++ = 0;
+                               }
+                       assert(m_len > 0);
+                       *op++ = m_len;
+               }
+               *op++ = m_off << 2;
+               *op++ = m_off >> 6;
+       } else {
+               unsigned k;
+
+               assert(m_len >= 3);
+               assert(m_off > 0x4000); assert(m_off <= 0xbfff);
+               m_off -= 0x4000;
+               k = (m_off & 0x4000) >> 11;
+               if (m_len <= M4_MAX_LEN)
+                       *op++ = M4_MARKER | k | (m_len - 2);
+               else {
+                       m_len -= M4_MAX_LEN;
+                       *op++ = M4_MARKER | k | 0;
+                       while (m_len > 255)
+                               {
+                                       m_len -= 255;
+                                       *op++ = 0;
+                               }
+                       assert(m_len > 0);
+                       *op++ = m_len;
+               }
+               *op++ = m_off << 2;
+               *op++ = m_off >> 6;
+       }
+
+       return op;
+}
+
+
+static uint8_t *STORE_RUN(lzo1x_999_t *c, uint8_t *op,
+               const uint8_t *ii, unsigned t)
+{
+       if (op == c->out && t <= 238) {
+               *op++ = 17 + t;
+       } else if (t <= 3) {
+               op[-2] |= t;
+       } else if (t <= 18) {
+               *op++ = t - 3;
+       } else {
+               unsigned tt = t - 18;
+
+               *op++ = 0;
+               while (tt > 255) {
+                       tt -= 255;
+                       *op++ = 0;
+               }
+               assert(tt > 0);
+               *op++ = tt;
+       }
+       do *op++ = *ii++; while (--t > 0);
+
+       return op;
+}
+
+
+static uint8_t *code_run(lzo1x_999_t *c, uint8_t *op, const uint8_t *ii,
+               unsigned lit)
+{
+       if (lit > 0) {
+               assert(m_len >= 2);
+               op = STORE_RUN(c,op,ii,lit);
+       } else {
+               assert(m_len >= 3);
+       }
+       c->r1_lit = lit;
+
+       return op;
+}
+
+
+/***********************************************************************
+//
+************************************************************************/
+static int len_of_coded_match(unsigned m_len, unsigned m_off, unsigned lit)
+{
+       int n = 4;
+
+       if (m_len < 2)
+               return -1;
+       if (m_len == 2)
+               return (m_off <= M1_MAX_OFFSET && lit > 0 && lit < 4) ? 2 : -1;
+       if (m_len <= M2_MAX_LEN && m_off <= M2_MAX_OFFSET)
+               return 2;
+       if (m_len == M2_MIN_LEN && m_off <= MX_MAX_OFFSET && lit >= 4)
+               return 2;
+       if (m_off <= M3_MAX_OFFSET) {
+               if (m_len <= M3_MAX_LEN)
+                       return 3;
+               m_len -= M3_MAX_LEN;
+       } else if (m_off <= M4_MAX_OFFSET) {
+               if (m_len <= M4_MAX_LEN)
+                       return 3;
+               m_len -= M4_MAX_LEN;
+       } else
+               return -1;
+       while (m_len > 255) {
+               m_len -= 255;
+               n++;
+       }
+       return n;
+}
+
+
+static int min_gain(unsigned ahead, unsigned lit1,
+                   unsigned lit2, int l1, int l2, int l3)
+{
+       int lazy_match_min_gain = 0;
+
+       assert (ahead >= 1);
+       lazy_match_min_gain += ahead;
+
+       if (lit1 <= 3)
+               lazy_match_min_gain += (lit2 <= 3) ? 0 : 2;
+       else if (lit1 <= 18)
+               lazy_match_min_gain += (lit2 <= 18) ? 0 : 1;
+
+       lazy_match_min_gain += (l2 - l1) * 2;
+       if (l3 > 0)
+               lazy_match_min_gain -= (ahead - l3) * 2;
+
+       if (lazy_match_min_gain < 0)
+               lazy_match_min_gain = 0;
+
+       return lazy_match_min_gain;
+}
+
+
+/***********************************************************************
+//
+************************************************************************/
+#if defined(SWD_BEST_OFF)
+
+static void better_match(const lzo_swd_p swd,
+                          unsigned *m_len, unsigned *m_off)
+{
+
+       if (*m_len <= M2_MIN_LEN)
+               return;
+
+       if (*m_off <= M2_MAX_OFFSET)
+               return;
+
+       /* M3/M4 -> M2 */
+       if (*m_off > M2_MAX_OFFSET &&
+           *m_len >= M2_MIN_LEN + 1 && *m_len <= M2_MAX_LEN + 1 &&
+           swd->best_off[*m_len-1] && swd->best_off[*m_len-1] <= M2_MAX_OFFSET)
+               {
+                       *m_len = *m_len - 1;
+                       *m_off = swd->best_off[*m_len];
+                       return;
+               }
+
+       /* M4 -> M2 */
+       if (*m_off > M3_MAX_OFFSET &&
+           *m_len >= M4_MAX_LEN + 1 && *m_len <= M2_MAX_LEN + 2 &&
+           swd->best_off[*m_len-2] && swd->best_off[*m_len-2] <= M2_MAX_OFFSET)
+               {
+                       *m_len = *m_len - 2;
+                       *m_off = swd->best_off[*m_len];
+                       return;
+               }
+       /* M4 -> M3 */
+       if (*m_off > M3_MAX_OFFSET &&
+           *m_len >= M4_MAX_LEN + 1 && *m_len <= M3_MAX_LEN + 1 &&
+           swd->best_off[*m_len-1] && swd->best_off[*m_len-1] <= M3_MAX_OFFSET)
+               {
+                       *m_len = *m_len - 1;
+                       *m_off = swd->best_off[*m_len];
+               }
+}
+
+#endif
+
+
+/***********************************************************************
+//
+************************************************************************/
+static int lzo1x_999_compress_internal(const uint8_t *in, unsigned in_len,
+               uint8_t *out, unsigned *out_len,
+               void *wrkmem,
+               unsigned good_length,
+               unsigned max_lazy,
+               unsigned max_chain,
+               uint32_t use_best_off)
+{
+       uint8_t *op;
+       const uint8_t *ii;
+       unsigned lit;
+       unsigned m_len, m_off;
+       lzo1x_999_t cc;
+       lzo1x_999_t * const c = &cc;
+       lzo_swd_p const swd = (lzo_swd_p) wrkmem;
+       int r;
+
+       c->init = 0;
+       c->ip = c->in = in;
+       c->in_end = in + in_len;
+       c->out = out;
+
+       op = out;
+       ii = c->ip;             /* point to start of literal run */
+       lit = 0;
+       c->r1_lit = 0;
+
+       r = init_match(c, swd, use_best_off);
+       if (r != 0)
+               return r;
+       swd->max_chain = max_chain;
+
+       r = find_match(c, swd, 0, 0);
+       if (r != 0)
+               return r;
+
+       while (c->look > 0) {
+               unsigned ahead;
+               unsigned max_ahead;
+               int l1, l2, l3;
+
+               m_len = c->m_len;
+               m_off = c->m_off;
+
+               assert(c->bp == c->ip - c->look);
+               assert(c->bp >= in);
+               if (lit == 0)
+                       ii = c->bp;
+               assert(ii + lit == c->bp);
+               assert(swd->b_char == *(c->bp));
+
+               if ( m_len < 2 ||
+                    (m_len == 2 && (m_off > M1_MAX_OFFSET || lit == 0 || lit >= 4)) ||
+                    /* Do not accept this match for compressed-data compatibility
+                     * with LZO v1.01 and before
+                     * [ might be a problem for decompress() and optimize() ]
+                     */
+                    (m_len == 2 && op == out) ||
+                    (op == out && lit == 0))
+                       {
+                               /* a literal */
+                               m_len = 0;
+                       }
+               else if (m_len == M2_MIN_LEN) {
+                       /* compression ratio improves if we code a literal in some cases */
+                       if (m_off > MX_MAX_OFFSET && lit >= 4)
+                               m_len = 0;
+               }
+
+               if (m_len == 0) {
+                       /* a literal */
+                       lit++;
+                       swd->max_chain = max_chain;
+                       r = find_match(c,swd,1,0);
+                       assert(r == 0);
+                       continue;
+               }
+
+               /* a match */
+#if defined(SWD_BEST_OFF)
+               if (swd->use_best_off)
+                       better_match(swd,&m_len,&m_off);
+#endif
+
+               /* shall we try a lazy match ? */
+               ahead = 0;
+               if (m_len >= max_lazy) {
+                       /* no */
+                       l1 = 0;
+                       max_ahead = 0;
+               } else {
+                       /* yes, try a lazy match */
+                       l1 = len_of_coded_match(m_len,m_off,lit);
+                       assert(l1 > 0);
+                       max_ahead = LZO_MIN(2, (unsigned)l1 - 1);
+               }
+
+
+               while (ahead < max_ahead && c->look > m_len) {
+                       int lazy_match_min_gain;
+
+                       if (m_len >= good_length)
+                               swd->max_chain = max_chain >> 2;
+                       else
+                               swd->max_chain = max_chain;
+                       r = find_match(c,swd,1,0);
+                       ahead++;
+
+                       assert(r == 0);
+                       assert(c->look > 0);
+                       assert(ii + lit + ahead == c->bp);
+
+                       if (c->m_len < m_len)
+                               continue;
+                       if (c->m_len == m_len && c->m_off >= m_off)
+                               continue;
+#if defined(SWD_BEST_OFF)
+                       if (swd->use_best_off)
+                               better_match(swd,&c->m_len,&c->m_off);
+#endif
+                       l2 = len_of_coded_match(c->m_len,c->m_off,lit+ahead);
+                       if (l2 < 0)
+                               continue;
+
+                       /* compressed-data compatibility [see above] */
+                       l3 = (op == out) ? -1 : len_of_coded_match(ahead,m_off,lit);
+
+                       lazy_match_min_gain = min_gain(ahead,lit,lit+ahead,l1,l2,l3);
+                       if (c->m_len >= m_len + lazy_match_min_gain) {
+                               if (l3 > 0) {
+                                       /* code previous run */
+                                       op = code_run(c,op,ii,lit);
+                                       lit = 0;
+                                       /* code shortened match */
+                                       op = code_match(c,op,ahead,m_off);
+                               } else {
+                                       lit += ahead;
+                                       assert(ii + lit == c->bp);
+                               }
+                               goto lazy_match_done;
+                       }
+               }
+
+               assert(ii + lit + ahead == c->bp);
+
+               /* 1 - code run */
+               op = code_run(c,op,ii,lit);
+               lit = 0;
+
+               /* 2 - code match */
+               op = code_match(c,op,m_len,m_off);
+               swd->max_chain = max_chain;
+               r = find_match(c,swd,m_len,1+ahead);
+               assert(r == 0);
+
+ lazy_match_done: ;
+       }
+
+       /* store final run */
+       if (lit > 0)
+               op = STORE_RUN(c,op,ii,lit);
+
+#if defined(LZO_EOF_CODE)
+       *op++ = M4_MARKER | 1;
+       *op++ = 0;
+       *op++ = 0;
+#endif
+
+       *out_len = op - out;
+
+       return LZO_E_OK;
+}
+
+
+/***********************************************************************
+//
+************************************************************************/
+int lzo1x_999_compress_level(const uint8_t *in, unsigned in_len,
+               uint8_t *out, unsigned *out_len,
+               void *wrkmem,
+               int compression_level)
+{
+       static const struct {
+               uint16_t good_length;
+               uint16_t max_lazy;
+               uint16_t max_chain;
+               uint16_t use_best_off;
+       } c[3] = {
+               {     8,    32,  256,   0 },
+               {    32,   128, 2048,   1 },
+               { SWD_F, SWD_F, 4096,   1 }       /* max. compression */
+       };
+
+       if (compression_level < 7 || compression_level > 9)
+               return LZO_E_ERROR;
+
+       compression_level -= 7;
+       return lzo1x_999_compress_internal(in, in_len, out, out_len, wrkmem,
+                                          c[compression_level].good_length,
+                                          c[compression_level].max_lazy,
+                                          c[compression_level].max_chain,
+                                          c[compression_level].use_best_off);
+}
diff --git a/archival/lzo1x_c.c b/archival/lzo1x_c.c
new file mode 100644 (file)
index 0000000..cc86f74
--- /dev/null
@@ -0,0 +1,296 @@
+/* implementation of the LZO1[XY]-1 compression algorithm
+
+   This file is part of the LZO real-time data compression library.
+
+   Copyright (C) 1996..2008 Markus Franz Xaver Johannes Oberhumer
+   All Rights Reserved.
+
+   Markus F.X.J. Oberhumer <markus@oberhumer.com>
+   http://www.oberhumer.com/opensource/lzo/
+
+   The LZO library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU General Public License as
+   published by the Free Software Foundation; either version 2 of
+   the License, or (at your option) any later version.
+
+   The LZO library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.         See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with the LZO library; see the file COPYING.
+   If not, write to the Free Software Foundation, Inc.,
+   51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+/***********************************************************************
+// compress a block of data.
+************************************************************************/
+static NOINLINE unsigned
+do_compress(const uint8_t* in, unsigned in_len,
+               uint8_t* out, unsigned* out_len,
+               void* wrkmem)
+{
+       register const uint8_t* ip;
+       uint8_t* op;
+       const uint8_t* const in_end = in + in_len;
+       const uint8_t* const ip_end = in + in_len - M2_MAX_LEN - 5;
+       const uint8_t* ii;
+       const void* *const dict = (const void**) wrkmem;
+
+       op = out;
+       ip = in;
+       ii = ip;
+
+       ip += 4;
+       for (;;) {
+               register const uint8_t* m_pos;
+               unsigned m_off;
+               unsigned m_len;
+               unsigned dindex;
+
+               D_INDEX1(dindex,ip);
+               GINDEX(m_pos,m_off,dict,dindex,in);
+               if (LZO_CHECK_MPOS_NON_DET(m_pos,m_off,in,ip,M4_MAX_OFFSET))
+                       goto literal;
+#if 1
+               if (m_off <= M2_MAX_OFFSET || m_pos[3] == ip[3])
+                       goto try_match;
+               D_INDEX2(dindex,ip);
+#endif
+               GINDEX(m_pos,m_off,dict,dindex,in);
+               if (LZO_CHECK_MPOS_NON_DET(m_pos,m_off,in,ip,M4_MAX_OFFSET))
+                       goto literal;
+               if (m_off <= M2_MAX_OFFSET || m_pos[3] == ip[3])
+                       goto try_match;
+               goto literal;
+
+ try_match:
+#if 1 && defined(LZO_UNALIGNED_OK_2)
+               if (* (const lzo_ushortp) m_pos != * (const lzo_ushortp) ip)
+#else
+               if (m_pos[0] != ip[0] || m_pos[1] != ip[1])
+#endif
+               {
+               } else {
+                       if (m_pos[2] == ip[2]) {
+#if 0
+                               if (m_off <= M2_MAX_OFFSET)
+                                       goto match;
+                               if (lit <= 3)
+                                       goto match;
+                               if (lit == 3) {                   /* better compression, but slower */
+                                       assert(op - 2 > out); op[-2] |= (uint8_t)(3);
+                                       *op++ = *ii++; *op++ = *ii++; *op++ = *ii++;
+                                       goto code_match;
+                               }
+                               if (m_pos[3] == ip[3])
+#endif
+                                       goto match;
+                       }
+                       else {
+                               /* still need a better way for finding M1 matches */
+#if 0
+                               /* a M1 match */
+#if 0
+                               if (m_off <= M1_MAX_OFFSET && lit > 0 && lit <= 3)
+#else
+                               if (m_off <= M1_MAX_OFFSET && lit == 3)
+#endif
+                               {
+                                       register unsigned t;
+
+                                       t = lit;
+                                       assert(op - 2 > out); op[-2] |= (uint8_t)(t);
+                                       do *op++ = *ii++; while (--t > 0);
+                                       assert(ii == ip);
+                                       m_off -= 1;
+                                       *op++ = (uint8_t)(M1_MARKER | ((m_off & 3) << 2));
+                                       *op++ = (uint8_t)(m_off >> 2);
+                                       ip += 2;
+                                       goto match_done;
+                               }
+#endif
+                       }
+               }
+
+               /* a literal */
+ literal:
+               UPDATE_I(dict, 0, dindex, ip, in);
+               ++ip;
+               if (ip >= ip_end)
+                       break;
+               continue;
+
+               /* a match */
+match:
+               UPDATE_I(dict, 0, dindex, ip, in);
+               /* store current literal run */
+               if (pd(ip, ii) > 0) {
+                       register unsigned t = pd(ip, ii);
+
+                       if (t <= 3) {
+                               assert(op - 2 > out);
+                               op[-2] |= (uint8_t)(t);
+                       }
+                       else if (t <= 18)
+                               *op++ = (uint8_t)(t - 3);
+                       else {
+                               register unsigned tt = t - 18;
+
+                               *op++ = 0;
+                               while (tt > 255) {
+                                       tt -= 255;
+                                       *op++ = 0;
+                               }
+                               assert(tt > 0);
+                               *op++ = (uint8_t)(tt);
+                       }
+                       do *op++ = *ii++; while (--t > 0);
+               }
+
+               /* code the match */
+               assert(ii == ip);
+               ip += 3;
+               if (m_pos[3] != *ip++ || m_pos[4] != *ip++ || m_pos[5] != *ip++
+                || m_pos[6] != *ip++ || m_pos[7] != *ip++ || m_pos[8] != *ip++
+#ifdef LZO1Y
+                || m_pos[ 9] != *ip++ || m_pos[10] != *ip++ || m_pos[11] != *ip++
+                || m_pos[12] != *ip++ || m_pos[13] != *ip++ || m_pos[14] != *ip++
+#endif
+               ) {
+                       --ip;
+                       m_len = pd(ip, ii);
+                       assert(m_len >= 3);
+                       assert(m_len <= M2_MAX_LEN);
+
+                       if (m_off <= M2_MAX_OFFSET) {
+                               m_off -= 1;
+#if defined(LZO1X)
+                               *op++ = (uint8_t)(((m_len - 1) << 5) | ((m_off & 7) << 2));
+                               *op++ = (uint8_t)(m_off >> 3);
+#elif defined(LZO1Y)
+                               *op++ = (uint8_t)(((m_len + 1) << 4) | ((m_off & 3) << 2));
+                               *op++ = (uint8_t)(m_off >> 2);
+#endif
+                       }
+                       else if (m_off <= M3_MAX_OFFSET) {
+                               m_off -= 1;
+                               *op++ = (uint8_t)(M3_MARKER | (m_len - 2));
+                               goto m3_m4_offset;
+                       } else {
+#if defined(LZO1X)
+                               m_off -= 0x4000;
+                               assert(m_off > 0);
+                               assert(m_off <= 0x7fff);
+                               *op++ = (uint8_t)(M4_MARKER | ((m_off & 0x4000) >> 11) | (m_len - 2));
+                               goto m3_m4_offset;
+#elif defined(LZO1Y)
+                               goto m4_match;
+#endif
+                       }
+               }
+               else {
+                       {
+                               const uint8_t* end = in_end;
+                               const uint8_t* m = m_pos + M2_MAX_LEN + 1;
+                               while (ip < end && *m == *ip)
+                                       m++, ip++;
+                               m_len = pd(ip, ii);
+                       }
+                       assert(m_len > M2_MAX_LEN);
+
+                       if (m_off <= M3_MAX_OFFSET) {
+                               m_off -= 1;
+                               if (m_len <= 33)
+                                       *op++ = (uint8_t)(M3_MARKER | (m_len - 2));
+                               else {
+                                       m_len -= 33;
+                                       *op++ = M3_MARKER | 0;
+                                       goto m3_m4_len;
+                               }
+                       } else {
+#if defined(LZO1Y)
+ m4_match:
+#endif
+                               m_off -= 0x4000;
+                               assert(m_off > 0);
+                               assert(m_off <= 0x7fff);
+                               if (m_len <= M4_MAX_LEN)
+                                       *op++ = (uint8_t)(M4_MARKER | ((m_off & 0x4000) >> 11) | (m_len - 2));
+                               else {
+                                       m_len -= M4_MAX_LEN;
+                                       *op++ = (uint8_t)(M4_MARKER | ((m_off & 0x4000) >> 11));
+ m3_m4_len:
+                                       while (m_len > 255) {
+                                               m_len -= 255;
+                                               *op++ = 0;
+                                       }
+                                       assert(m_len > 0);
+                                       *op++ = (uint8_t)(m_len);
+                               }
+                       }
+ m3_m4_offset:
+                       *op++ = (uint8_t)((m_off & 63) << 2);
+                       *op++ = (uint8_t)(m_off >> 6);
+               }
+#if 0
+ match_done:
+#endif
+               ii = ip;
+               if (ip >= ip_end)
+                       break;
+       }
+
+       *out_len = pd(op, out);
+       return pd(in_end, ii);
+}
+
+/***********************************************************************
+// public entry point
+************************************************************************/
+int DO_COMPRESS(const uint8_t* in, unsigned in_len,
+               uint8_t* out, unsigned* out_len,
+               void* wrkmem)
+{
+       uint8_t* op = out;
+       unsigned t;
+
+       if (in_len <= M2_MAX_LEN + 5)
+               t = in_len;
+       else {
+               t = do_compress(in,in_len,op,out_len,wrkmem);
+               op += *out_len;
+       }
+
+       if (t > 0) {
+               const uint8_t* ii = in + in_len - t;
+
+               if (op == out && t <= 238)
+                       *op++ = (uint8_t)(17 + t);
+               else if (t <= 3)
+                       op[-2] |= (uint8_t)(t);
+               else if (t <= 18)
+                       *op++ = (uint8_t)(t - 3);
+               else {
+                       unsigned tt = t - 18;
+
+                       *op++ = 0;
+                       while (tt > 255) {
+                               tt -= 255;
+                               *op++ = 0;
+                       }
+                       assert(tt > 0);
+                       *op++ = (uint8_t)(tt);
+               }
+               do *op++ = *ii++; while (--t > 0);
+       }
+
+       *op++ = M4_MARKER | 1;
+       *op++ = 0;
+       *op++ = 0;
+
+       *out_len = pd(op, out);
+       return 0; /*LZO_E_OK*/
+}
diff --git a/archival/lzo1x_d.c b/archival/lzo1x_d.c
new file mode 100644 (file)
index 0000000..348a855
--- /dev/null
@@ -0,0 +1,420 @@
+/* implementation of the LZO1X decompression algorithm
+
+   This file is part of the LZO real-time data compression library.
+
+   Copyright (C) 1996..2008 Markus Franz Xaver Johannes Oberhumer
+   All Rights Reserved.
+
+   Markus F.X.J. Oberhumer <markus@oberhumer.com>
+   http://www.oberhumer.com/opensource/lzo/
+
+   The LZO library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU General Public License as
+   published by the Free Software Foundation; either version 2 of
+   the License, or (at your option) any later version.
+
+   The LZO library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.         See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with the LZO library; see the file COPYING.
+   If not, write to the Free Software Foundation, Inc.,
+   51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+#include "libbb.h"
+#include "liblzo.h"
+
+/***********************************************************************
+// decompress a block of data.
+************************************************************************/
+/* safe decompression with overrun testing */
+int lzo1x_decompress_safe(const uint8_t* in, unsigned in_len,
+               uint8_t* out, unsigned* out_len,
+               void* wrkmem UNUSED_PARAM)
+{
+       register uint8_t* op;
+       register const uint8_t* ip;
+       register unsigned t;
+#if defined(COPY_DICT)
+       unsigned m_off;
+       const uint8_t* dict_end;
+#else
+       register const uint8_t* m_pos = NULL; /* possibly not needed */
+#endif
+       const uint8_t* const ip_end = in + in_len;
+#if defined(HAVE_ANY_OP)
+       uint8_t* const op_end = out + *out_len;
+#endif
+#if defined(LZO1Z)
+       unsigned last_m_off = 0;
+#endif
+
+//     LZO_UNUSED(wrkmem);
+
+#if defined(COPY_DICT)
+       if (dict) {
+               if (dict_len > M4_MAX_OFFSET) {
+                       dict += dict_len - M4_MAX_OFFSET;
+                       dict_len = M4_MAX_OFFSET;
+               }
+               dict_end = dict + dict_len;
+       } else {
+               dict_len = 0;
+               dict_end = NULL;
+       }
+#endif /* COPY_DICT */
+
+       *out_len = 0;
+
+       op = out;
+       ip = in;
+
+       if (*ip > 17) {
+               t = *ip++ - 17;
+               if (t < 4)
+                       goto match_next;
+               assert(t > 0); NEED_OP(t); NEED_IP(t+1);
+               do *op++ = *ip++; while (--t > 0);
+               goto first_literal_run;
+       }
+
+       while (TEST_IP && TEST_OP) {
+               t = *ip++;
+               if (t >= 16)
+                       goto match;
+               /* a literal run */
+               if (t == 0) {
+                       NEED_IP(1);
+                       while (*ip == 0) {
+                               t += 255;
+                               ip++;
+                               NEED_IP(1);
+                       }
+                       t += 15 + *ip++;
+               }
+               /* copy literals */
+               assert(t > 0);
+               NEED_OP(t+3);
+               NEED_IP(t+4);
+#if defined(LZO_UNALIGNED_OK_4) || defined(LZO_ALIGNED_OK_4)
+# if !defined(LZO_UNALIGNED_OK_4)
+               if (PTR_ALIGNED2_4(op, ip))
+# endif
+               {
+                       COPY4(op, ip);
+                       op += 4;
+                       ip += 4;
+                       if (--t > 0) {
+                               if (t >= 4) {
+                                       do {
+                                               COPY4(op, ip);
+                                               op += 4;
+                                               ip += 4;
+                                               t -= 4;
+                                       } while (t >= 4);
+                                       if (t > 0)
+                                               do *op++ = *ip++; while (--t > 0);
+                               } else {
+                                       do *op++ = *ip++; while (--t > 0);
+                               }
+                       }
+               }
+# if !defined(LZO_UNALIGNED_OK_4)
+               else
+# endif
+#endif
+#if !defined(LZO_UNALIGNED_OK_4)
+               {
+                       *op++ = *ip++;
+                       *op++ = *ip++;
+                       *op++ = *ip++;
+                       do *op++ = *ip++; while (--t > 0);
+               }
+#endif
+
+ first_literal_run:
+               t = *ip++;
+               if (t >= 16)
+                       goto match;
+#if defined(COPY_DICT)
+#if defined(LZO1Z)
+               m_off = (1 + M2_MAX_OFFSET) + (t << 6) + (*ip++ >> 2);
+               last_m_off = m_off;
+#else
+               m_off = (1 + M2_MAX_OFFSET) + (t >> 2) + (*ip++ << 2);
+#endif
+               NEED_OP(3);
+               t = 3; COPY_DICT(t,m_off)
+#else /* !COPY_DICT */
+#if defined(LZO1Z)
+               t = (1 + M2_MAX_OFFSET) + (t << 6) + (*ip++ >> 2);
+               m_pos = op - t;
+               last_m_off = t;
+#else
+               m_pos = op - (1 + M2_MAX_OFFSET);
+               m_pos -= t >> 2;
+               m_pos -= *ip++ << 2;
+#endif
+               TEST_LB(m_pos); NEED_OP(3);
+               *op++ = *m_pos++;
+               *op++ = *m_pos++;
+               *op++ = *m_pos;
+#endif /* COPY_DICT */
+               goto match_done;
+
+               /* handle matches */
+               do {
+ match:
+                       if (t >= 64) {          /* a M2 match */
+#if defined(COPY_DICT)
+#if defined(LZO1X)
+                               m_off = 1 + ((t >> 2) & 7) + (*ip++ << 3);
+                               t = (t >> 5) - 1;
+#elif defined(LZO1Y)
+                               m_off = 1 + ((t >> 2) & 3) + (*ip++ << 2);
+                               t = (t >> 4) - 3;
+#elif defined(LZO1Z)
+                               m_off = t & 0x1f;
+                               if (m_off >= 0x1c)
+                                       m_off = last_m_off;
+                               else {
+                                       m_off = 1 + (m_off << 6) + (*ip++ >> 2);
+                                       last_m_off = m_off;
+                               }
+                               t = (t >> 5) - 1;
+#endif
+#else /* !COPY_DICT */
+#if defined(LZO1X)
+                               m_pos = op - 1;
+                               m_pos -= (t >> 2) & 7;
+                               m_pos -= *ip++ << 3;
+                               t = (t >> 5) - 1;
+#elif defined(LZO1Y)
+                               m_pos = op - 1;
+                               m_pos -= (t >> 2) & 3;
+                               m_pos -= *ip++ << 2;
+                               t = (t >> 4) - 3;
+#elif defined(LZO1Z)
+                               {
+                                       unsigned off = t & 0x1f;
+                                       m_pos = op;
+                                       if (off >= 0x1c) {
+                                               assert(last_m_off > 0);
+                                               m_pos -= last_m_off;
+                                       } else {
+                                               off = 1 + (off << 6) + (*ip++ >> 2);
+                                               m_pos -= off;
+                                               last_m_off = off;
+                                       }
+                               }
+                               t = (t >> 5) - 1;
+#endif
+                               TEST_LB(m_pos); assert(t > 0); NEED_OP(t+3-1);
+                               goto copy_match;
+#endif /* COPY_DICT */
+                       }
+                       else if (t >= 32) {                     /* a M3 match */
+                               t &= 31;
+                               if (t == 0) {
+                                       NEED_IP(1);
+                                       while (*ip == 0) {
+                                               t += 255;
+                                               ip++;
+                                               NEED_IP(1);
+                                       }
+                                       t += 31 + *ip++;
+                               }
+#if defined(COPY_DICT)
+#if defined(LZO1Z)
+                               m_off = 1 + (ip[0] << 6) + (ip[1] >> 2);
+                               last_m_off = m_off;
+#else
+                               m_off = 1 + (ip[0] >> 2) + (ip[1] << 6);
+#endif
+#else /* !COPY_DICT */
+#if defined(LZO1Z)
+                               {
+                                       unsigned off = 1 + (ip[0] << 6) + (ip[1] >> 2);
+                                       m_pos = op - off;
+                                       last_m_off = off;
+                               }
+#elif defined(LZO_UNALIGNED_OK_2) && defined(LZO_ABI_LITTLE_ENDIAN)
+                               m_pos = op - 1;
+                               m_pos -= (* (const lzo_ushortp) ip) >> 2;
+#else
+                               m_pos = op - 1;
+                               m_pos -= (ip[0] >> 2) + (ip[1] << 6);
+#endif
+#endif /* COPY_DICT */
+                               ip += 2;
+                       }
+                       else if (t >= 16) {                     /* a M4 match */
+#if defined(COPY_DICT)
+                               m_off = (t & 8) << 11;
+#else /* !COPY_DICT */
+                               m_pos = op;
+                               m_pos -= (t & 8) << 11;
+#endif /* COPY_DICT */
+                               t &= 7;
+                               if (t == 0) {
+                                       NEED_IP(1);
+                                       while (*ip == 0) {
+                                               t += 255;
+                                               ip++;
+                                               NEED_IP(1);
+                                       }
+                                       t += 7 + *ip++;
+                               }
+#if defined(COPY_DICT)
+#if defined(LZO1Z)
+                               m_off += (ip[0] << 6) + (ip[1] >> 2);
+#else
+                               m_off += (ip[0] >> 2) + (ip[1] << 6);
+#endif
+                               ip += 2;
+                               if (m_off == 0)
+                                       goto eof_found;
+                               m_off += 0x4000;
+#if defined(LZO1Z)
+                               last_m_off = m_off;
+#endif
+#else /* !COPY_DICT */
+#if defined(LZO1Z)
+                               m_pos -= (ip[0] << 6) + (ip[1] >> 2);
+#elif defined(LZO_UNALIGNED_OK_2) && defined(LZO_ABI_LITTLE_ENDIAN)
+                               m_pos -= (* (const lzo_ushortp) ip) >> 2;
+#else
+                               m_pos -= (ip[0] >> 2) + (ip[1] << 6);
+#endif
+                               ip += 2;
+                               if (m_pos == op)
+                                       goto eof_found;
+                               m_pos -= 0x4000;
+#if defined(LZO1Z)
+                               last_m_off = pd((const uint8_t*)op, m_pos);
+#endif
+#endif /* COPY_DICT */
+                       }
+                       else {                          /* a M1 match */
+#if defined(COPY_DICT)
+#if defined(LZO1Z)
+                               m_off = 1 + (t << 6) + (*ip++ >> 2);
+                               last_m_off = m_off;
+#else
+                               m_off = 1 + (t >> 2) + (*ip++ << 2);
+#endif
+                               NEED_OP(2);
+                               t = 2; COPY_DICT(t,m_off)
+#else /* !COPY_DICT */
+#if defined(LZO1Z)
+                               t = 1 + (t << 6) + (*ip++ >> 2);
+                               m_pos = op - t;
+                               last_m_off = t;
+#else
+                               m_pos = op - 1;
+                               m_pos -= t >> 2;
+                               m_pos -= *ip++ << 2;
+#endif
+                               TEST_LB(m_pos); NEED_OP(2);
+                               *op++ = *m_pos++;
+                               *op++ = *m_pos;
+#endif /* COPY_DICT */
+                               goto match_done;
+                       }
+
+                       /* copy match */
+#if defined(COPY_DICT)
+
+                       NEED_OP(t+3-1);
+                       t += 3-1; COPY_DICT(t,m_off)
+
+#else /* !COPY_DICT */
+
+                       TEST_LB(m_pos); assert(t > 0); NEED_OP(t+3-1);
+#if defined(LZO_UNALIGNED_OK_4) || defined(LZO_ALIGNED_OK_4)
+# if !defined(LZO_UNALIGNED_OK_4)
+                       if (t >= 2 * 4 - (3 - 1) && PTR_ALIGNED2_4(op,m_pos)) {
+                               assert((op - m_pos) >= 4);      /* both pointers are aligned */
+# else
+                       if (t >= 2 * 4 - (3 - 1) && (op - m_pos) >= 4) {
+# endif
+                               COPY4(op,m_pos);
+                               op += 4; m_pos += 4; t -= 4 - (3 - 1);
+                               do {
+                                       COPY4(op,m_pos);
+                                       op += 4; m_pos += 4; t -= 4;
+                               } while (t >= 4);
+                               if (t > 0)
+                                       do *op++ = *m_pos++; while (--t > 0);
+                       }
+                       else
+#endif
+                       {
+ copy_match:
+                               *op++ = *m_pos++; *op++ = *m_pos++;
+                               do *op++ = *m_pos++; while (--t > 0);
+                       }
+
+#endif /* COPY_DICT */
+
+ match_done:
+#if defined(LZO1Z)
+                       t = ip[-1] & 3;
+#else
+                       t = ip[-2] & 3;
+#endif
+                       if (t == 0)
+                               break;
+
+                       /* copy literals */
+ match_next:
+                       assert(t > 0);
+                       assert(t < 4);
+                       NEED_OP(t);
+                       NEED_IP(t+1);
+#if 0
+                       do *op++ = *ip++; while (--t > 0);
+#else
+                       *op++ = *ip++;
+                       if (t > 1) {
+                               *op++ = *ip++;
+                               if (t > 2)
+                                       *op++ = *ip++;
+                       }
+#endif
+                       t = *ip++;
+               } while (TEST_IP && TEST_OP);
+       }
+
+//#if defined(HAVE_TEST_IP) || defined(HAVE_TEST_OP)
+       /* no EOF code was found */
+       *out_len = pd(op, out);
+       return LZO_E_EOF_NOT_FOUND;
+//#endif
+
+ eof_found:
+       assert(t == 1);
+       *out_len = pd(op, out);
+       return (ip == ip_end ? LZO_E_OK :
+                  (ip < ip_end  ? LZO_E_INPUT_NOT_CONSUMED : LZO_E_INPUT_OVERRUN));
+
+//#if defined(HAVE_NEED_IP)
+ input_overrun:
+       *out_len = pd(op, out);
+       return LZO_E_INPUT_OVERRUN;
+//#endif
+
+//#if defined(HAVE_NEED_OP)
+ output_overrun:
+       *out_len = pd(op, out);
+       return LZO_E_OUTPUT_OVERRUN;
+//#endif
+
+//#if defined(LZO_TEST_OVERRUN_LOOKBEHIND)
+ lookbehind_overrun:
+       *out_len = pd(op, out);
+       return LZO_E_LOOKBEHIND_OVERRUN;
+//#endif
+}
diff --git a/archival/lzop.c b/archival/lzop.c
new file mode 100644 (file)
index 0000000..a30d5e7
--- /dev/null
@@ -0,0 +1,1075 @@
+/*
+   This file is part of the lzop file compressor.
+
+   Copyright (C) 1996..2003 Markus Franz Xaver Johannes Oberhumer
+   All Rights Reserved.
+
+   Markus F.X.J. Oberhumer <markus@oberhumer.com>
+   http://www.oberhumer.com/opensource/lzop/
+
+   lzop and the LZO library are free software; you can redistribute them
+   and/or modify them under the terms of the GNU General Public License as
+   published by the Free Software Foundation; either version 2 of
+   the License, or (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.         See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; see the file COPYING.
+   If not, write to the Free Software Foundation, Inc.,
+   59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+   "Minimalized" for busybox by Alain Knaff
+*/
+
+#include "libbb.h"
+#include "unarchive.h"
+#include "liblzo_interface.h"
+
+/* lzo-2.03/src/lzo_ptr.h */
+#define pd(a,b)         ((unsigned)((a)-(b)))
+
+#define lzo_version()                  LZO_VERSION
+#define lzo_sizeof_dict_t              (sizeof(uint8_t*))
+
+/* lzo-2.03/include/lzo/lzo1x.h */
+#define LZO1X_1_MEM_COMPRESS   (16384 * lzo_sizeof_dict_t)
+#define LZO1X_1_15_MEM_COMPRESS (32768 * lzo_sizeof_dict_t)
+#define LZO1X_999_MEM_COMPRESS (14 * 16384 * sizeof(short))
+
+/* lzo-2.03/src/lzo1x_oo.c */
+#define NO_LIT UINT_MAX
+
+/**********************************************************************/
+static void copy2(uint8_t* ip, const uint8_t* m_pos, unsigned off)
+{
+       ip[0] = m_pos[0];
+       if (off == 1)
+               ip[1] = m_pos[0];
+       else
+               ip[1] = m_pos[1];
+}
+
+static void copy3(uint8_t* ip, const uint8_t* m_pos, unsigned off)
+{
+       ip[0] = m_pos[0];
+       if (off == 1) {
+               ip[2] = ip[1] = m_pos[0];
+       }
+       else if (off == 2) {
+               ip[1] = m_pos[1];
+               ip[2] = m_pos[0];
+       }
+       else {
+               ip[1] = m_pos[1];
+               ip[2] = m_pos[2];
+       }
+}
+
+/**********************************************************************/
+// optimize a block of data.
+/**********************************************************************/
+#define TEST_IP                (ip < ip_end)
+#define TEST_OP                (op <= op_end)
+
+static int lzo1x_optimize(uint8_t *in, unsigned in_len,
+               uint8_t *out, unsigned *out_len,
+               void* wrkmem UNUSED_PARAM)
+{
+       uint8_t* op;
+       uint8_t* ip;
+       unsigned t;
+       uint8_t* m_pos;
+       uint8_t* const ip_end = in + in_len;
+       uint8_t* const op_end = out + *out_len;
+       uint8_t* litp = NULL;
+       unsigned lit = 0;
+       unsigned next_lit = NO_LIT;
+       unsigned nl;
+       unsigned long o_m1_a = 0, o_m1_b = 0, o_m2 = 0, o_m3_a = 0, o_m3_b = 0;
+
+//       LZO_UNUSED(wrkmem);
+
+       *out_len = 0;
+
+       op = out;
+       ip = in;
+
+       if (*ip > 17) {
+               t = *ip++ - 17;
+               if (t < 4)
+                       goto match_next;
+               goto first_literal_run;
+       }
+
+       while (TEST_IP && TEST_OP) {
+               t = *ip++;
+               if (t >= 16)
+                       goto match;
+               /* a literal run */
+               litp = ip - 1;
+               if (t == 0) {
+                       t = 15;
+                       while (*ip == 0)
+                               t += 255, ip++;
+                       t += *ip++;
+               }
+               lit = t + 3;
+               /* copy literals */
+ copy_literal_run:
+               *op++ = *ip++;
+               *op++ = *ip++;
+               *op++ = *ip++;
+ first_literal_run:
+               do *op++ = *ip++; while (--t > 0);
+
+               t = *ip++;
+
+               if (t >= 16)
+                       goto match;
+#if defined(LZO1X)
+               m_pos = op - 1 - 0x800;
+#elif defined(LZO1Y)
+               m_pos = op - 1 - 0x400;
+#endif
+               m_pos -= t >> 2;
+               m_pos -= *ip++ << 2;
+               *op++ = *m_pos++;
+               *op++ = *m_pos++;
+               *op++ = *m_pos++;
+               lit = 0;
+               goto match_done;
+
+
+               /* handle matches */
+               do {
+                       if (t < 16) { /* a M1 match */
+                               m_pos = op - 1;
+                               m_pos -= t >> 2;
+                               m_pos -= *ip++ << 2;
+
+                               if (litp == NULL)
+                                       goto copy_m1;
+
+                               nl = ip[-2] & 3;
+                               /* test if a match follows */
+                               if (nl == 0 && lit == 1 && ip[0] >= 16) {
+                                       next_lit = nl;
+                                       /* adjust length of previous short run */
+                                       lit += 2;
+                                       *litp = (unsigned char)((*litp & ~3) | lit);
+                                       /* copy over the 2 literals that replace the match */
+                                       copy2(ip-2, m_pos, pd(op, m_pos));
+                                       o_m1_a++;
+                               }
+                               /* test if a literal run follows */
+                               else if (nl == 0 && ip[0] < 16 && ip[0] != 0 &&
+                                                (lit + 2 + ip[0] < 16))
+                               {
+                                       t = *ip++;
+                                       /* remove short run */
+                                       *litp &= ~3;
+                                       /* copy over the 2 literals that replace the match */
+                                       copy2(ip-3+1,m_pos,pd(op,m_pos));
+                                       /* move literals 1 byte ahead */
+                                       litp += 2;
+                                       if (lit > 0)
+                                               memmove(litp+1, litp, lit);
+                                       /* insert new length of long literal run */
+                                       lit += 2 + t + 3;
+                                       *litp = (unsigned char)(lit - 3);
+
+                                       o_m1_b++;
+                                       *op++ = *m_pos++; *op++ = *m_pos++;
+                                       goto copy_literal_run;
+                               }
+ copy_m1:
+                               *op++ = *m_pos++;
+                               *op++ = *m_pos++;
+                       } else {
+ match:
+                               if (t >= 64) {                          /* a M2 match */
+                                       m_pos = op - 1;
+#if defined(LZO1X)
+                                       m_pos -= (t >> 2) & 7;
+                                       m_pos -= *ip++ << 3;
+                                       t = (t >> 5) - 1;
+#elif defined(LZO1Y)
+                                       m_pos -= (t >> 2) & 3;
+                                       m_pos -= *ip++ << 2;
+                                       t = (t >> 4) - 3;
+#endif
+                                       if (litp == NULL)
+                                               goto copy_m;
+
+                                       nl = ip[-2] & 3;
+                                       /* test if in beetween two long literal runs */
+                                       if (t == 1 && lit > 3 && nl == 0
+                                        && ip[0] < 16 && ip[0] != 0 && (lit + 3 + ip[0] < 16)
+                                       ) {
+                                               t = *ip++;
+                                               /* copy over the 3 literals that replace the match */
+                                               copy3(ip-1-2,m_pos,pd(op,m_pos));
+                                               /* set new length of previous literal run */
+                                               lit += 3 + t + 3;
+                                               *litp = (unsigned char)(lit - 3);
+                                               o_m2++;
+                                               *op++ = *m_pos++;
+                                               *op++ = *m_pos++;
+                                               *op++ = *m_pos++;
+                                               goto copy_literal_run;
+                                       }
+                               } else {
+                                       if (t >= 32) {                  /* a M3 match */
+                                               t &= 31;
+                                               if (t == 0) {
+                                                       t = 31;
+                                                       while (*ip == 0)
+                                                               t += 255, ip++;
+                                                       t += *ip++;
+                                               }
+                                               m_pos = op - 1;
+                                               m_pos -= *ip++ >> 2;
+                                               m_pos -= *ip++ << 6;
+                                       } else {                                        /* a M4 match */
+                                               m_pos = op;
+                                               m_pos -= (t & 8) << 11;
+                                               t &= 7;
+                                               if (t == 0) {
+                                                       t = 7;
+                                                       while (*ip == 0)
+                                                               t += 255, ip++;
+                                                       t += *ip++;
+                                               }
+                                               m_pos -= *ip++ >> 2;
+                                               m_pos -= *ip++ << 6;
+                                               if (m_pos == op)
+                                                       goto eof_found;
+                                               m_pos -= 0x4000;
+                                       }
+                                       if (litp == NULL)
+                                               goto copy_m;
+
+                                       nl = ip[-2] & 3;
+                                       /* test if in beetween two matches */
+                                       if (t == 1 && lit == 0 && nl == 0 && ip[0] >= 16) {
+                                               next_lit = nl;
+                                               /* make a previous short run */
+                                               lit += 3;
+                                               *litp = (unsigned char)((*litp & ~3) | lit);
+                                               /* copy over the 3 literals that replace the match */
+                                               copy3(ip-3,m_pos,pd(op,m_pos));
+                                               o_m3_a++;
+                                       }
+                                       /* test if a literal run follows */
+                                       else if (t == 1 && lit <= 3 && nl == 0
+                                        && ip[0] < 16 && ip[0] != 0 && (lit + 3 + ip[0] < 16)
+                                       ) {
+                                               t = *ip++;
+                                               /* remove short run */
+                                               *litp &= ~3;
+                                               /* copy over the 3 literals that replace the match */
+                                               copy3(ip-4+1,m_pos,pd(op,m_pos));
+                                               /* move literals 1 byte ahead */
+                                               litp += 2;
+                                               if (lit > 0)
+                                                       memmove(litp+1,litp,lit);
+                                               /* insert new length of long literal run */
+                                               lit += 3 + t + 3;
+                                               *litp = (unsigned char)(lit - 3);
+
+                                               o_m3_b++;
+                                               *op++ = *m_pos++;
+                                               *op++ = *m_pos++;
+                                               *op++ = *m_pos++;
+                                               goto copy_literal_run;
+                                       }
+                               }
+ copy_m:
+                               *op++ = *m_pos++;
+                               *op++ = *m_pos++;
+                               do *op++ = *m_pos++; while (--t > 0);
+                       }
+
+ match_done:
+                       if (next_lit == NO_LIT) {
+                               t = ip[-2] & 3;
+                               lit = t;
+                               litp = ip - 2;
+                       }
+                       else
+                               t = next_lit;
+                       next_lit = NO_LIT;
+                       if (t == 0)
+                               break;
+                       /* copy literals */
+ match_next:
+                       do *op++ = *ip++; while (--t > 0);
+                       t = *ip++;
+               } while (TEST_IP && TEST_OP);
+       }
+
+       /* no EOF code was found */
+       *out_len = pd(op, out);
+       return LZO_E_EOF_NOT_FOUND;
+
+ eof_found:
+//       LZO_UNUSED(o_m1_a); LZO_UNUSED(o_m1_b); LZO_UNUSED(o_m2);
+//       LZO_UNUSED(o_m3_a); LZO_UNUSED(o_m3_b);
+       *out_len = pd(op, out);
+       return (ip == ip_end ? LZO_E_OK :
+                  (ip < ip_end  ? LZO_E_INPUT_NOT_CONSUMED : LZO_E_INPUT_OVERRUN));
+}
+
+/**********************************************************************/
+#define F_OS F_OS_UNIX
+#define F_CS F_CS_NATIVE
+
+/**********************************************************************/
+#define ADLER32_INIT_VALUE 1
+#define CRC32_INIT_VALUE   0
+
+/**********************************************************************/
+enum {
+       M_LZO1X_1    = 1,
+       M_LZO1X_1_15 = 2,
+       M_LZO1X_999  = 3,
+};
+
+/**********************************************************************/
+/* header flags */
+#define F_ADLER32_D     0x00000001L
+#define F_ADLER32_C     0x00000002L
+#define F_H_EXTRA_FIELD 0x00000040L
+#define F_H_GMTDIFF     0x00000080L
+#define F_CRC32_D       0x00000100L
+#define F_CRC32_C       0x00000200L
+#define F_H_FILTER      0x00000800L
+#define F_H_CRC32       0x00001000L
+#define F_MASK          0x00003FFFL
+
+/* operating system & file system that created the file [mostly unused] */
+#define F_OS_UNIX       0x03000000L
+#define F_OS_SHIFT      24
+#define F_OS_MASK       0xff000000L
+
+/* character set for file name encoding [mostly unused] */
+#define F_CS_NATIVE     0x00000000L
+#define F_CS_SHIFT      20
+#define F_CS_MASK       0x00f00000L
+
+/* these bits must be zero */
+#define F_RESERVED      ((F_MASK | F_OS_MASK | F_CS_MASK) ^ 0xffffffffL)
+
+typedef struct chksum_t {
+       uint32_t f_adler32;
+       uint32_t f_crc32;
+} chksum_t;
+
+typedef struct header_t {
+       unsigned version;
+       unsigned lib_version;
+       unsigned version_needed_to_extract;
+       uint32_t flags;
+       uint32_t mode;
+       uint32_t mtime;
+       uint32_t gmtdiff;
+       uint32_t header_checksum;
+
+       uint32_t extra_field_len;
+       uint32_t extra_field_checksum;
+
+       unsigned char method;
+       unsigned char level;
+
+       /* info */
+       char name[255+1];
+} header_t;
+
+struct globals {
+       const uint32_t *lzo_crc32_table;
+       chksum_t chksum_in;
+       chksum_t chksum_out;
+};
+#define G (*(struct globals*)&bb_common_bufsiz1)
+#define INIT_G() do { } while (0)
+//#define G (*ptr_to_globals)
+//#define INIT_G() do {
+//        SET_PTR_TO_GLOBALS(xzalloc(sizeof(G)));
+//} while (0)
+
+
+/**********************************************************************/
+#define LZOP_VERSION            0x1010
+//#define LZOP_VERSION_STRING     "1.01"
+//#define LZOP_VERSION_DATE       "Apr 27th 2003"
+
+#define OPTION_STRING "cfvdt123456789CF"
+
+enum {
+       OPT_STDOUT      = (1 << 0),
+       OPT_FORCE       = (1 << 1),
+       OPT_VERBOSE     = (1 << 2),
+       OPT_DECOMPRESS  = (1 << 3),
+       OPT_TEST        = (1 << 4),
+       OPT_1           = (1 << 5),
+       OPT_2           = (1 << 6),
+       OPT_3           = (1 << 7),
+       OPT_4           = (1 << 8),
+       OPT_5           = (1 << 9),
+       OPT_6           = (1 << 10),
+       OPT_789         = (7 << 11),
+       OPT_7           = (1 << 11),
+       OPT_8           = (1 << 12),
+       OPT_C           = (1 << 14),
+       OPT_F           = (1 << 15),
+};
+
+/**********************************************************************/
+// adler32 checksum
+// adapted from free code by Mark Adler <madler@alumni.caltech.edu>
+// see http://www.zlib.org/
+/**********************************************************************/
+static FAST_FUNC uint32_t
+lzo_adler32(uint32_t adler, const uint8_t* buf, unsigned len)
+{
+       enum {
+               LZO_BASE = 65521, /* largest prime smaller than 65536 */
+               /* NMAX is the largest n such that
+                * 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1 */
+               LZO_NMAX = 5552,
+       };
+       uint32_t s1 = adler & 0xffff;
+       uint32_t s2 = (adler >> 16) & 0xffff;
+       unsigned k;
+
+       if (buf == NULL)
+               return 1;
+
+       while (len > 0) {
+               k = len < LZO_NMAX ? (unsigned) len : LZO_NMAX;
+               len -= k;
+               if (k != 0) do {
+                       s1 += *buf++;
+                       s2 += s1;
+               } while (--k > 0);
+               s1 %= LZO_BASE;
+               s2 %= LZO_BASE;
+       }
+       return (s2 << 16) | s1;
+}
+
+static FAST_FUNC uint32_t
+lzo_crc32(uint32_t c, const uint8_t* buf, unsigned len)
+{
+       uint32_t crc;
+
+       if (buf == NULL)
+               return 0;
+
+       crc = ~c;
+       if (len != 0) do {
+       crc = G.lzo_crc32_table[((int)crc ^ *buf) & 0xff] ^ (crc >> 8);
+               buf += 1;
+               len -= 1;
+       } while (len > 0);
+
+       return ~crc;
+}
+
+/**********************************************************************/
+static void init_chksum(chksum_t *ct)
+{
+       ct->f_adler32 = ADLER32_INIT_VALUE;
+       ct->f_crc32 = CRC32_INIT_VALUE;
+}
+
+static void add_bytes_to_chksum(chksum_t *ct, const void* buf, int cnt)
+{
+       /* We need to handle the two checksums at once, because at the
+        * beginning of the header, we don't know yet which one we'll
+        * eventually need */
+       ct->f_adler32 = lzo_adler32(ct->f_adler32, (const uint8_t*)buf, cnt);
+       ct->f_crc32 = lzo_crc32(ct->f_crc32, (const uint8_t*)buf, cnt);
+}
+
+static uint32_t chksum_getresult(chksum_t *ct, const header_t *h)
+{
+       return (h->flags & F_H_CRC32) ? ct->f_crc32 : ct->f_adler32;
+}
+
+/**********************************************************************/
+static uint32_t read32(void)
+{
+       uint32_t v;
+       xread(0, &v, 4);
+       return ntohl(v);
+}
+
+static void write32(uint32_t v)
+{
+       v = htonl(v);
+       xwrite(1, &v, 4);
+}
+
+static void f_write(const void* buf, int cnt)
+{
+       xwrite(1, buf, cnt);
+       add_bytes_to_chksum(&G.chksum_out, buf, cnt);
+}
+
+static void f_read(void* buf, int cnt)
+{
+       xread(0, buf, cnt);
+       add_bytes_to_chksum(&G.chksum_in, buf, cnt);
+}
+
+static int f_read8(void)
+{
+       uint8_t v;
+       f_read(&v, 1);
+       return v;
+}
+
+static void f_write8(uint8_t v)
+{
+       f_write(&v, 1);
+}
+
+static unsigned f_read16(void)
+{
+       uint16_t v;
+       f_read(&v, 2);
+       return ntohs(v);
+}
+
+static void f_write16(uint16_t v)
+{
+       v = htons(v);
+       f_write(&v, 2);
+}
+
+static uint32_t f_read32(void)
+{
+       uint32_t v;
+       f_read(&v, 4);
+       return ntohl(v);
+}
+
+static void f_write32(uint32_t v)
+{
+       v = htonl(v);
+       f_write(&v, 4);
+}
+
+/**********************************************************************/
+static int lzo_get_method(header_t *h)
+{
+       /* check method */
+       if (h->method == M_LZO1X_1) {
+               if (h->level == 0)
+                       h->level = 3;
+       } else if (h->method == M_LZO1X_1_15) {
+               if (h->level == 0)
+                       h->level = 1;
+       } else if (h->method == M_LZO1X_999) {
+               if (h->level == 0)
+                       h->level = 9;
+       } else
+               return -1;              /* not a LZO method */
+
+       /* check compression level */
+       if (h->level < 1 || h->level > 9)
+               return 15;
+
+       return 0;
+}
+
+/**********************************************************************/
+#define LZO_BLOCK_SIZE (256 * 1024l)
+#define MAX_BLOCK_SIZE (64 * 1024l * 1024l)    /* DO NOT CHANGE */
+
+/* LZO may expand uncompressible data by a small amount */
+#define MAX_COMPRESSED_SIZE(x) ((x) + (x) / 16 + 64 + 3)
+
+/**********************************************************************/
+// compress a file
+/**********************************************************************/
+static smallint lzo_compress(const header_t *h)
+{
+       unsigned block_size = LZO_BLOCK_SIZE;
+       int r = 0; /* LZO_E_OK */
+       uint8_t *const b1 = xzalloc(block_size);
+       uint8_t *const b2 = xzalloc(MAX_COMPRESSED_SIZE(block_size));
+       unsigned src_len = 0, dst_len = 0;
+       uint32_t d_adler32 = ADLER32_INIT_VALUE;
+       uint32_t d_crc32 = CRC32_INIT_VALUE;
+       int l;
+       smallint ok = 1;
+       uint8_t *wrk_mem = NULL;
+
+       if (h->method == M_LZO1X_1)
+               wrk_mem = xzalloc(LZO1X_1_MEM_COMPRESS);
+       else if (h->method == M_LZO1X_1_15)
+               wrk_mem = xzalloc(LZO1X_1_15_MEM_COMPRESS);
+       else if (h->method == M_LZO1X_999)
+               wrk_mem = xzalloc(LZO1X_999_MEM_COMPRESS);
+
+       for (;;) {
+               /* read a block */
+               l = full_read(0, b1, block_size);
+               src_len = (l > 0 ? l : 0);
+
+               /* write uncompressed block size */
+               write32(src_len);
+
+               /* exit if last block */
+               if (src_len == 0)
+                       break;
+
+               /* compute checksum of uncompressed block */
+               if (h->flags & F_ADLER32_D)
+                       d_adler32 = lzo_adler32(ADLER32_INIT_VALUE, b1, src_len);
+               if (h->flags & F_CRC32_D)
+                       d_crc32 = lzo_crc32(CRC32_INIT_VALUE, b1, src_len);
+
+               /* compress */
+               if (h->method == M_LZO1X_1)
+                       r = lzo1x_1_compress(b1, src_len, b2, &dst_len, wrk_mem);
+               else if (h->method == M_LZO1X_1_15)
+                       r = lzo1x_1_15_compress(b1, src_len, b2, &dst_len, wrk_mem);
+#if ENABLE_LZOP_COMPR_HIGH
+               else if (h->method == M_LZO1X_999)
+                       r = lzo1x_999_compress_level(b1, src_len, b2, &dst_len,
+                                               wrk_mem, h->level);
+#endif
+               else
+                       bb_error_msg_and_die("internal error");
+
+               if (r != 0) /* not LZO_E_OK */
+                       bb_error_msg_and_die("internal error - compression failed");
+
+               /* write compressed block size */
+               if (dst_len < src_len) {
+                       /* optimize */
+                       if (h->method == M_LZO1X_999) {
+                               unsigned new_len = src_len;
+                               r = lzo1x_optimize(b2, dst_len, b1, &new_len, NULL);
+                               if (r != 0 /*LZO_E_OK*/ || new_len != src_len)
+                                       bb_error_msg_and_die("internal error - optimization failed");
+                       }
+                       write32(dst_len);
+               } else {
+                       /* data actually expanded => store data uncompressed */
+                       write32(src_len);
+               }
+
+               /* write checksum of uncompressed block */
+               if (h->flags & F_ADLER32_D)
+                       write32(d_adler32);
+               if (h->flags & F_CRC32_D)
+                       write32(d_crc32);
+
+               if (dst_len < src_len) {
+                       /* write checksum of compressed block */
+                       if (h->flags & F_ADLER32_C)
+                               write32(lzo_adler32(ADLER32_INIT_VALUE, b2,
+                                                       dst_len));
+                       if (h->flags & F_CRC32_C)
+                               write32(lzo_crc32(CRC32_INIT_VALUE, b2, dst_len));
+                       /* write compressed block data */
+                       xwrite(1, b2, dst_len);
+               } else {
+                       /* write uncompressed block data */
+                       xwrite(1, b1, src_len);
+               }
+       }
+
+       free(wrk_mem);
+       free(b1);
+       free(b2);
+       return ok;
+}
+
+static void lzo_check(uint32_t FAST_FUNC (*fn)(uint32_t, const uint8_t*, unsigned),
+               uint32_t ref, uint32_t init,
+               uint8_t* buf, unsigned len)
+{
+       uint32_t c = fn(init, buf, len);
+       if (c != ref)
+               bb_error_msg_and_die("checksum error");
+}
+
+/**********************************************************************/
+// decompress a file
+/**********************************************************************/
+static smallint lzo_decompress(const header_t *h)
+{
+       unsigned block_size = LZO_BLOCK_SIZE;
+       int r;
+       uint32_t src_len, dst_len;
+       uint32_t c_adler32 = ADLER32_INIT_VALUE;
+       uint32_t d_adler32 = ADLER32_INIT_VALUE;
+       uint32_t c_crc32 = CRC32_INIT_VALUE, d_crc32 = CRC32_INIT_VALUE;
+       smallint ok = 1;
+       uint8_t *b1;
+       uint32_t mcs_block_size = MAX_COMPRESSED_SIZE(block_size);
+       uint8_t *b2 = NULL;
+
+       for (;;) {
+               uint8_t *dst;
+
+               /* read uncompressed block size */
+               dst_len = read32();
+
+               /* exit if last block */
+               if (dst_len == 0)
+                       break;
+
+               /* error if split file */
+               if (dst_len == 0xffffffffL)
+                       /* should not happen - not yet implemented */
+                       bb_error_msg_and_die("this file is a split lzop file");
+
+               if (dst_len > MAX_BLOCK_SIZE)
+                       bb_error_msg_and_die("lzop file corrupted");
+
+               /* read compressed block size */
+               src_len = read32();
+               if (src_len <= 0 || src_len > dst_len)
+                       bb_error_msg_and_die("lzop file corrupted");
+
+               if (dst_len > block_size) {
+                       if (b2) {
+//FIXME!
+                               b2 = NULL;
+                               free(b2);
+                       }
+                       block_size = dst_len;
+                       mcs_block_size = MAX_COMPRESSED_SIZE(block_size);
+               }
+
+               /* read checksum of uncompressed block */
+               if (h->flags & F_ADLER32_D)
+                       d_adler32 = read32();
+               if (h->flags & F_CRC32_D)
+                       d_crc32 = read32();
+
+               /* read checksum of compressed block */
+               if (src_len < dst_len) {
+                       if (h->flags & F_ADLER32_C)
+                               c_adler32 = read32();
+                       if (h->flags & F_CRC32_C)
+                               c_crc32 = read32();
+               }
+
+               if (b2 == NULL)
+                       b2 = xzalloc(mcs_block_size);
+               /* read the block into the end of our buffer */
+               b1 = b2 + mcs_block_size - src_len;
+               xread(0, b1, src_len);
+
+               if (src_len < dst_len) {
+                       unsigned d = dst_len;
+
+                       if (!(option_mask32 & OPT_F)) {
+                               /* verify checksum of compressed block */
+                               if (h->flags & F_ADLER32_C)
+                                       lzo_check(lzo_adler32, c_adler32,
+                                                       ADLER32_INIT_VALUE,
+                                                       b1, src_len);
+                               if (h->flags & F_CRC32_C)
+                                       lzo_check(lzo_crc32, c_crc32,
+                                                       CRC32_INIT_VALUE,
+                                                       b1, src_len);
+                       }
+
+                       /* decompress */
+//                     if (option_mask32 & OPT_F)
+//                             r = lzo1x_decompress(b1, src_len, b2, &d, NULL);
+//                     else
+                               r = lzo1x_decompress_safe(b1, src_len, b2, &d, NULL);
+
+                       if (r != 0 /*LZO_E_OK*/ || dst_len != d) {
+                               bb_error_msg_and_die("corrupted compressed data");
+                       }
+                       dst = b2;
+               } else {
+                       /* "stored" block => no decompression */
+                       dst = b1;
+               }
+
+               if (!(option_mask32 & OPT_F)) {
+                       /* verify checksum of uncompressed block */
+                       if (h->flags & F_ADLER32_D)
+                               lzo_check(lzo_adler32, d_adler32, ADLER32_INIT_VALUE,
+                                         dst, dst_len);
+                       if (h->flags & F_CRC32_D)
+                               lzo_check(lzo_crc32, d_crc32, CRC32_INIT_VALUE,
+                                         dst, dst_len);
+               }
+
+               /* write uncompressed block data */
+               xwrite(1, dst, dst_len);
+       }
+
+       free(b2);
+       return ok;
+}
+
+/**********************************************************************/
+// lzop file signature (shamelessly borrowed from PNG)
+/**********************************************************************/
+/*
+ * The first nine bytes of a lzop file always contain the following values:
+ *
+ *                                 0   1   2   3   4   5   6   7   8
+ *                               --- --- --- --- --- --- --- --- ---
+ * (hex)                          89  4c  5a  4f  00  0d  0a  1a  0a
+ * (decimal)                     137  76  90  79   0  13  10  26  10
+ * (C notation - ASCII)         \211   L   Z   O  \0  \r  \n \032 \n
+ */
+
+/* (vda) comparison with lzop v1.02rc1 ("lzop -1 <FILE" cmd):
+ * Only slight differences in header:
+ * -00000000  89 4c 5a 4f 00 0d 0a 1a 0a 10 20 20 20 09 40 02
+ * +00000000  89 4c 5a 4f 00 0d 0a 1a 0a 10 10 20 30 09 40 02
+ *                                       ^^^^^ ^^^^^
+ *                                     version lib_version
+ * -00000010  01 03 00 00 0d 00 00 81 a4 49 f7 a6 3f 00 00 00
+ * +00000010  01 03 00 00 01 00 00 00 00 00 00 00 00 00 00 00
+ *               ^^^^^^^^^^^ ^^^^^^^^^^^ ^^^^^^^^^^^
+ *               flags       mode        mtime
+ * -00000020  00 00 2d 67 04 17 00 04 00 00 00 03 ed ec 9d 6d
+ * +00000020  00 00 10 5f 00 c1 00 04 00 00 00 03 ed ec 9d 6d
+ *                  ^^^^^^^^^^^
+ *                  chksum_out
+ * The rest is identical.
+*/
+static const unsigned char lzop_magic[9] = {
+       0x89, 0x4c, 0x5a, 0x4f, 0x00, 0x0d, 0x0a, 0x1a, 0x0a
+};
+
+/* This coding is derived from Alexander Lehmann's pngcheck code. */
+static void check_magic(void)
+{
+       unsigned char magic[sizeof(lzop_magic)];        
+       xread(0, magic, sizeof(magic));
+       if (memcmp(magic, lzop_magic, sizeof(lzop_magic)) != 0)
+               bb_error_msg_and_die("bad magic number");
+}
+
+/**********************************************************************/
+// lzop file header
+/**********************************************************************/
+static void write_header(const header_t *h)
+{
+       int l;
+
+       xwrite(1, lzop_magic, sizeof(lzop_magic));
+
+       init_chksum(&G.chksum_out);
+
+       f_write16(h->version);
+       f_write16(h->lib_version);
+       f_write16(h->version_needed_to_extract);
+       f_write8(h->method);
+       f_write8(h->level);
+       f_write32(h->flags);
+       f_write32(h->mode);
+       f_write32(h->mtime);
+       f_write32(h->gmtdiff);
+
+       l = (int) strlen(h->name);
+       f_write8(l);
+       if (l)
+               f_write(h->name, l);
+
+       f_write32(chksum_getresult(&G.chksum_out, h));
+}
+
+static int read_header(header_t *h)
+{
+       int r;
+       int l;
+       uint32_t checksum;
+
+       memset(h, 0, sizeof(*h));
+       h->version_needed_to_extract = 0x0900;  /* first lzop version */
+       h->level = 0;
+
+       init_chksum(&G.chksum_in);
+
+       h->version = f_read16();
+       if (h->version < 0x0900)
+               return 3;
+       h->lib_version = f_read16();
+       if (h->version >= 0x0940) {
+               h->version_needed_to_extract = f_read16();
+               if (h->version_needed_to_extract > LZOP_VERSION)
+                       return 16;
+               if (h->version_needed_to_extract < 0x0900)
+                       return 3;
+       }
+       h->method = f_read8();
+       if (h->version >= 0x0940)
+               h->level = f_read8();
+       h->flags = f_read32();
+       if (h->flags & F_H_FILTER)
+               return 16; /* filter not supported */
+       h->mode = f_read32();
+       h->mtime = f_read32();
+       if (h->version >= 0x0940)
+               h->gmtdiff = f_read32();
+
+       l = f_read8();
+       if (l > 0)
+               f_read(h->name, l);
+       h->name[l] = 0;
+
+       checksum = chksum_getresult(&G.chksum_in, h);
+       h->header_checksum = f_read32();
+       if (h->header_checksum != checksum)
+               return 2;
+
+       if (h->method <= 0)
+               return 14;
+       r = lzo_get_method(h);
+       if (r != 0)
+               return r;
+
+       /* check reserved flags */
+       if (h->flags & F_RESERVED)
+               return -13;
+
+       /* skip extra field [not used yet] */
+       if (h->flags & F_H_EXTRA_FIELD) {
+               uint32_t k;
+               
+               /* note: the checksum also covers the length */
+               init_chksum(&G.chksum_in);
+               h->extra_field_len = f_read32();
+               for (k = 0; k < h->extra_field_len; k++)
+                       f_read8();
+               checksum = chksum_getresult(&G.chksum_in, h);
+               h->extra_field_checksum = f_read32();
+               if (h->extra_field_checksum != checksum)
+                       return 3;
+       }
+
+       return 0;
+}
+
+static void p_header(header_t *h)
+{
+       int r;
+
+       r = read_header(h);
+       if (r == 0)
+               return;
+       bb_error_msg_and_die("header_error %d", r);
+}
+
+/**********************************************************************/
+// compress
+/**********************************************************************/
+static void lzo_set_method(header_t *h)
+{
+       int level = 1;
+
+       if (option_mask32 & OPT_1) {
+               h->method = M_LZO1X_1_15;
+       } else if (option_mask32 & OPT_789) {
+#if ENABLE_LZOP_COMPR_HIGH
+               h->method = M_LZO1X_999;
+               if (option_mask32 & OPT_7)
+                       level = 7;
+               else if (option_mask32 & OPT_8)
+                       level = 8;
+               else
+                       level = 9;
+#else
+               bb_error_msg_and_die("high compression not compiled in");
+#endif
+       } else { /* levels 2..6 or none (defaults to level 3) */
+               h->method = M_LZO1X_1;
+               level = 5; /* levels 2-6 are actually the same */
+       }
+
+       h->level = level;
+}
+
+static smallint do_lzo_compress(void)
+{
+       header_t header;
+
+#define h (&header)
+       memset(h, 0, sizeof(*h));
+
+       lzo_set_method(h);
+
+       h->version = (LZOP_VERSION & 0xffff);
+       h->version_needed_to_extract = 0x0940;
+       h->lib_version = lzo_version() & 0xffff;
+
+       h->flags = (F_OS & F_OS_MASK) | (F_CS & F_CS_MASK);
+
+       if (!(option_mask32 & OPT_F) || h->method == M_LZO1X_999) {
+               h->flags |= F_ADLER32_D;
+               if (option_mask32 & OPT_C)
+                       h->flags |= F_ADLER32_C;
+       }
+       write_header(h);
+       return lzo_compress(h);
+#undef h
+}
+
+/**********************************************************************/
+// decompress
+/**********************************************************************/
+static smallint do_lzo_decompress(void)
+{
+       header_t header;
+       
+       check_magic();
+       p_header(&header);
+       return lzo_decompress(&header);
+}
+
+static char* make_new_name_lzop(char *filename)
+{
+       if (option_mask32 & OPT_DECOMPRESS) {
+               char *extension = strrchr(filename, '.');
+               if (!extension || strcmp(extension + 1, "lzo") != 0)
+                       return xasprintf("%s.out", filename);
+               *extension = '\0';
+               return filename;
+       }
+       return xasprintf("%s.lzo", filename);
+}
+
+static IF_DESKTOP(long long) int pack_lzop(unpack_info_t *info UNUSED_PARAM)
+{
+       if (option_mask32 & OPT_DECOMPRESS)
+               return do_lzo_decompress();
+       return do_lzo_compress();
+}
+
+int lzop_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int lzop_main(int argc UNUSED_PARAM, char **argv)
+{
+       getopt32(argv, OPTION_STRING);
+       argv += optind;
+       /* lzopcat? */
+       if (applet_name[4] == 'c')
+               option_mask32 |= (OPT_STDOUT | OPT_DECOMPRESS);
+       /* unlzop? */
+       if (applet_name[0] == 'u')
+               option_mask32 |= OPT_DECOMPRESS;
+
+       G.lzo_crc32_table = crc32_filltable(NULL, 0);
+       return bbunpack(argv, make_new_name_lzop, pack_lzop);
+}
index a41f75e311957ed9b93491eef18f8e1ffd1054f9..359440def6ed761a2b0e48a52ae4305dd08ea0bc 100644 (file)
@@ -242,6 +242,8 @@ IF_LSATTR(APPLET(lsattr, _BB_DIR_BIN, _BB_SUID_NEVER))
 IF_LSMOD(APPLET(lsmod, _BB_DIR_SBIN, _BB_SUID_NEVER))
 IF_MODPROBE_SMALL(APPLET_ODDNAME(lsmod, modprobe, _BB_DIR_SBIN, _BB_SUID_NEVER, modprobe))
 IF_UNLZMA(APPLET_ODDNAME(lzmacat, unlzma, _BB_DIR_USR_BIN, _BB_SUID_NEVER, lzmacat))
+IF_LZOP(APPLET(lzop, _BB_DIR_BIN, _BB_SUID_NEVER))
+IF_LZOP(APPLET_ODDNAME(lzopcat, lzop, _BB_DIR_USR_BIN, _BB_SUID_NEVER, lzopcat))
 IF_MAKEDEVS(APPLET(makedevs, _BB_DIR_SBIN, _BB_SUID_NEVER))
 IF_MAKEMIME(APPLET(makemime, _BB_DIR_BIN, _BB_SUID_NEVER))
 IF_MAN(APPLET(man, _BB_DIR_SBIN, _BB_SUID_NEVER))
@@ -401,6 +403,7 @@ IF_UNEXPAND(APPLET_ODDNAME(unexpand, expand, _BB_DIR_USR_BIN, _BB_SUID_NEVER, un
 IF_UNIQ(APPLET(uniq, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
 IF_UNIX2DOS(APPLET_ODDNAME(unix2dos, dos2unix, _BB_DIR_USR_BIN, _BB_SUID_NEVER, unix2dos))
 IF_UNLZMA(APPLET(unlzma, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
+IF_LZOP(APPLET_ODDNAME(unlzop, lzop, _BB_DIR_USR_BIN, _BB_SUID_NEVER, unlzop))
 IF_UNZIP(APPLET(unzip, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
 IF_UPTIME(APPLET(uptime, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
 IF_USLEEP(APPLET_NOFORK(usleep, usleep, _BB_DIR_BIN, _BB_SUID_NEVER, usleep))
index 3fb9961267e46a8b9449151de4928282a28be674..123462a0275b2e3f72bf9a2eec31f7d141525a69 100644 (file)
 #define busybox_notes_usage \
        "Hello world!\n"
 
+#define lzop_trivial_usage \
+       "[-cfvd123456789CF] [file..]"
+#define lzop_full_usage "\n\n" \
+       "       -c      Write to standard output" \
+     "\n       -f      Force" \
+     "\n       -v      Verbose" \
+     "\n       -d      Decompress" \
+     "\n       -F      Don't store or verify checksum" \
+     "\n       -C      Also write checksum of compressed block" \
+     "\n       -1..9   Compression level" \
+
+#define lzopcat_trivial_usage \
+       "[-vCF] [file..]"
+#define lzopcat_full_usage "\n\n" \
+       "       -v      Verbose" \
+     "\n       -F      Don't store or verify checksum" \
+
+#define unlzop_trivial_usage \
+       "[-cfvCF] [file..]"
+#define unlzop_full_usage "\n\n" \
+       "       -c      Write to standard output" \
+     "\n       -f      Force" \
+     "\n       -v      Verbose" \
+     "\n       -F      Don't store or verify checksum" \
+
 #define bzcat_trivial_usage \
        "FILE"
 #define bzcat_full_usage "\n\n" \