diff options
author | Denis Vlasenko <vda.linux@googlemail.com> | 2009-04-29 12:01:51 +0000 |
---|---|---|
committer | Denis Vlasenko <vda.linux@googlemail.com> | 2009-04-29 12:01:51 +0000 |
commit | 052ad9a56883a56742cec1afc6c1c8dfff222495 (patch) | |
tree | c06321623bd51c725b559f3e91d1a9b736a26646 | |
parent | c8653f62f2203d0377933c1b5f0442666e27f91a (diff) | |
download | busybox-w32-052ad9a56883a56742cec1afc6c1c8dfff222495.tar.gz busybox-w32-052ad9a56883a56742cec1afc6c1c8dfff222495.tar.bz2 busybox-w32-052ad9a56883a56742cec1afc6c1c8dfff222495.zip |
lzop: new applet. Busyboxed by Alain Knaff. +7700 bytes.
-rw-r--r-- | archival/Config.in | 15 | ||||
-rw-r--r-- | archival/Kbuild | 2 | ||||
-rw-r--r-- | archival/liblzo.h | 93 | ||||
-rw-r--r-- | archival/liblzo_interface.h | 71 | ||||
-rw-r--r-- | archival/lzo1x_1.c | 35 | ||||
-rw-r--r-- | archival/lzo1x_1o.c | 35 | ||||
-rw-r--r-- | archival/lzo1x_9x.c | 920 | ||||
-rw-r--r-- | archival/lzo1x_c.c | 296 | ||||
-rw-r--r-- | archival/lzo1x_d.c | 420 | ||||
-rw-r--r-- | archival/lzop.c | 1075 | ||||
-rw-r--r-- | include/applets.h | 3 | ||||
-rw-r--r-- | include/usage.h | 25 |
12 files changed, 2990 insertions, 0 deletions
diff --git a/archival/Config.in b/archival/Config.in index e0d43c0ee..a983e4433 100644 --- a/archival/Config.in +++ b/archival/Config.in | |||
@@ -165,6 +165,21 @@ config GZIP | |||
165 | gzip is used to compress files. | 165 | gzip is used to compress files. |
166 | It's probably the most widely used UNIX compression program. | 166 | It's probably the most widely used UNIX compression program. |
167 | 167 | ||
168 | config LZOP | ||
169 | bool "lzop" | ||
170 | default n | ||
171 | help | ||
172 | Lzop compression/decompresion. | ||
173 | |||
174 | config LZOP_COMPR_HIGH | ||
175 | bool "lzop complession levels 7,8,9 (not very useful)" | ||
176 | default n | ||
177 | depends on LZOP | ||
178 | help | ||
179 | High levels (7,8,9) of lzop compression. These levels | ||
180 | are actually slower than gzip at equivalent compression ratios | ||
181 | and take up 3.2K of code. | ||
182 | |||
168 | config RPM2CPIO | 183 | config RPM2CPIO |
169 | bool "rpm2cpio" | 184 | bool "rpm2cpio" |
170 | default n | 185 | default n |
diff --git a/archival/Kbuild b/archival/Kbuild index 72dbdda0e..de0ca4315 100644 --- a/archival/Kbuild +++ b/archival/Kbuild | |||
@@ -16,6 +16,8 @@ lib-$(CONFIG_DPKG) += dpkg.o | |||
16 | lib-$(CONFIG_DPKG_DEB) += dpkg_deb.o | 16 | lib-$(CONFIG_DPKG_DEB) += dpkg_deb.o |
17 | lib-$(CONFIG_GUNZIP) += bbunzip.o | 17 | lib-$(CONFIG_GUNZIP) += bbunzip.o |
18 | lib-$(CONFIG_GZIP) += gzip.o bbunzip.o | 18 | lib-$(CONFIG_GZIP) += gzip.o bbunzip.o |
19 | lib-$(CONFIG_LZOP) += lzop.o lzo1x_1.o lzo1x_1o.o lzo1x_d.o | ||
20 | lib-$(CONFIG_LZOP_COMPR_HIGH) += lzo1x_9x.o | ||
19 | lib-$(CONFIG_RPM2CPIO) += rpm2cpio.o | 21 | lib-$(CONFIG_RPM2CPIO) += rpm2cpio.o |
20 | lib-$(CONFIG_RPM) += rpm.o | 22 | lib-$(CONFIG_RPM) += rpm.o |
21 | lib-$(CONFIG_TAR) += tar.o | 23 | lib-$(CONFIG_TAR) += tar.o |
diff --git a/archival/liblzo.h b/archival/liblzo.h new file mode 100644 index 000000000..843997cb9 --- /dev/null +++ b/archival/liblzo.h | |||
@@ -0,0 +1,93 @@ | |||
1 | /* | ||
2 | This file is part of the LZO real-time data compression library. | ||
3 | |||
4 | Copyright (C) 1996..2008 Markus Franz Xaver Johannes Oberhumer | ||
5 | All Rights Reserved. | ||
6 | |||
7 | Markus F.X.J. Oberhumer <markus@oberhumer.com> | ||
8 | http://www.oberhumer.com/opensource/lzo/ | ||
9 | |||
10 | The LZO library is free software; you can redistribute it and/or | ||
11 | modify it under the terms of the GNU General Public License as | ||
12 | published by the Free Software Foundation; either version 2 of | ||
13 | the License, or (at your option) any later version. | ||
14 | |||
15 | The LZO library is distributed in the hope that it will be useful, | ||
16 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
17 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
18 | GNU General Public License for more details. | ||
19 | |||
20 | You should have received a copy of the GNU General Public License | ||
21 | along with the LZO library; see the file COPYING. | ||
22 | If not, write to the Free Software Foundation, Inc., | ||
23 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | ||
24 | */ | ||
25 | |||
26 | #include "liblzo_interface.h" | ||
27 | |||
28 | /* lzo-2.03/src/config1x.h */ | ||
29 | #define M2_MIN_LEN 3 | ||
30 | #define M2_MAX_LEN 8 | ||
31 | #define M3_MAX_LEN 33 | ||
32 | #define M4_MAX_LEN 9 | ||
33 | #define M1_MAX_OFFSET 0x0400 | ||
34 | #define M2_MAX_OFFSET 0x0800 | ||
35 | #define M3_MAX_OFFSET 0x4000 | ||
36 | #define M4_MAX_OFFSET 0xbfff | ||
37 | #define M1_MARKER 0 | ||
38 | #define M3_MARKER 32 | ||
39 | #define M4_MARKER 16 | ||
40 | |||
41 | #define MX_MAX_OFFSET (M1_MAX_OFFSET + M2_MAX_OFFSET) | ||
42 | #define MIN_LOOKAHEAD (M2_MAX_LEN + 1) | ||
43 | |||
44 | #define LZO_EOF_CODE | ||
45 | |||
46 | /* lzo-2.03/src/lzo_dict.h */ | ||
47 | #define GINDEX(m_pos,m_off,dict,dindex,in) m_pos = dict[dindex] | ||
48 | #define DX2(p,s1,s2) \ | ||
49 | (((((unsigned)((p)[2]) << (s2)) ^ (p)[1]) << (s1)) ^ (p)[0]) | ||
50 | //#define DA3(p,s1,s2,s3) ((DA2((p)+1,s2,s3) << (s1)) + (p)[0]) | ||
51 | //#define DS3(p,s1,s2,s3) ((DS2((p)+1,s2,s3) << (s1)) - (p)[0]) | ||
52 | #define DX3(p,s1,s2,s3) ((DX2((p)+1,s2,s3) << (s1)) ^ (p)[0]) | ||
53 | |||
54 | #define D_SIZE (1U << D_BITS) | ||
55 | #define D_MASK ((1U << D_BITS) - 1) | ||
56 | #define D_HIGH ((D_MASK >> 1) + 1) | ||
57 | |||
58 | #define LZO_CHECK_MPOS_NON_DET(m_pos,m_off,in,ip,max_offset) \ | ||
59 | ( \ | ||
60 | m_pos = ip - (unsigned)(ip - m_pos), \ | ||
61 | ((uintptr_t)m_pos < (uintptr_t)in \ | ||
62 | || (m_off = (unsigned)(ip - m_pos)) <= 0 \ | ||
63 | || m_off > max_offset) \ | ||
64 | ) | ||
65 | |||
66 | #define DENTRY(p,in) (p) | ||
67 | #define UPDATE_I(dict,drun,index,p,in) dict[index] = DENTRY(p,in) | ||
68 | |||
69 | #define DMS(v,s) ((unsigned) (((v) & (D_MASK >> (s))) << (s))) | ||
70 | #define DM(v) ((unsigned) ((v) & D_MASK)) | ||
71 | #define DMUL(a,b) ((unsigned) ((a) * (b))) | ||
72 | |||
73 | /* lzo-2.03/src/lzo_ptr.h */ | ||
74 | #define pd(a,b) ((unsigned)((a)-(b))) | ||
75 | |||
76 | # define TEST_IP (ip < ip_end) | ||
77 | # define NEED_IP(x) \ | ||
78 | if ((unsigned)(ip_end - ip) < (unsigned)(x)) goto input_overrun | ||
79 | |||
80 | # undef TEST_OP /* don't need both of the tests here */ | ||
81 | # define TEST_OP 1 | ||
82 | # define NEED_OP(x) \ | ||
83 | if ((unsigned)(op_end - op) < (unsigned)(x)) goto output_overrun | ||
84 | |||
85 | #define HAVE_ANY_OP 1 | ||
86 | |||
87 | //#if defined(LZO_TEST_OVERRUN_LOOKBEHIND) | ||
88 | # define TEST_LB(m_pos) if (m_pos < out || m_pos >= op) goto lookbehind_overrun | ||
89 | //# define TEST_LBO(m_pos,o) if (m_pos < out || m_pos >= op - (o)) goto lookbehind_overrun | ||
90 | //#else | ||
91 | //# define TEST_LB(m_pos) ((void) 0) | ||
92 | //# define TEST_LBO(m_pos,o) ((void) 0) | ||
93 | //#endif | ||
diff --git a/archival/liblzo_interface.h b/archival/liblzo_interface.h new file mode 100644 index 000000000..9a84c0b6b --- /dev/null +++ b/archival/liblzo_interface.h | |||
@@ -0,0 +1,71 @@ | |||
1 | /* | ||
2 | This file is part of the LZO real-time data compression library. | ||
3 | |||
4 | Copyright (C) 1996..2008 Markus Franz Xaver Johannes Oberhumer | ||
5 | All Rights Reserved. | ||
6 | |||
7 | Markus F.X.J. Oberhumer <markus@oberhumer.com> | ||
8 | http://www.oberhumer.com/opensource/lzo/ | ||
9 | |||
10 | The LZO library is free software; you can redistribute it and/or | ||
11 | modify it under the terms of the GNU General Public License as | ||
12 | published by the Free Software Foundation; either version 2 of | ||
13 | the License, or (at your option) any later version. | ||
14 | |||
15 | The LZO library is distributed in the hope that it will be useful, | ||
16 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
17 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
18 | GNU General Public License for more details. | ||
19 | |||
20 | You should have received a copy of the GNU General Public License | ||
21 | along with the LZO library; see the file COPYING. | ||
22 | If not, write to the Free Software Foundation, Inc., | ||
23 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | ||
24 | */ | ||
25 | |||
26 | #define LZO1X | ||
27 | #undef LZO1Y | ||
28 | |||
29 | #undef assert | ||
30 | /* | ||
31 | static void die_at(int line) | ||
32 | { | ||
33 | bb_error_msg_and_die("internal error at %d", line); | ||
34 | } | ||
35 | #define assert(v) if (!(v)) die_at(__LINE__) | ||
36 | */ | ||
37 | #define assert(v) ((void)0) | ||
38 | |||
39 | int lzo1x_1_compress(const uint8_t* src, unsigned src_len, | ||
40 | uint8_t* dst, unsigned* dst_len, | ||
41 | void* wrkmem); | ||
42 | int lzo1x_1_15_compress(const uint8_t* src, unsigned src_len, | ||
43 | uint8_t* dst, unsigned* dst_len, | ||
44 | void* wrkmem); | ||
45 | int lzo1x_999_compress_level(const uint8_t* in, unsigned in_len, | ||
46 | uint8_t* out, unsigned* out_len, | ||
47 | void* wrkmem, | ||
48 | int compression_level); | ||
49 | |||
50 | /* decompression */ | ||
51 | //int lzo1x_decompress(const uint8_t* src, unsigned src_len, | ||
52 | // uint8_t* dst, unsigned* dst_len, | ||
53 | // void* wrkmem /* NOT USED */); | ||
54 | /* safe decompression with overrun testing */ | ||
55 | int lzo1x_decompress_safe(const uint8_t* src, unsigned src_len, | ||
56 | uint8_t* dst, unsigned* dst_len, | ||
57 | void* wrkmem /* NOT USED */); | ||
58 | |||
59 | #define LZO_E_OK 0 | ||
60 | #define LZO_E_ERROR (-1) | ||
61 | #define LZO_E_OUT_OF_MEMORY (-2) /* [not used right now] */ | ||
62 | #define LZO_E_NOT_COMPRESSIBLE (-3) /* [not used right now] */ | ||
63 | #define LZO_E_INPUT_OVERRUN (-4) | ||
64 | #define LZO_E_OUTPUT_OVERRUN (-5) | ||
65 | #define LZO_E_LOOKBEHIND_OVERRUN (-6) | ||
66 | #define LZO_E_EOF_NOT_FOUND (-7) | ||
67 | #define LZO_E_INPUT_NOT_CONSUMED (-8) | ||
68 | #define LZO_E_NOT_YET_IMPLEMENTED (-9) /* [not used right now] */ | ||
69 | |||
70 | /* lzo-2.03/include/lzo/lzoconf.h */ | ||
71 | #define LZO_VERSION 0x2030 | ||
diff --git a/archival/lzo1x_1.c b/archival/lzo1x_1.c new file mode 100644 index 000000000..a88839846 --- /dev/null +++ b/archival/lzo1x_1.c | |||
@@ -0,0 +1,35 @@ | |||
1 | /* LZO1X-1 compression | ||
2 | |||
3 | This file is part of the LZO real-time data compression library. | ||
4 | |||
5 | Copyright (C) 1996..2008 Markus Franz Xaver Johannes Oberhumer | ||
6 | All Rights Reserved. | ||
7 | |||
8 | Markus F.X.J. Oberhumer <markus@oberhumer.com> | ||
9 | http://www.oberhumer.com/opensource/lzo/ | ||
10 | |||
11 | The LZO library is free software; you can redistribute it and/or | ||
12 | modify it under the terms of the GNU General Public License as | ||
13 | published by the Free Software Foundation; either version 2 of | ||
14 | the License, or (at your option) any later version. | ||
15 | |||
16 | The LZO library is distributed in the hope that it will be useful, | ||
17 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
18 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
19 | GNU General Public License for more details. | ||
20 | |||
21 | You should have received a copy of the GNU General Public License | ||
22 | along with the LZO library; see the file COPYING. | ||
23 | If not, write to the Free Software Foundation, Inc., | ||
24 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | ||
25 | */ | ||
26 | #include "libbb.h" | ||
27 | #include "liblzo.h" | ||
28 | |||
29 | #define D_BITS 14 | ||
30 | #define D_INDEX1(d,p) d = DM(DMUL(0x21,DX3(p,5,5,6)) >> 5) | ||
31 | #define D_INDEX2(d,p) d = (d & (D_MASK & 0x7ff)) ^ (D_HIGH | 0x1f) | ||
32 | |||
33 | #define DO_COMPRESS lzo1x_1_compress | ||
34 | |||
35 | #include "lzo1x_c.c" | ||
diff --git a/archival/lzo1x_1o.c b/archival/lzo1x_1o.c new file mode 100644 index 000000000..3c61253e0 --- /dev/null +++ b/archival/lzo1x_1o.c | |||
@@ -0,0 +1,35 @@ | |||
1 | /* LZO1X-1(15) compression | ||
2 | |||
3 | This file is part of the LZO real-time data compression library. | ||
4 | |||
5 | Copyright (C) 1996..2008 Markus Franz Xaver Johannes Oberhumer | ||
6 | All Rights Reserved. | ||
7 | |||
8 | Markus F.X.J. Oberhumer <markus@oberhumer.com> | ||
9 | http://www.oberhumer.com/opensource/lzo/ | ||
10 | |||
11 | The LZO library is free software; you can redistribute it and/or | ||
12 | modify it under the terms of the GNU General Public License as | ||
13 | published by the Free Software Foundation; either version 2 of | ||
14 | the License, or (at your option) any later version. | ||
15 | |||
16 | The LZO library is distributed in the hope that it will be useful, | ||
17 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
18 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
19 | GNU General Public License for more details. | ||
20 | |||
21 | You should have received a copy of the GNU General Public License | ||
22 | along with the LZO library; see the file COPYING. | ||
23 | If not, write to the Free Software Foundation, Inc., | ||
24 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | ||
25 | */ | ||
26 | #include "libbb.h" | ||
27 | #include "liblzo.h" | ||
28 | |||
29 | #define D_BITS 15 | ||
30 | #define D_INDEX1(d,p) d = DM(DMUL(0x21,DX3(p,5,5,6)) >> 5) | ||
31 | #define D_INDEX2(d,p) d = (d & (D_MASK & 0x7ff)) ^ (D_HIGH | 0x1f) | ||
32 | |||
33 | #define DO_COMPRESS lzo1x_1_15_compress | ||
34 | |||
35 | #include "lzo1x_c.c" | ||
diff --git a/archival/lzo1x_9x.c b/archival/lzo1x_9x.c new file mode 100644 index 000000000..d30e2e7d1 --- /dev/null +++ b/archival/lzo1x_9x.c | |||
@@ -0,0 +1,920 @@ | |||
1 | /* lzo1x_9x.c -- implementation of the LZO1X-999 compression algorithm | ||
2 | |||
3 | This file is part of the LZO real-time data compression library. | ||
4 | |||
5 | Copyright (C) 2008 Markus Franz Xaver Johannes Oberhumer | ||
6 | Copyright (C) 2007 Markus Franz Xaver Johannes Oberhumer | ||
7 | Copyright (C) 2006 Markus Franz Xaver Johannes Oberhumer | ||
8 | Copyright (C) 2005 Markus Franz Xaver Johannes Oberhumer | ||
9 | Copyright (C) 2004 Markus Franz Xaver Johannes Oberhumer | ||
10 | Copyright (C) 2003 Markus Franz Xaver Johannes Oberhumer | ||
11 | Copyright (C) 2002 Markus Franz Xaver Johannes Oberhumer | ||
12 | Copyright (C) 2001 Markus Franz Xaver Johannes Oberhumer | ||
13 | Copyright (C) 2000 Markus Franz Xaver Johannes Oberhumer | ||
14 | Copyright (C) 1999 Markus Franz Xaver Johannes Oberhumer | ||
15 | Copyright (C) 1998 Markus Franz Xaver Johannes Oberhumer | ||
16 | Copyright (C) 1997 Markus Franz Xaver Johannes Oberhumer | ||
17 | Copyright (C) 1996 Markus Franz Xaver Johannes Oberhumer | ||
18 | All Rights Reserved. | ||
19 | |||
20 | The LZO library is free software; you can redistribute it and/or | ||
21 | modify it under the terms of the GNU General Public License as | ||
22 | published by the Free Software Foundation; either version 2 of | ||
23 | the License, or (at your option) any later version. | ||
24 | |||
25 | The LZO library is distributed in the hope that it will be useful, | ||
26 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
27 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
28 | GNU General Public License for more details. | ||
29 | |||
30 | You should have received a copy of the GNU General Public License | ||
31 | along with the LZO library; see the file COPYING. | ||
32 | If not, write to the Free Software Foundation, Inc., | ||
33 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | ||
34 | |||
35 | Markus F.X.J. Oberhumer | ||
36 | <markus@oberhumer.com> | ||
37 | http://www.oberhumer.com/opensource/lzo/ | ||
38 | */ | ||
39 | #include "libbb.h" | ||
40 | |||
41 | /* The following is probably only safe on Intel-compatible processors ... */ | ||
42 | #define LZO_UNALIGNED_OK_2 | ||
43 | #define LZO_UNALIGNED_OK_4 | ||
44 | |||
45 | #include "liblzo.h" | ||
46 | |||
47 | #define LZO_MAX(a,b) ((a) >= (b) ? (a) : (b)) | ||
48 | #define LZO_MIN(a,b) ((a) <= (b) ? (a) : (b)) | ||
49 | #define LZO_MAX3(a,b,c) ((a) >= (b) ? LZO_MAX(a,c) : LZO_MAX(b,c)) | ||
50 | |||
51 | /*********************************************************************** | ||
52 | // | ||
53 | ************************************************************************/ | ||
54 | #define SWD_N M4_MAX_OFFSET /* size of ring buffer */ | ||
55 | #define SWD_F 2048 /* upper limit for match length */ | ||
56 | |||
57 | #define SWD_BEST_OFF (LZO_MAX3(M2_MAX_LEN, M3_MAX_LEN, M4_MAX_LEN) + 1) | ||
58 | |||
59 | typedef struct { | ||
60 | int init; | ||
61 | |||
62 | unsigned look; /* bytes in lookahead buffer */ | ||
63 | |||
64 | unsigned m_len; | ||
65 | unsigned m_off; | ||
66 | |||
67 | const uint8_t *bp; | ||
68 | const uint8_t *ip; | ||
69 | const uint8_t *in; | ||
70 | const uint8_t *in_end; | ||
71 | uint8_t *out; | ||
72 | |||
73 | unsigned r1_lit; | ||
74 | |||
75 | } lzo1x_999_t; | ||
76 | |||
77 | #define getbyte(c) ((c).ip < (c).in_end ? *((c).ip)++ : (-1)) | ||
78 | |||
79 | /* lzo_swd.c -- sliding window dictionary */ | ||
80 | |||
81 | /*********************************************************************** | ||
82 | // | ||
83 | ************************************************************************/ | ||
84 | #define SWD_UINT_MAX USHRT_MAX | ||
85 | |||
86 | #ifndef SWD_HSIZE | ||
87 | # define SWD_HSIZE 16384 | ||
88 | #endif | ||
89 | #ifndef SWD_MAX_CHAIN | ||
90 | # define SWD_MAX_CHAIN 2048 | ||
91 | #endif | ||
92 | |||
93 | #define HEAD3(b, p) \ | ||
94 | ( ((0x9f5f * ((((b[p]<<5)^b[p+1])<<5) ^ b[p+2])) >> 5) & (SWD_HSIZE-1) ) | ||
95 | |||
96 | #if defined(LZO_UNALIGNED_OK_2) | ||
97 | # define HEAD2(b,p) (* (uint16_t *) &(b[p])) | ||
98 | #else | ||
99 | # define HEAD2(b,p) (b[p] ^ ((unsigned)b[p+1]<<8)) | ||
100 | #endif | ||
101 | #define NIL2 SWD_UINT_MAX | ||
102 | |||
103 | typedef struct lzo_swd { | ||
104 | /* public - "built-in" */ | ||
105 | |||
106 | /* public - configuration */ | ||
107 | unsigned max_chain; | ||
108 | int use_best_off; | ||
109 | |||
110 | /* public - output */ | ||
111 | unsigned m_len; | ||
112 | unsigned m_off; | ||
113 | unsigned look; | ||
114 | int b_char; | ||
115 | #if defined(SWD_BEST_OFF) | ||
116 | unsigned best_off[SWD_BEST_OFF]; | ||
117 | #endif | ||
118 | |||
119 | /* semi public */ | ||
120 | lzo1x_999_t *c; | ||
121 | unsigned m_pos; | ||
122 | #if defined(SWD_BEST_OFF) | ||
123 | unsigned best_pos[SWD_BEST_OFF]; | ||
124 | #endif | ||
125 | |||
126 | /* private */ | ||
127 | unsigned ip; /* input pointer (lookahead) */ | ||
128 | unsigned bp; /* buffer pointer */ | ||
129 | unsigned rp; /* remove pointer */ | ||
130 | |||
131 | unsigned node_count; | ||
132 | unsigned first_rp; | ||
133 | |||
134 | uint8_t b[SWD_N + SWD_F]; | ||
135 | uint8_t b_wrap[SWD_F]; /* must follow b */ | ||
136 | uint16_t head3[SWD_HSIZE]; | ||
137 | uint16_t succ3[SWD_N + SWD_F]; | ||
138 | uint16_t best3[SWD_N + SWD_F]; | ||
139 | uint16_t llen3[SWD_HSIZE]; | ||
140 | #ifdef HEAD2 | ||
141 | uint16_t head2[65536L]; | ||
142 | #endif | ||
143 | } lzo_swd_t, *lzo_swd_p; | ||
144 | |||
145 | #define SIZEOF_LZO_SWD_T (sizeof(lzo_swd_t)) | ||
146 | |||
147 | |||
148 | /* Access macro for head3. | ||
149 | * head3[key] may be uninitialized, but then its value will never be used. | ||
150 | */ | ||
151 | #define s_get_head3(s,key) s->head3[key] | ||
152 | |||
153 | |||
154 | /*********************************************************************** | ||
155 | // | ||
156 | ************************************************************************/ | ||
157 | #define B_SIZE (SWD_N + SWD_F) | ||
158 | |||
159 | static int swd_init(lzo_swd_p s) | ||
160 | { | ||
161 | /* defaults */ | ||
162 | s->node_count = SWD_N; | ||
163 | |||
164 | memset(s->llen3, 0, sizeof(s->llen3[0]) * (unsigned)SWD_HSIZE); | ||
165 | #ifdef HEAD2 | ||
166 | memset(s->head2, 0xff, sizeof(s->head2[0]) * 65536L); | ||
167 | assert(s->head2[0] == NIL2); | ||
168 | #endif | ||
169 | |||
170 | s->ip = 0; | ||
171 | s->bp = s->ip; | ||
172 | s->first_rp = s->ip; | ||
173 | |||
174 | assert(s->ip + SWD_F <= B_SIZE); | ||
175 | s->look = (unsigned) (s->c->in_end - s->c->ip); | ||
176 | if (s->look > 0) { | ||
177 | if (s->look > SWD_F) | ||
178 | s->look = SWD_F; | ||
179 | memcpy(&s->b[s->ip],s->c->ip,s->look); | ||
180 | s->c->ip += s->look; | ||
181 | s->ip += s->look; | ||
182 | } | ||
183 | if (s->ip == B_SIZE) | ||
184 | s->ip = 0; | ||
185 | |||
186 | s->rp = s->first_rp; | ||
187 | if (s->rp >= s->node_count) | ||
188 | s->rp -= s->node_count; | ||
189 | else | ||
190 | s->rp += B_SIZE - s->node_count; | ||
191 | |||
192 | return LZO_E_OK; | ||
193 | } | ||
194 | |||
195 | #define swd_pos2off(s,pos) \ | ||
196 | (s->bp > (pos) ? s->bp - (pos) : B_SIZE - ((pos) - s->bp)) | ||
197 | |||
198 | |||
199 | /*********************************************************************** | ||
200 | // | ||
201 | ************************************************************************/ | ||
202 | static void swd_getbyte(lzo_swd_p s) | ||
203 | { | ||
204 | int c; | ||
205 | |||
206 | if ((c = getbyte(*(s->c))) < 0) { | ||
207 | if (s->look > 0) | ||
208 | --s->look; | ||
209 | } else { | ||
210 | s->b[s->ip] = c; | ||
211 | if (s->ip < SWD_F) | ||
212 | s->b_wrap[s->ip] = c; | ||
213 | } | ||
214 | if (++s->ip == B_SIZE) | ||
215 | s->ip = 0; | ||
216 | if (++s->bp == B_SIZE) | ||
217 | s->bp = 0; | ||
218 | if (++s->rp == B_SIZE) | ||
219 | s->rp = 0; | ||
220 | } | ||
221 | |||
222 | |||
223 | /*********************************************************************** | ||
224 | // remove node from lists | ||
225 | ************************************************************************/ | ||
226 | static void swd_remove_node(lzo_swd_p s, unsigned node) | ||
227 | { | ||
228 | if (s->node_count == 0) { | ||
229 | unsigned key; | ||
230 | |||
231 | key = HEAD3(s->b,node); | ||
232 | assert(s->llen3[key] > 0); | ||
233 | --s->llen3[key]; | ||
234 | |||
235 | #ifdef HEAD2 | ||
236 | key = HEAD2(s->b,node); | ||
237 | assert(s->head2[key] != NIL2); | ||
238 | if ((unsigned) s->head2[key] == node) | ||
239 | s->head2[key] = NIL2; | ||
240 | #endif | ||
241 | } else | ||
242 | --s->node_count; | ||
243 | } | ||
244 | |||
245 | |||
246 | /*********************************************************************** | ||
247 | // | ||
248 | ************************************************************************/ | ||
249 | static void swd_accept(lzo_swd_p s, unsigned n) | ||
250 | { | ||
251 | assert(n <= s->look); | ||
252 | |||
253 | while (n--) { | ||
254 | unsigned key; | ||
255 | |||
256 | swd_remove_node(s,s->rp); | ||
257 | |||
258 | /* add bp into HEAD3 */ | ||
259 | key = HEAD3(s->b,s->bp); | ||
260 | s->succ3[s->bp] = s_get_head3(s,key); | ||
261 | s->head3[key] = s->bp; | ||
262 | s->best3[s->bp] = SWD_F + 1; | ||
263 | s->llen3[key]++; | ||
264 | assert(s->llen3[key] <= SWD_N); | ||
265 | |||
266 | #ifdef HEAD2 | ||
267 | /* add bp into HEAD2 */ | ||
268 | key = HEAD2(s->b,s->bp); | ||
269 | s->head2[key] = s->bp; | ||
270 | #endif | ||
271 | |||
272 | swd_getbyte(s); | ||
273 | } | ||
274 | } | ||
275 | |||
276 | |||
277 | /*********************************************************************** | ||
278 | // | ||
279 | ************************************************************************/ | ||
280 | static void swd_search(lzo_swd_p s, unsigned node, unsigned cnt) | ||
281 | { | ||
282 | const uint8_t *p1; | ||
283 | const uint8_t *p2; | ||
284 | const uint8_t *px; | ||
285 | unsigned m_len = s->m_len; | ||
286 | const uint8_t *b = s->b; | ||
287 | const uint8_t *bp = s->b + s->bp; | ||
288 | const uint8_t *bx = s->b + s->bp + s->look; | ||
289 | unsigned char scan_end1; | ||
290 | |||
291 | assert(s->m_len > 0); | ||
292 | |||
293 | scan_end1 = bp[m_len - 1]; | ||
294 | for ( ; cnt-- > 0; node = s->succ3[node]) { | ||
295 | p1 = bp; | ||
296 | p2 = b + node; | ||
297 | px = bx; | ||
298 | |||
299 | assert(m_len < s->look); | ||
300 | |||
301 | if (p2[m_len - 1] == scan_end1 && | ||
302 | p2[m_len] == p1[m_len] && | ||
303 | p2[0] == p1[0] && | ||
304 | p2[1] == p1[1]) { | ||
305 | unsigned i; | ||
306 | assert(lzo_memcmp(bp,&b[node],3) == 0); | ||
307 | |||
308 | p1 += 2; p2 += 2; | ||
309 | do {} while (++p1 < px && *p1 == *++p2); | ||
310 | i = p1-bp; | ||
311 | |||
312 | assert(lzo_memcmp(bp,&b[node],i) == 0); | ||
313 | |||
314 | #if defined(SWD_BEST_OFF) | ||
315 | if (i < SWD_BEST_OFF) { | ||
316 | if (s->best_pos[i] == 0) | ||
317 | s->best_pos[i] = node + 1; | ||
318 | } | ||
319 | #endif | ||
320 | if (i > m_len) { | ||
321 | s->m_len = m_len = i; | ||
322 | s->m_pos = node; | ||
323 | if (m_len == s->look) | ||
324 | return; | ||
325 | if (m_len >= SWD_F) | ||
326 | return; | ||
327 | if (m_len > (unsigned) s->best3[node]) | ||
328 | return; | ||
329 | scan_end1 = bp[m_len - 1]; | ||
330 | } | ||
331 | } | ||
332 | } | ||
333 | } | ||
334 | |||
335 | |||
336 | /*********************************************************************** | ||
337 | // | ||
338 | ************************************************************************/ | ||
339 | #ifdef HEAD2 | ||
340 | |||
341 | static int swd_search2(lzo_swd_p s) | ||
342 | { | ||
343 | unsigned key; | ||
344 | |||
345 | assert(s->look >= 2); | ||
346 | assert(s->m_len > 0); | ||
347 | |||
348 | key = s->head2[ HEAD2(s->b,s->bp) ]; | ||
349 | if (key == NIL2) | ||
350 | return 0; | ||
351 | assert(lzo_memcmp(&s->b[s->bp],&s->b[key],2) == 0); | ||
352 | #if defined(SWD_BEST_OFF) | ||
353 | if (s->best_pos[2] == 0) | ||
354 | s->best_pos[2] = key + 1; | ||
355 | #endif | ||
356 | |||
357 | if (s->m_len < 2) { | ||
358 | s->m_len = 2; | ||
359 | s->m_pos = key; | ||
360 | } | ||
361 | return 1; | ||
362 | } | ||
363 | |||
364 | #endif | ||
365 | |||
366 | |||
367 | /*********************************************************************** | ||
368 | // | ||
369 | ************************************************************************/ | ||
370 | static void swd_findbest(lzo_swd_p s) | ||
371 | { | ||
372 | unsigned key; | ||
373 | unsigned cnt, node; | ||
374 | unsigned len; | ||
375 | |||
376 | assert(s->m_len > 0); | ||
377 | |||
378 | /* get current head, add bp into HEAD3 */ | ||
379 | key = HEAD3(s->b,s->bp); | ||
380 | node = s->succ3[s->bp] = s_get_head3(s,key); | ||
381 | cnt = s->llen3[key]++; | ||
382 | assert(s->llen3[key] <= SWD_N + SWD_F); | ||
383 | if (cnt > s->max_chain) | ||
384 | cnt = s->max_chain; | ||
385 | s->head3[key] = s->bp; | ||
386 | |||
387 | s->b_char = s->b[s->bp]; | ||
388 | len = s->m_len; | ||
389 | if (s->m_len >= s->look) { | ||
390 | if (s->look == 0) | ||
391 | s->b_char = -1; | ||
392 | s->m_off = 0; | ||
393 | s->best3[s->bp] = SWD_F + 1; | ||
394 | } else { | ||
395 | #ifdef HEAD2 | ||
396 | if (swd_search2(s)) | ||
397 | #endif | ||
398 | if (s->look >= 3) | ||
399 | swd_search(s,node,cnt); | ||
400 | if (s->m_len > len) | ||
401 | s->m_off = swd_pos2off(s,s->m_pos); | ||
402 | s->best3[s->bp] = s->m_len; | ||
403 | |||
404 | #if defined(SWD_BEST_OFF) | ||
405 | if (s->use_best_off) { | ||
406 | int i; | ||
407 | for (i = 2; i < SWD_BEST_OFF; i++) | ||
408 | if (s->best_pos[i] > 0) | ||
409 | s->best_off[i] = swd_pos2off(s,s->best_pos[i]-1); | ||
410 | else | ||
411 | s->best_off[i] = 0; | ||
412 | } | ||
413 | #endif | ||
414 | } | ||
415 | |||
416 | swd_remove_node(s,s->rp); | ||
417 | |||
418 | #ifdef HEAD2 | ||
419 | /* add bp into HEAD2 */ | ||
420 | key = HEAD2(s->b,s->bp); | ||
421 | s->head2[key] = s->bp; | ||
422 | #endif | ||
423 | } | ||
424 | |||
425 | #undef HEAD3 | ||
426 | #undef HEAD2 | ||
427 | #undef s_get_head3 | ||
428 | |||
429 | |||
430 | /*********************************************************************** | ||
431 | // | ||
432 | ************************************************************************/ | ||
433 | static int init_match(lzo1x_999_t *c, lzo_swd_p s, uint32_t use_best_off) | ||
434 | { | ||
435 | int r; | ||
436 | |||
437 | assert(!c->init); | ||
438 | c->init = 1; | ||
439 | |||
440 | s->c = c; | ||
441 | |||
442 | r = swd_init(s); | ||
443 | if (r != 0) | ||
444 | return r; | ||
445 | |||
446 | s->use_best_off = use_best_off; | ||
447 | return r; | ||
448 | } | ||
449 | |||
450 | |||
451 | /*********************************************************************** | ||
452 | // | ||
453 | ************************************************************************/ | ||
454 | static int find_match(lzo1x_999_t *c, lzo_swd_p s, | ||
455 | unsigned this_len, unsigned skip) | ||
456 | { | ||
457 | assert(c->init); | ||
458 | |||
459 | if (skip > 0) { | ||
460 | assert(this_len >= skip); | ||
461 | swd_accept(s, this_len - skip); | ||
462 | } else { | ||
463 | assert(this_len <= 1); | ||
464 | } | ||
465 | |||
466 | s->m_len = 1; | ||
467 | s->m_len = 1; | ||
468 | #ifdef SWD_BEST_OFF | ||
469 | if (s->use_best_off) | ||
470 | memset(s->best_pos,0,sizeof(s->best_pos)); | ||
471 | #endif | ||
472 | swd_findbest(s); | ||
473 | c->m_len = s->m_len; | ||
474 | c->m_off = s->m_off; | ||
475 | |||
476 | swd_getbyte(s); | ||
477 | |||
478 | if (s->b_char < 0) { | ||
479 | c->look = 0; | ||
480 | c->m_len = 0; | ||
481 | } else { | ||
482 | c->look = s->look + 1; | ||
483 | } | ||
484 | c->bp = c->ip - c->look; | ||
485 | |||
486 | return LZO_E_OK; | ||
487 | } | ||
488 | |||
489 | /* this is a public functions, but there is no prototype in a header file */ | ||
490 | static int lzo1x_999_compress_internal(const uint8_t *in , unsigned in_len, | ||
491 | uint8_t *out, unsigned *out_len, | ||
492 | void *wrkmem, | ||
493 | unsigned good_length, | ||
494 | unsigned max_lazy, | ||
495 | unsigned max_chain, | ||
496 | uint32_t use_best_off); | ||
497 | |||
498 | |||
499 | /*********************************************************************** | ||
500 | // | ||
501 | ************************************************************************/ | ||
502 | static uint8_t *code_match(lzo1x_999_t *c, | ||
503 | uint8_t *op, unsigned m_len, unsigned m_off) | ||
504 | { | ||
505 | assert(op > c->out); | ||
506 | if (m_len == 2) { | ||
507 | assert(m_off <= M1_MAX_OFFSET); | ||
508 | assert(c->r1_lit > 0); assert(c->r1_lit < 4); | ||
509 | m_off -= 1; | ||
510 | *op++ = M1_MARKER | ((m_off & 3) << 2); | ||
511 | *op++ = m_off >> 2; | ||
512 | } else if (m_len <= M2_MAX_LEN && m_off <= M2_MAX_OFFSET) { | ||
513 | assert(m_len >= 3); | ||
514 | m_off -= 1; | ||
515 | *op++ = ((m_len - 1) << 5) | ((m_off & 7) << 2); | ||
516 | *op++ = m_off >> 3; | ||
517 | assert(op[-2] >= M2_MARKER); | ||
518 | } else if (m_len == M2_MIN_LEN && m_off <= MX_MAX_OFFSET && c->r1_lit >= 4) { | ||
519 | assert(m_len == 3); | ||
520 | assert(m_off > M2_MAX_OFFSET); | ||
521 | m_off -= 1 + M2_MAX_OFFSET; | ||
522 | *op++ = M1_MARKER | ((m_off & 3) << 2); | ||
523 | *op++ = m_off >> 2; | ||
524 | } else if (m_off <= M3_MAX_OFFSET) { | ||
525 | assert(m_len >= 3); | ||
526 | m_off -= 1; | ||
527 | if (m_len <= M3_MAX_LEN) | ||
528 | *op++ = M3_MARKER | (m_len - 2); | ||
529 | else { | ||
530 | m_len -= M3_MAX_LEN; | ||
531 | *op++ = M3_MARKER | 0; | ||
532 | while (m_len > 255) | ||
533 | { | ||
534 | m_len -= 255; | ||
535 | *op++ = 0; | ||
536 | } | ||
537 | assert(m_len > 0); | ||
538 | *op++ = m_len; | ||
539 | } | ||
540 | *op++ = m_off << 2; | ||
541 | *op++ = m_off >> 6; | ||
542 | } else { | ||
543 | unsigned k; | ||
544 | |||
545 | assert(m_len >= 3); | ||
546 | assert(m_off > 0x4000); assert(m_off <= 0xbfff); | ||
547 | m_off -= 0x4000; | ||
548 | k = (m_off & 0x4000) >> 11; | ||
549 | if (m_len <= M4_MAX_LEN) | ||
550 | *op++ = M4_MARKER | k | (m_len - 2); | ||
551 | else { | ||
552 | m_len -= M4_MAX_LEN; | ||
553 | *op++ = M4_MARKER | k | 0; | ||
554 | while (m_len > 255) | ||
555 | { | ||
556 | m_len -= 255; | ||
557 | *op++ = 0; | ||
558 | } | ||
559 | assert(m_len > 0); | ||
560 | *op++ = m_len; | ||
561 | } | ||
562 | *op++ = m_off << 2; | ||
563 | *op++ = m_off >> 6; | ||
564 | } | ||
565 | |||
566 | return op; | ||
567 | } | ||
568 | |||
569 | |||
570 | static uint8_t *STORE_RUN(lzo1x_999_t *c, uint8_t *op, | ||
571 | const uint8_t *ii, unsigned t) | ||
572 | { | ||
573 | if (op == c->out && t <= 238) { | ||
574 | *op++ = 17 + t; | ||
575 | } else if (t <= 3) { | ||
576 | op[-2] |= t; | ||
577 | } else if (t <= 18) { | ||
578 | *op++ = t - 3; | ||
579 | } else { | ||
580 | unsigned tt = t - 18; | ||
581 | |||
582 | *op++ = 0; | ||
583 | while (tt > 255) { | ||
584 | tt -= 255; | ||
585 | *op++ = 0; | ||
586 | } | ||
587 | assert(tt > 0); | ||
588 | *op++ = tt; | ||
589 | } | ||
590 | do *op++ = *ii++; while (--t > 0); | ||
591 | |||
592 | return op; | ||
593 | } | ||
594 | |||
595 | |||
596 | static uint8_t *code_run(lzo1x_999_t *c, uint8_t *op, const uint8_t *ii, | ||
597 | unsigned lit) | ||
598 | { | ||
599 | if (lit > 0) { | ||
600 | assert(m_len >= 2); | ||
601 | op = STORE_RUN(c,op,ii,lit); | ||
602 | } else { | ||
603 | assert(m_len >= 3); | ||
604 | } | ||
605 | c->r1_lit = lit; | ||
606 | |||
607 | return op; | ||
608 | } | ||
609 | |||
610 | |||
611 | /*********************************************************************** | ||
612 | // | ||
613 | ************************************************************************/ | ||
614 | static int len_of_coded_match(unsigned m_len, unsigned m_off, unsigned lit) | ||
615 | { | ||
616 | int n = 4; | ||
617 | |||
618 | if (m_len < 2) | ||
619 | return -1; | ||
620 | if (m_len == 2) | ||
621 | return (m_off <= M1_MAX_OFFSET && lit > 0 && lit < 4) ? 2 : -1; | ||
622 | if (m_len <= M2_MAX_LEN && m_off <= M2_MAX_OFFSET) | ||
623 | return 2; | ||
624 | if (m_len == M2_MIN_LEN && m_off <= MX_MAX_OFFSET && lit >= 4) | ||
625 | return 2; | ||
626 | if (m_off <= M3_MAX_OFFSET) { | ||
627 | if (m_len <= M3_MAX_LEN) | ||
628 | return 3; | ||
629 | m_len -= M3_MAX_LEN; | ||
630 | } else if (m_off <= M4_MAX_OFFSET) { | ||
631 | if (m_len <= M4_MAX_LEN) | ||
632 | return 3; | ||
633 | m_len -= M4_MAX_LEN; | ||
634 | } else | ||
635 | return -1; | ||
636 | while (m_len > 255) { | ||
637 | m_len -= 255; | ||
638 | n++; | ||
639 | } | ||
640 | return n; | ||
641 | } | ||
642 | |||
643 | |||
644 | static int min_gain(unsigned ahead, unsigned lit1, | ||
645 | unsigned lit2, int l1, int l2, int l3) | ||
646 | { | ||
647 | int lazy_match_min_gain = 0; | ||
648 | |||
649 | assert (ahead >= 1); | ||
650 | lazy_match_min_gain += ahead; | ||
651 | |||
652 | if (lit1 <= 3) | ||
653 | lazy_match_min_gain += (lit2 <= 3) ? 0 : 2; | ||
654 | else if (lit1 <= 18) | ||
655 | lazy_match_min_gain += (lit2 <= 18) ? 0 : 1; | ||
656 | |||
657 | lazy_match_min_gain += (l2 - l1) * 2; | ||
658 | if (l3 > 0) | ||
659 | lazy_match_min_gain -= (ahead - l3) * 2; | ||
660 | |||
661 | if (lazy_match_min_gain < 0) | ||
662 | lazy_match_min_gain = 0; | ||
663 | |||
664 | return lazy_match_min_gain; | ||
665 | } | ||
666 | |||
667 | |||
668 | /*********************************************************************** | ||
669 | // | ||
670 | ************************************************************************/ | ||
671 | #if defined(SWD_BEST_OFF) | ||
672 | |||
673 | static void better_match(const lzo_swd_p swd, | ||
674 | unsigned *m_len, unsigned *m_off) | ||
675 | { | ||
676 | |||
677 | if (*m_len <= M2_MIN_LEN) | ||
678 | return; | ||
679 | |||
680 | if (*m_off <= M2_MAX_OFFSET) | ||
681 | return; | ||
682 | |||
683 | /* M3/M4 -> M2 */ | ||
684 | if (*m_off > M2_MAX_OFFSET && | ||
685 | *m_len >= M2_MIN_LEN + 1 && *m_len <= M2_MAX_LEN + 1 && | ||
686 | swd->best_off[*m_len-1] && swd->best_off[*m_len-1] <= M2_MAX_OFFSET) | ||
687 | { | ||
688 | *m_len = *m_len - 1; | ||
689 | *m_off = swd->best_off[*m_len]; | ||
690 | return; | ||
691 | } | ||
692 | |||
693 | /* M4 -> M2 */ | ||
694 | if (*m_off > M3_MAX_OFFSET && | ||
695 | *m_len >= M4_MAX_LEN + 1 && *m_len <= M2_MAX_LEN + 2 && | ||
696 | swd->best_off[*m_len-2] && swd->best_off[*m_len-2] <= M2_MAX_OFFSET) | ||
697 | { | ||
698 | *m_len = *m_len - 2; | ||
699 | *m_off = swd->best_off[*m_len]; | ||
700 | return; | ||
701 | } | ||
702 | /* M4 -> M3 */ | ||
703 | if (*m_off > M3_MAX_OFFSET && | ||
704 | *m_len >= M4_MAX_LEN + 1 && *m_len <= M3_MAX_LEN + 1 && | ||
705 | swd->best_off[*m_len-1] && swd->best_off[*m_len-1] <= M3_MAX_OFFSET) | ||
706 | { | ||
707 | *m_len = *m_len - 1; | ||
708 | *m_off = swd->best_off[*m_len]; | ||
709 | } | ||
710 | } | ||
711 | |||
712 | #endif | ||
713 | |||
714 | |||
715 | /*********************************************************************** | ||
716 | // | ||
717 | ************************************************************************/ | ||
718 | static int lzo1x_999_compress_internal(const uint8_t *in, unsigned in_len, | ||
719 | uint8_t *out, unsigned *out_len, | ||
720 | void *wrkmem, | ||
721 | unsigned good_length, | ||
722 | unsigned max_lazy, | ||
723 | unsigned max_chain, | ||
724 | uint32_t use_best_off) | ||
725 | { | ||
726 | uint8_t *op; | ||
727 | const uint8_t *ii; | ||
728 | unsigned lit; | ||
729 | unsigned m_len, m_off; | ||
730 | lzo1x_999_t cc; | ||
731 | lzo1x_999_t * const c = &cc; | ||
732 | lzo_swd_p const swd = (lzo_swd_p) wrkmem; | ||
733 | int r; | ||
734 | |||
735 | c->init = 0; | ||
736 | c->ip = c->in = in; | ||
737 | c->in_end = in + in_len; | ||
738 | c->out = out; | ||
739 | |||
740 | op = out; | ||
741 | ii = c->ip; /* point to start of literal run */ | ||
742 | lit = 0; | ||
743 | c->r1_lit = 0; | ||
744 | |||
745 | r = init_match(c, swd, use_best_off); | ||
746 | if (r != 0) | ||
747 | return r; | ||
748 | swd->max_chain = max_chain; | ||
749 | |||
750 | r = find_match(c, swd, 0, 0); | ||
751 | if (r != 0) | ||
752 | return r; | ||
753 | |||
754 | while (c->look > 0) { | ||
755 | unsigned ahead; | ||
756 | unsigned max_ahead; | ||
757 | int l1, l2, l3; | ||
758 | |||
759 | m_len = c->m_len; | ||
760 | m_off = c->m_off; | ||
761 | |||
762 | assert(c->bp == c->ip - c->look); | ||
763 | assert(c->bp >= in); | ||
764 | if (lit == 0) | ||
765 | ii = c->bp; | ||
766 | assert(ii + lit == c->bp); | ||
767 | assert(swd->b_char == *(c->bp)); | ||
768 | |||
769 | if ( m_len < 2 || | ||
770 | (m_len == 2 && (m_off > M1_MAX_OFFSET || lit == 0 || lit >= 4)) || | ||
771 | /* Do not accept this match for compressed-data compatibility | ||
772 | * with LZO v1.01 and before | ||
773 | * [ might be a problem for decompress() and optimize() ] | ||
774 | */ | ||
775 | (m_len == 2 && op == out) || | ||
776 | (op == out && lit == 0)) | ||
777 | { | ||
778 | /* a literal */ | ||
779 | m_len = 0; | ||
780 | } | ||
781 | else if (m_len == M2_MIN_LEN) { | ||
782 | /* compression ratio improves if we code a literal in some cases */ | ||
783 | if (m_off > MX_MAX_OFFSET && lit >= 4) | ||
784 | m_len = 0; | ||
785 | } | ||
786 | |||
787 | if (m_len == 0) { | ||
788 | /* a literal */ | ||
789 | lit++; | ||
790 | swd->max_chain = max_chain; | ||
791 | r = find_match(c,swd,1,0); | ||
792 | assert(r == 0); | ||
793 | continue; | ||
794 | } | ||
795 | |||
796 | /* a match */ | ||
797 | #if defined(SWD_BEST_OFF) | ||
798 | if (swd->use_best_off) | ||
799 | better_match(swd,&m_len,&m_off); | ||
800 | #endif | ||
801 | |||
802 | /* shall we try a lazy match ? */ | ||
803 | ahead = 0; | ||
804 | if (m_len >= max_lazy) { | ||
805 | /* no */ | ||
806 | l1 = 0; | ||
807 | max_ahead = 0; | ||
808 | } else { | ||
809 | /* yes, try a lazy match */ | ||
810 | l1 = len_of_coded_match(m_len,m_off,lit); | ||
811 | assert(l1 > 0); | ||
812 | max_ahead = LZO_MIN(2, (unsigned)l1 - 1); | ||
813 | } | ||
814 | |||
815 | |||
816 | while (ahead < max_ahead && c->look > m_len) { | ||
817 | int lazy_match_min_gain; | ||
818 | |||
819 | if (m_len >= good_length) | ||
820 | swd->max_chain = max_chain >> 2; | ||
821 | else | ||
822 | swd->max_chain = max_chain; | ||
823 | r = find_match(c,swd,1,0); | ||
824 | ahead++; | ||
825 | |||
826 | assert(r == 0); | ||
827 | assert(c->look > 0); | ||
828 | assert(ii + lit + ahead == c->bp); | ||
829 | |||
830 | if (c->m_len < m_len) | ||
831 | continue; | ||
832 | if (c->m_len == m_len && c->m_off >= m_off) | ||
833 | continue; | ||
834 | #if defined(SWD_BEST_OFF) | ||
835 | if (swd->use_best_off) | ||
836 | better_match(swd,&c->m_len,&c->m_off); | ||
837 | #endif | ||
838 | l2 = len_of_coded_match(c->m_len,c->m_off,lit+ahead); | ||
839 | if (l2 < 0) | ||
840 | continue; | ||
841 | |||
842 | /* compressed-data compatibility [see above] */ | ||
843 | l3 = (op == out) ? -1 : len_of_coded_match(ahead,m_off,lit); | ||
844 | |||
845 | lazy_match_min_gain = min_gain(ahead,lit,lit+ahead,l1,l2,l3); | ||
846 | if (c->m_len >= m_len + lazy_match_min_gain) { | ||
847 | if (l3 > 0) { | ||
848 | /* code previous run */ | ||
849 | op = code_run(c,op,ii,lit); | ||
850 | lit = 0; | ||
851 | /* code shortened match */ | ||
852 | op = code_match(c,op,ahead,m_off); | ||
853 | } else { | ||
854 | lit += ahead; | ||
855 | assert(ii + lit == c->bp); | ||
856 | } | ||
857 | goto lazy_match_done; | ||
858 | } | ||
859 | } | ||
860 | |||
861 | assert(ii + lit + ahead == c->bp); | ||
862 | |||
863 | /* 1 - code run */ | ||
864 | op = code_run(c,op,ii,lit); | ||
865 | lit = 0; | ||
866 | |||
867 | /* 2 - code match */ | ||
868 | op = code_match(c,op,m_len,m_off); | ||
869 | swd->max_chain = max_chain; | ||
870 | r = find_match(c,swd,m_len,1+ahead); | ||
871 | assert(r == 0); | ||
872 | |||
873 | lazy_match_done: ; | ||
874 | } | ||
875 | |||
876 | /* store final run */ | ||
877 | if (lit > 0) | ||
878 | op = STORE_RUN(c,op,ii,lit); | ||
879 | |||
880 | #if defined(LZO_EOF_CODE) | ||
881 | *op++ = M4_MARKER | 1; | ||
882 | *op++ = 0; | ||
883 | *op++ = 0; | ||
884 | #endif | ||
885 | |||
886 | *out_len = op - out; | ||
887 | |||
888 | return LZO_E_OK; | ||
889 | } | ||
890 | |||
891 | |||
892 | /*********************************************************************** | ||
893 | // | ||
894 | ************************************************************************/ | ||
895 | int lzo1x_999_compress_level(const uint8_t *in, unsigned in_len, | ||
896 | uint8_t *out, unsigned *out_len, | ||
897 | void *wrkmem, | ||
898 | int compression_level) | ||
899 | { | ||
900 | static const struct { | ||
901 | uint16_t good_length; | ||
902 | uint16_t max_lazy; | ||
903 | uint16_t max_chain; | ||
904 | uint16_t use_best_off; | ||
905 | } c[3] = { | ||
906 | { 8, 32, 256, 0 }, | ||
907 | { 32, 128, 2048, 1 }, | ||
908 | { SWD_F, SWD_F, 4096, 1 } /* max. compression */ | ||
909 | }; | ||
910 | |||
911 | if (compression_level < 7 || compression_level > 9) | ||
912 | return LZO_E_ERROR; | ||
913 | |||
914 | compression_level -= 7; | ||
915 | return lzo1x_999_compress_internal(in, in_len, out, out_len, wrkmem, | ||
916 | c[compression_level].good_length, | ||
917 | c[compression_level].max_lazy, | ||
918 | c[compression_level].max_chain, | ||
919 | c[compression_level].use_best_off); | ||
920 | } | ||
diff --git a/archival/lzo1x_c.c b/archival/lzo1x_c.c new file mode 100644 index 000000000..cc86f74b1 --- /dev/null +++ b/archival/lzo1x_c.c | |||
@@ -0,0 +1,296 @@ | |||
1 | /* implementation of the LZO1[XY]-1 compression algorithm | ||
2 | |||
3 | This file is part of the LZO real-time data compression library. | ||
4 | |||
5 | Copyright (C) 1996..2008 Markus Franz Xaver Johannes Oberhumer | ||
6 | All Rights Reserved. | ||
7 | |||
8 | Markus F.X.J. Oberhumer <markus@oberhumer.com> | ||
9 | http://www.oberhumer.com/opensource/lzo/ | ||
10 | |||
11 | The LZO library is free software; you can redistribute it and/or | ||
12 | modify it under the terms of the GNU General Public License as | ||
13 | published by the Free Software Foundation; either version 2 of | ||
14 | the License, or (at your option) any later version. | ||
15 | |||
16 | The LZO library is distributed in the hope that it will be useful, | ||
17 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
18 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
19 | GNU General Public License for more details. | ||
20 | |||
21 | You should have received a copy of the GNU General Public License | ||
22 | along with the LZO library; see the file COPYING. | ||
23 | If not, write to the Free Software Foundation, Inc., | ||
24 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | ||
25 | */ | ||
26 | |||
27 | /*********************************************************************** | ||
28 | // compress a block of data. | ||
29 | ************************************************************************/ | ||
30 | static NOINLINE unsigned | ||
31 | do_compress(const uint8_t* in, unsigned in_len, | ||
32 | uint8_t* out, unsigned* out_len, | ||
33 | void* wrkmem) | ||
34 | { | ||
35 | register const uint8_t* ip; | ||
36 | uint8_t* op; | ||
37 | const uint8_t* const in_end = in + in_len; | ||
38 | const uint8_t* const ip_end = in + in_len - M2_MAX_LEN - 5; | ||
39 | const uint8_t* ii; | ||
40 | const void* *const dict = (const void**) wrkmem; | ||
41 | |||
42 | op = out; | ||
43 | ip = in; | ||
44 | ii = ip; | ||
45 | |||
46 | ip += 4; | ||
47 | for (;;) { | ||
48 | register const uint8_t* m_pos; | ||
49 | unsigned m_off; | ||
50 | unsigned m_len; | ||
51 | unsigned dindex; | ||
52 | |||
53 | D_INDEX1(dindex,ip); | ||
54 | GINDEX(m_pos,m_off,dict,dindex,in); | ||
55 | if (LZO_CHECK_MPOS_NON_DET(m_pos,m_off,in,ip,M4_MAX_OFFSET)) | ||
56 | goto literal; | ||
57 | #if 1 | ||
58 | if (m_off <= M2_MAX_OFFSET || m_pos[3] == ip[3]) | ||
59 | goto try_match; | ||
60 | D_INDEX2(dindex,ip); | ||
61 | #endif | ||
62 | GINDEX(m_pos,m_off,dict,dindex,in); | ||
63 | if (LZO_CHECK_MPOS_NON_DET(m_pos,m_off,in,ip,M4_MAX_OFFSET)) | ||
64 | goto literal; | ||
65 | if (m_off <= M2_MAX_OFFSET || m_pos[3] == ip[3]) | ||
66 | goto try_match; | ||
67 | goto literal; | ||
68 | |||
69 | try_match: | ||
70 | #if 1 && defined(LZO_UNALIGNED_OK_2) | ||
71 | if (* (const lzo_ushortp) m_pos != * (const lzo_ushortp) ip) | ||
72 | #else | ||
73 | if (m_pos[0] != ip[0] || m_pos[1] != ip[1]) | ||
74 | #endif | ||
75 | { | ||
76 | } else { | ||
77 | if (m_pos[2] == ip[2]) { | ||
78 | #if 0 | ||
79 | if (m_off <= M2_MAX_OFFSET) | ||
80 | goto match; | ||
81 | if (lit <= 3) | ||
82 | goto match; | ||
83 | if (lit == 3) { /* better compression, but slower */ | ||
84 | assert(op - 2 > out); op[-2] |= (uint8_t)(3); | ||
85 | *op++ = *ii++; *op++ = *ii++; *op++ = *ii++; | ||
86 | goto code_match; | ||
87 | } | ||
88 | if (m_pos[3] == ip[3]) | ||
89 | #endif | ||
90 | goto match; | ||
91 | } | ||
92 | else { | ||
93 | /* still need a better way for finding M1 matches */ | ||
94 | #if 0 | ||
95 | /* a M1 match */ | ||
96 | #if 0 | ||
97 | if (m_off <= M1_MAX_OFFSET && lit > 0 && lit <= 3) | ||
98 | #else | ||
99 | if (m_off <= M1_MAX_OFFSET && lit == 3) | ||
100 | #endif | ||
101 | { | ||
102 | register unsigned t; | ||
103 | |||
104 | t = lit; | ||
105 | assert(op - 2 > out); op[-2] |= (uint8_t)(t); | ||
106 | do *op++ = *ii++; while (--t > 0); | ||
107 | assert(ii == ip); | ||
108 | m_off -= 1; | ||
109 | *op++ = (uint8_t)(M1_MARKER | ((m_off & 3) << 2)); | ||
110 | *op++ = (uint8_t)(m_off >> 2); | ||
111 | ip += 2; | ||
112 | goto match_done; | ||
113 | } | ||
114 | #endif | ||
115 | } | ||
116 | } | ||
117 | |||
118 | /* a literal */ | ||
119 | literal: | ||
120 | UPDATE_I(dict, 0, dindex, ip, in); | ||
121 | ++ip; | ||
122 | if (ip >= ip_end) | ||
123 | break; | ||
124 | continue; | ||
125 | |||
126 | /* a match */ | ||
127 | match: | ||
128 | UPDATE_I(dict, 0, dindex, ip, in); | ||
129 | /* store current literal run */ | ||
130 | if (pd(ip, ii) > 0) { | ||
131 | register unsigned t = pd(ip, ii); | ||
132 | |||
133 | if (t <= 3) { | ||
134 | assert(op - 2 > out); | ||
135 | op[-2] |= (uint8_t)(t); | ||
136 | } | ||
137 | else if (t <= 18) | ||
138 | *op++ = (uint8_t)(t - 3); | ||
139 | else { | ||
140 | register unsigned tt = t - 18; | ||
141 | |||
142 | *op++ = 0; | ||
143 | while (tt > 255) { | ||
144 | tt -= 255; | ||
145 | *op++ = 0; | ||
146 | } | ||
147 | assert(tt > 0); | ||
148 | *op++ = (uint8_t)(tt); | ||
149 | } | ||
150 | do *op++ = *ii++; while (--t > 0); | ||
151 | } | ||
152 | |||
153 | /* code the match */ | ||
154 | assert(ii == ip); | ||
155 | ip += 3; | ||
156 | if (m_pos[3] != *ip++ || m_pos[4] != *ip++ || m_pos[5] != *ip++ | ||
157 | || m_pos[6] != *ip++ || m_pos[7] != *ip++ || m_pos[8] != *ip++ | ||
158 | #ifdef LZO1Y | ||
159 | || m_pos[ 9] != *ip++ || m_pos[10] != *ip++ || m_pos[11] != *ip++ | ||
160 | || m_pos[12] != *ip++ || m_pos[13] != *ip++ || m_pos[14] != *ip++ | ||
161 | #endif | ||
162 | ) { | ||
163 | --ip; | ||
164 | m_len = pd(ip, ii); | ||
165 | assert(m_len >= 3); | ||
166 | assert(m_len <= M2_MAX_LEN); | ||
167 | |||
168 | if (m_off <= M2_MAX_OFFSET) { | ||
169 | m_off -= 1; | ||
170 | #if defined(LZO1X) | ||
171 | *op++ = (uint8_t)(((m_len - 1) << 5) | ((m_off & 7) << 2)); | ||
172 | *op++ = (uint8_t)(m_off >> 3); | ||
173 | #elif defined(LZO1Y) | ||
174 | *op++ = (uint8_t)(((m_len + 1) << 4) | ((m_off & 3) << 2)); | ||
175 | *op++ = (uint8_t)(m_off >> 2); | ||
176 | #endif | ||
177 | } | ||
178 | else if (m_off <= M3_MAX_OFFSET) { | ||
179 | m_off -= 1; | ||
180 | *op++ = (uint8_t)(M3_MARKER | (m_len - 2)); | ||
181 | goto m3_m4_offset; | ||
182 | } else { | ||
183 | #if defined(LZO1X) | ||
184 | m_off -= 0x4000; | ||
185 | assert(m_off > 0); | ||
186 | assert(m_off <= 0x7fff); | ||
187 | *op++ = (uint8_t)(M4_MARKER | ((m_off & 0x4000) >> 11) | (m_len - 2)); | ||
188 | goto m3_m4_offset; | ||
189 | #elif defined(LZO1Y) | ||
190 | goto m4_match; | ||
191 | #endif | ||
192 | } | ||
193 | } | ||
194 | else { | ||
195 | { | ||
196 | const uint8_t* end = in_end; | ||
197 | const uint8_t* m = m_pos + M2_MAX_LEN + 1; | ||
198 | while (ip < end && *m == *ip) | ||
199 | m++, ip++; | ||
200 | m_len = pd(ip, ii); | ||
201 | } | ||
202 | assert(m_len > M2_MAX_LEN); | ||
203 | |||
204 | if (m_off <= M3_MAX_OFFSET) { | ||
205 | m_off -= 1; | ||
206 | if (m_len <= 33) | ||
207 | *op++ = (uint8_t)(M3_MARKER | (m_len - 2)); | ||
208 | else { | ||
209 | m_len -= 33; | ||
210 | *op++ = M3_MARKER | 0; | ||
211 | goto m3_m4_len; | ||
212 | } | ||
213 | } else { | ||
214 | #if defined(LZO1Y) | ||
215 | m4_match: | ||
216 | #endif | ||
217 | m_off -= 0x4000; | ||
218 | assert(m_off > 0); | ||
219 | assert(m_off <= 0x7fff); | ||
220 | if (m_len <= M4_MAX_LEN) | ||
221 | *op++ = (uint8_t)(M4_MARKER | ((m_off & 0x4000) >> 11) | (m_len - 2)); | ||
222 | else { | ||
223 | m_len -= M4_MAX_LEN; | ||
224 | *op++ = (uint8_t)(M4_MARKER | ((m_off & 0x4000) >> 11)); | ||
225 | m3_m4_len: | ||
226 | while (m_len > 255) { | ||
227 | m_len -= 255; | ||
228 | *op++ = 0; | ||
229 | } | ||
230 | assert(m_len > 0); | ||
231 | *op++ = (uint8_t)(m_len); | ||
232 | } | ||
233 | } | ||
234 | m3_m4_offset: | ||
235 | *op++ = (uint8_t)((m_off & 63) << 2); | ||
236 | *op++ = (uint8_t)(m_off >> 6); | ||
237 | } | ||
238 | #if 0 | ||
239 | match_done: | ||
240 | #endif | ||
241 | ii = ip; | ||
242 | if (ip >= ip_end) | ||
243 | break; | ||
244 | } | ||
245 | |||
246 | *out_len = pd(op, out); | ||
247 | return pd(in_end, ii); | ||
248 | } | ||
249 | |||
250 | /*********************************************************************** | ||
251 | // public entry point | ||
252 | ************************************************************************/ | ||
253 | int DO_COMPRESS(const uint8_t* in, unsigned in_len, | ||
254 | uint8_t* out, unsigned* out_len, | ||
255 | void* wrkmem) | ||
256 | { | ||
257 | uint8_t* op = out; | ||
258 | unsigned t; | ||
259 | |||
260 | if (in_len <= M2_MAX_LEN + 5) | ||
261 | t = in_len; | ||
262 | else { | ||
263 | t = do_compress(in,in_len,op,out_len,wrkmem); | ||
264 | op += *out_len; | ||
265 | } | ||
266 | |||
267 | if (t > 0) { | ||
268 | const uint8_t* ii = in + in_len - t; | ||
269 | |||
270 | if (op == out && t <= 238) | ||
271 | *op++ = (uint8_t)(17 + t); | ||
272 | else if (t <= 3) | ||
273 | op[-2] |= (uint8_t)(t); | ||
274 | else if (t <= 18) | ||
275 | *op++ = (uint8_t)(t - 3); | ||
276 | else { | ||
277 | unsigned tt = t - 18; | ||
278 | |||
279 | *op++ = 0; | ||
280 | while (tt > 255) { | ||
281 | tt -= 255; | ||
282 | *op++ = 0; | ||
283 | } | ||
284 | assert(tt > 0); | ||
285 | *op++ = (uint8_t)(tt); | ||
286 | } | ||
287 | do *op++ = *ii++; while (--t > 0); | ||
288 | } | ||
289 | |||
290 | *op++ = M4_MARKER | 1; | ||
291 | *op++ = 0; | ||
292 | *op++ = 0; | ||
293 | |||
294 | *out_len = pd(op, out); | ||
295 | return 0; /*LZO_E_OK*/ | ||
296 | } | ||
diff --git a/archival/lzo1x_d.c b/archival/lzo1x_d.c new file mode 100644 index 000000000..348a85510 --- /dev/null +++ b/archival/lzo1x_d.c | |||
@@ -0,0 +1,420 @@ | |||
1 | /* implementation of the LZO1X decompression algorithm | ||
2 | |||
3 | This file is part of the LZO real-time data compression library. | ||
4 | |||
5 | Copyright (C) 1996..2008 Markus Franz Xaver Johannes Oberhumer | ||
6 | All Rights Reserved. | ||
7 | |||
8 | Markus F.X.J. Oberhumer <markus@oberhumer.com> | ||
9 | http://www.oberhumer.com/opensource/lzo/ | ||
10 | |||
11 | The LZO library is free software; you can redistribute it and/or | ||
12 | modify it under the terms of the GNU General Public License as | ||
13 | published by the Free Software Foundation; either version 2 of | ||
14 | the License, or (at your option) any later version. | ||
15 | |||
16 | The LZO library is distributed in the hope that it will be useful, | ||
17 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
18 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
19 | GNU General Public License for more details. | ||
20 | |||
21 | You should have received a copy of the GNU General Public License | ||
22 | along with the LZO library; see the file COPYING. | ||
23 | If not, write to the Free Software Foundation, Inc., | ||
24 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | ||
25 | */ | ||
26 | #include "libbb.h" | ||
27 | #include "liblzo.h" | ||
28 | |||
29 | /*********************************************************************** | ||
30 | // decompress a block of data. | ||
31 | ************************************************************************/ | ||
32 | /* safe decompression with overrun testing */ | ||
33 | int lzo1x_decompress_safe(const uint8_t* in, unsigned in_len, | ||
34 | uint8_t* out, unsigned* out_len, | ||
35 | void* wrkmem UNUSED_PARAM) | ||
36 | { | ||
37 | register uint8_t* op; | ||
38 | register const uint8_t* ip; | ||
39 | register unsigned t; | ||
40 | #if defined(COPY_DICT) | ||
41 | unsigned m_off; | ||
42 | const uint8_t* dict_end; | ||
43 | #else | ||
44 | register const uint8_t* m_pos = NULL; /* possibly not needed */ | ||
45 | #endif | ||
46 | const uint8_t* const ip_end = in + in_len; | ||
47 | #if defined(HAVE_ANY_OP) | ||
48 | uint8_t* const op_end = out + *out_len; | ||
49 | #endif | ||
50 | #if defined(LZO1Z) | ||
51 | unsigned last_m_off = 0; | ||
52 | #endif | ||
53 | |||
54 | // LZO_UNUSED(wrkmem); | ||
55 | |||
56 | #if defined(COPY_DICT) | ||
57 | if (dict) { | ||
58 | if (dict_len > M4_MAX_OFFSET) { | ||
59 | dict += dict_len - M4_MAX_OFFSET; | ||
60 | dict_len = M4_MAX_OFFSET; | ||
61 | } | ||
62 | dict_end = dict + dict_len; | ||
63 | } else { | ||
64 | dict_len = 0; | ||
65 | dict_end = NULL; | ||
66 | } | ||
67 | #endif /* COPY_DICT */ | ||
68 | |||
69 | *out_len = 0; | ||
70 | |||
71 | op = out; | ||
72 | ip = in; | ||
73 | |||
74 | if (*ip > 17) { | ||
75 | t = *ip++ - 17; | ||
76 | if (t < 4) | ||
77 | goto match_next; | ||
78 | assert(t > 0); NEED_OP(t); NEED_IP(t+1); | ||
79 | do *op++ = *ip++; while (--t > 0); | ||
80 | goto first_literal_run; | ||
81 | } | ||
82 | |||
83 | while (TEST_IP && TEST_OP) { | ||
84 | t = *ip++; | ||
85 | if (t >= 16) | ||
86 | goto match; | ||
87 | /* a literal run */ | ||
88 | if (t == 0) { | ||
89 | NEED_IP(1); | ||
90 | while (*ip == 0) { | ||
91 | t += 255; | ||
92 | ip++; | ||
93 | NEED_IP(1); | ||
94 | } | ||
95 | t += 15 + *ip++; | ||
96 | } | ||
97 | /* copy literals */ | ||
98 | assert(t > 0); | ||
99 | NEED_OP(t+3); | ||
100 | NEED_IP(t+4); | ||
101 | #if defined(LZO_UNALIGNED_OK_4) || defined(LZO_ALIGNED_OK_4) | ||
102 | # if !defined(LZO_UNALIGNED_OK_4) | ||
103 | if (PTR_ALIGNED2_4(op, ip)) | ||
104 | # endif | ||
105 | { | ||
106 | COPY4(op, ip); | ||
107 | op += 4; | ||
108 | ip += 4; | ||
109 | if (--t > 0) { | ||
110 | if (t >= 4) { | ||
111 | do { | ||
112 | COPY4(op, ip); | ||
113 | op += 4; | ||
114 | ip += 4; | ||
115 | t -= 4; | ||
116 | } while (t >= 4); | ||
117 | if (t > 0) | ||
118 | do *op++ = *ip++; while (--t > 0); | ||
119 | } else { | ||
120 | do *op++ = *ip++; while (--t > 0); | ||
121 | } | ||
122 | } | ||
123 | } | ||
124 | # if !defined(LZO_UNALIGNED_OK_4) | ||
125 | else | ||
126 | # endif | ||
127 | #endif | ||
128 | #if !defined(LZO_UNALIGNED_OK_4) | ||
129 | { | ||
130 | *op++ = *ip++; | ||
131 | *op++ = *ip++; | ||
132 | *op++ = *ip++; | ||
133 | do *op++ = *ip++; while (--t > 0); | ||
134 | } | ||
135 | #endif | ||
136 | |||
137 | first_literal_run: | ||
138 | t = *ip++; | ||
139 | if (t >= 16) | ||
140 | goto match; | ||
141 | #if defined(COPY_DICT) | ||
142 | #if defined(LZO1Z) | ||
143 | m_off = (1 + M2_MAX_OFFSET) + (t << 6) + (*ip++ >> 2); | ||
144 | last_m_off = m_off; | ||
145 | #else | ||
146 | m_off = (1 + M2_MAX_OFFSET) + (t >> 2) + (*ip++ << 2); | ||
147 | #endif | ||
148 | NEED_OP(3); | ||
149 | t = 3; COPY_DICT(t,m_off) | ||
150 | #else /* !COPY_DICT */ | ||
151 | #if defined(LZO1Z) | ||
152 | t = (1 + M2_MAX_OFFSET) + (t << 6) + (*ip++ >> 2); | ||
153 | m_pos = op - t; | ||
154 | last_m_off = t; | ||
155 | #else | ||
156 | m_pos = op - (1 + M2_MAX_OFFSET); | ||
157 | m_pos -= t >> 2; | ||
158 | m_pos -= *ip++ << 2; | ||
159 | #endif | ||
160 | TEST_LB(m_pos); NEED_OP(3); | ||
161 | *op++ = *m_pos++; | ||
162 | *op++ = *m_pos++; | ||
163 | *op++ = *m_pos; | ||
164 | #endif /* COPY_DICT */ | ||
165 | goto match_done; | ||
166 | |||
167 | /* handle matches */ | ||
168 | do { | ||
169 | match: | ||
170 | if (t >= 64) { /* a M2 match */ | ||
171 | #if defined(COPY_DICT) | ||
172 | #if defined(LZO1X) | ||
173 | m_off = 1 + ((t >> 2) & 7) + (*ip++ << 3); | ||
174 | t = (t >> 5) - 1; | ||
175 | #elif defined(LZO1Y) | ||
176 | m_off = 1 + ((t >> 2) & 3) + (*ip++ << 2); | ||
177 | t = (t >> 4) - 3; | ||
178 | #elif defined(LZO1Z) | ||
179 | m_off = t & 0x1f; | ||
180 | if (m_off >= 0x1c) | ||
181 | m_off = last_m_off; | ||
182 | else { | ||
183 | m_off = 1 + (m_off << 6) + (*ip++ >> 2); | ||
184 | last_m_off = m_off; | ||
185 | } | ||
186 | t = (t >> 5) - 1; | ||
187 | #endif | ||
188 | #else /* !COPY_DICT */ | ||
189 | #if defined(LZO1X) | ||
190 | m_pos = op - 1; | ||
191 | m_pos -= (t >> 2) & 7; | ||
192 | m_pos -= *ip++ << 3; | ||
193 | t = (t >> 5) - 1; | ||
194 | #elif defined(LZO1Y) | ||
195 | m_pos = op - 1; | ||
196 | m_pos -= (t >> 2) & 3; | ||
197 | m_pos -= *ip++ << 2; | ||
198 | t = (t >> 4) - 3; | ||
199 | #elif defined(LZO1Z) | ||
200 | { | ||
201 | unsigned off = t & 0x1f; | ||
202 | m_pos = op; | ||
203 | if (off >= 0x1c) { | ||
204 | assert(last_m_off > 0); | ||
205 | m_pos -= last_m_off; | ||
206 | } else { | ||
207 | off = 1 + (off << 6) + (*ip++ >> 2); | ||
208 | m_pos -= off; | ||
209 | last_m_off = off; | ||
210 | } | ||
211 | } | ||
212 | t = (t >> 5) - 1; | ||
213 | #endif | ||
214 | TEST_LB(m_pos); assert(t > 0); NEED_OP(t+3-1); | ||
215 | goto copy_match; | ||
216 | #endif /* COPY_DICT */ | ||
217 | } | ||
218 | else if (t >= 32) { /* a M3 match */ | ||
219 | t &= 31; | ||
220 | if (t == 0) { | ||
221 | NEED_IP(1); | ||
222 | while (*ip == 0) { | ||
223 | t += 255; | ||
224 | ip++; | ||
225 | NEED_IP(1); | ||
226 | } | ||
227 | t += 31 + *ip++; | ||
228 | } | ||
229 | #if defined(COPY_DICT) | ||
230 | #if defined(LZO1Z) | ||
231 | m_off = 1 + (ip[0] << 6) + (ip[1] >> 2); | ||
232 | last_m_off = m_off; | ||
233 | #else | ||
234 | m_off = 1 + (ip[0] >> 2) + (ip[1] << 6); | ||
235 | #endif | ||
236 | #else /* !COPY_DICT */ | ||
237 | #if defined(LZO1Z) | ||
238 | { | ||
239 | unsigned off = 1 + (ip[0] << 6) + (ip[1] >> 2); | ||
240 | m_pos = op - off; | ||
241 | last_m_off = off; | ||
242 | } | ||
243 | #elif defined(LZO_UNALIGNED_OK_2) && defined(LZO_ABI_LITTLE_ENDIAN) | ||
244 | m_pos = op - 1; | ||
245 | m_pos -= (* (const lzo_ushortp) ip) >> 2; | ||
246 | #else | ||
247 | m_pos = op - 1; | ||
248 | m_pos -= (ip[0] >> 2) + (ip[1] << 6); | ||
249 | #endif | ||
250 | #endif /* COPY_DICT */ | ||
251 | ip += 2; | ||
252 | } | ||
253 | else if (t >= 16) { /* a M4 match */ | ||
254 | #if defined(COPY_DICT) | ||
255 | m_off = (t & 8) << 11; | ||
256 | #else /* !COPY_DICT */ | ||
257 | m_pos = op; | ||
258 | m_pos -= (t & 8) << 11; | ||
259 | #endif /* COPY_DICT */ | ||
260 | t &= 7; | ||
261 | if (t == 0) { | ||
262 | NEED_IP(1); | ||
263 | while (*ip == 0) { | ||
264 | t += 255; | ||
265 | ip++; | ||
266 | NEED_IP(1); | ||
267 | } | ||
268 | t += 7 + *ip++; | ||
269 | } | ||
270 | #if defined(COPY_DICT) | ||
271 | #if defined(LZO1Z) | ||
272 | m_off += (ip[0] << 6) + (ip[1] >> 2); | ||
273 | #else | ||
274 | m_off += (ip[0] >> 2) + (ip[1] << 6); | ||
275 | #endif | ||
276 | ip += 2; | ||
277 | if (m_off == 0) | ||
278 | goto eof_found; | ||
279 | m_off += 0x4000; | ||
280 | #if defined(LZO1Z) | ||
281 | last_m_off = m_off; | ||
282 | #endif | ||
283 | #else /* !COPY_DICT */ | ||
284 | #if defined(LZO1Z) | ||
285 | m_pos -= (ip[0] << 6) + (ip[1] >> 2); | ||
286 | #elif defined(LZO_UNALIGNED_OK_2) && defined(LZO_ABI_LITTLE_ENDIAN) | ||
287 | m_pos -= (* (const lzo_ushortp) ip) >> 2; | ||
288 | #else | ||
289 | m_pos -= (ip[0] >> 2) + (ip[1] << 6); | ||
290 | #endif | ||
291 | ip += 2; | ||
292 | if (m_pos == op) | ||
293 | goto eof_found; | ||
294 | m_pos -= 0x4000; | ||
295 | #if defined(LZO1Z) | ||
296 | last_m_off = pd((const uint8_t*)op, m_pos); | ||
297 | #endif | ||
298 | #endif /* COPY_DICT */ | ||
299 | } | ||
300 | else { /* a M1 match */ | ||
301 | #if defined(COPY_DICT) | ||
302 | #if defined(LZO1Z) | ||
303 | m_off = 1 + (t << 6) + (*ip++ >> 2); | ||
304 | last_m_off = m_off; | ||
305 | #else | ||
306 | m_off = 1 + (t >> 2) + (*ip++ << 2); | ||
307 | #endif | ||
308 | NEED_OP(2); | ||
309 | t = 2; COPY_DICT(t,m_off) | ||
310 | #else /* !COPY_DICT */ | ||
311 | #if defined(LZO1Z) | ||
312 | t = 1 + (t << 6) + (*ip++ >> 2); | ||
313 | m_pos = op - t; | ||
314 | last_m_off = t; | ||
315 | #else | ||
316 | m_pos = op - 1; | ||
317 | m_pos -= t >> 2; | ||
318 | m_pos -= *ip++ << 2; | ||
319 | #endif | ||
320 | TEST_LB(m_pos); NEED_OP(2); | ||
321 | *op++ = *m_pos++; | ||
322 | *op++ = *m_pos; | ||
323 | #endif /* COPY_DICT */ | ||
324 | goto match_done; | ||
325 | } | ||
326 | |||
327 | /* copy match */ | ||
328 | #if defined(COPY_DICT) | ||
329 | |||
330 | NEED_OP(t+3-1); | ||
331 | t += 3-1; COPY_DICT(t,m_off) | ||
332 | |||
333 | #else /* !COPY_DICT */ | ||
334 | |||
335 | TEST_LB(m_pos); assert(t > 0); NEED_OP(t+3-1); | ||
336 | #if defined(LZO_UNALIGNED_OK_4) || defined(LZO_ALIGNED_OK_4) | ||
337 | # if !defined(LZO_UNALIGNED_OK_4) | ||
338 | if (t >= 2 * 4 - (3 - 1) && PTR_ALIGNED2_4(op,m_pos)) { | ||
339 | assert((op - m_pos) >= 4); /* both pointers are aligned */ | ||
340 | # else | ||
341 | if (t >= 2 * 4 - (3 - 1) && (op - m_pos) >= 4) { | ||
342 | # endif | ||
343 | COPY4(op,m_pos); | ||
344 | op += 4; m_pos += 4; t -= 4 - (3 - 1); | ||
345 | do { | ||
346 | COPY4(op,m_pos); | ||
347 | op += 4; m_pos += 4; t -= 4; | ||
348 | } while (t >= 4); | ||
349 | if (t > 0) | ||
350 | do *op++ = *m_pos++; while (--t > 0); | ||
351 | } | ||
352 | else | ||
353 | #endif | ||
354 | { | ||
355 | copy_match: | ||
356 | *op++ = *m_pos++; *op++ = *m_pos++; | ||
357 | do *op++ = *m_pos++; while (--t > 0); | ||
358 | } | ||
359 | |||
360 | #endif /* COPY_DICT */ | ||
361 | |||
362 | match_done: | ||
363 | #if defined(LZO1Z) | ||
364 | t = ip[-1] & 3; | ||
365 | #else | ||
366 | t = ip[-2] & 3; | ||
367 | #endif | ||
368 | if (t == 0) | ||
369 | break; | ||
370 | |||
371 | /* copy literals */ | ||
372 | match_next: | ||
373 | assert(t > 0); | ||
374 | assert(t < 4); | ||
375 | NEED_OP(t); | ||
376 | NEED_IP(t+1); | ||
377 | #if 0 | ||
378 | do *op++ = *ip++; while (--t > 0); | ||
379 | #else | ||
380 | *op++ = *ip++; | ||
381 | if (t > 1) { | ||
382 | *op++ = *ip++; | ||
383 | if (t > 2) | ||
384 | *op++ = *ip++; | ||
385 | } | ||
386 | #endif | ||
387 | t = *ip++; | ||
388 | } while (TEST_IP && TEST_OP); | ||
389 | } | ||
390 | |||
391 | //#if defined(HAVE_TEST_IP) || defined(HAVE_TEST_OP) | ||
392 | /* no EOF code was found */ | ||
393 | *out_len = pd(op, out); | ||
394 | return LZO_E_EOF_NOT_FOUND; | ||
395 | //#endif | ||
396 | |||
397 | eof_found: | ||
398 | assert(t == 1); | ||
399 | *out_len = pd(op, out); | ||
400 | return (ip == ip_end ? LZO_E_OK : | ||
401 | (ip < ip_end ? LZO_E_INPUT_NOT_CONSUMED : LZO_E_INPUT_OVERRUN)); | ||
402 | |||
403 | //#if defined(HAVE_NEED_IP) | ||
404 | input_overrun: | ||
405 | *out_len = pd(op, out); | ||
406 | return LZO_E_INPUT_OVERRUN; | ||
407 | //#endif | ||
408 | |||
409 | //#if defined(HAVE_NEED_OP) | ||
410 | output_overrun: | ||
411 | *out_len = pd(op, out); | ||
412 | return LZO_E_OUTPUT_OVERRUN; | ||
413 | //#endif | ||
414 | |||
415 | //#if defined(LZO_TEST_OVERRUN_LOOKBEHIND) | ||
416 | lookbehind_overrun: | ||
417 | *out_len = pd(op, out); | ||
418 | return LZO_E_LOOKBEHIND_OVERRUN; | ||
419 | //#endif | ||
420 | } | ||
diff --git a/archival/lzop.c b/archival/lzop.c new file mode 100644 index 000000000..a30d5e78b --- /dev/null +++ b/archival/lzop.c | |||
@@ -0,0 +1,1075 @@ | |||
1 | /* | ||
2 | This file is part of the lzop file compressor. | ||
3 | |||
4 | Copyright (C) 1996..2003 Markus Franz Xaver Johannes Oberhumer | ||
5 | All Rights Reserved. | ||
6 | |||
7 | Markus F.X.J. Oberhumer <markus@oberhumer.com> | ||
8 | http://www.oberhumer.com/opensource/lzop/ | ||
9 | |||
10 | lzop and the LZO library are free software; you can redistribute them | ||
11 | and/or modify them under the terms of the GNU General Public License as | ||
12 | published by the Free Software Foundation; either version 2 of | ||
13 | the License, or (at your option) any later version. | ||
14 | |||
15 | This program is distributed in the hope that it will be useful, | ||
16 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
17 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
18 | GNU General Public License for more details. | ||
19 | |||
20 | You should have received a copy of the GNU General Public License | ||
21 | along with this program; see the file COPYING. | ||
22 | If not, write to the Free Software Foundation, Inc., | ||
23 | 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
24 | |||
25 | "Minimalized" for busybox by Alain Knaff | ||
26 | */ | ||
27 | |||
28 | #include "libbb.h" | ||
29 | #include "unarchive.h" | ||
30 | #include "liblzo_interface.h" | ||
31 | |||
32 | /* lzo-2.03/src/lzo_ptr.h */ | ||
33 | #define pd(a,b) ((unsigned)((a)-(b))) | ||
34 | |||
35 | #define lzo_version() LZO_VERSION | ||
36 | #define lzo_sizeof_dict_t (sizeof(uint8_t*)) | ||
37 | |||
38 | /* lzo-2.03/include/lzo/lzo1x.h */ | ||
39 | #define LZO1X_1_MEM_COMPRESS (16384 * lzo_sizeof_dict_t) | ||
40 | #define LZO1X_1_15_MEM_COMPRESS (32768 * lzo_sizeof_dict_t) | ||
41 | #define LZO1X_999_MEM_COMPRESS (14 * 16384 * sizeof(short)) | ||
42 | |||
43 | /* lzo-2.03/src/lzo1x_oo.c */ | ||
44 | #define NO_LIT UINT_MAX | ||
45 | |||
46 | /**********************************************************************/ | ||
47 | static void copy2(uint8_t* ip, const uint8_t* m_pos, unsigned off) | ||
48 | { | ||
49 | ip[0] = m_pos[0]; | ||
50 | if (off == 1) | ||
51 | ip[1] = m_pos[0]; | ||
52 | else | ||
53 | ip[1] = m_pos[1]; | ||
54 | } | ||
55 | |||
56 | static void copy3(uint8_t* ip, const uint8_t* m_pos, unsigned off) | ||
57 | { | ||
58 | ip[0] = m_pos[0]; | ||
59 | if (off == 1) { | ||
60 | ip[2] = ip[1] = m_pos[0]; | ||
61 | } | ||
62 | else if (off == 2) { | ||
63 | ip[1] = m_pos[1]; | ||
64 | ip[2] = m_pos[0]; | ||
65 | } | ||
66 | else { | ||
67 | ip[1] = m_pos[1]; | ||
68 | ip[2] = m_pos[2]; | ||
69 | } | ||
70 | } | ||
71 | |||
72 | /**********************************************************************/ | ||
73 | // optimize a block of data. | ||
74 | /**********************************************************************/ | ||
75 | #define TEST_IP (ip < ip_end) | ||
76 | #define TEST_OP (op <= op_end) | ||
77 | |||
78 | static int lzo1x_optimize(uint8_t *in, unsigned in_len, | ||
79 | uint8_t *out, unsigned *out_len, | ||
80 | void* wrkmem UNUSED_PARAM) | ||
81 | { | ||
82 | uint8_t* op; | ||
83 | uint8_t* ip; | ||
84 | unsigned t; | ||
85 | uint8_t* m_pos; | ||
86 | uint8_t* const ip_end = in + in_len; | ||
87 | uint8_t* const op_end = out + *out_len; | ||
88 | uint8_t* litp = NULL; | ||
89 | unsigned lit = 0; | ||
90 | unsigned next_lit = NO_LIT; | ||
91 | unsigned nl; | ||
92 | unsigned long o_m1_a = 0, o_m1_b = 0, o_m2 = 0, o_m3_a = 0, o_m3_b = 0; | ||
93 | |||
94 | // LZO_UNUSED(wrkmem); | ||
95 | |||
96 | *out_len = 0; | ||
97 | |||
98 | op = out; | ||
99 | ip = in; | ||
100 | |||
101 | if (*ip > 17) { | ||
102 | t = *ip++ - 17; | ||
103 | if (t < 4) | ||
104 | goto match_next; | ||
105 | goto first_literal_run; | ||
106 | } | ||
107 | |||
108 | while (TEST_IP && TEST_OP) { | ||
109 | t = *ip++; | ||
110 | if (t >= 16) | ||
111 | goto match; | ||
112 | /* a literal run */ | ||
113 | litp = ip - 1; | ||
114 | if (t == 0) { | ||
115 | t = 15; | ||
116 | while (*ip == 0) | ||
117 | t += 255, ip++; | ||
118 | t += *ip++; | ||
119 | } | ||
120 | lit = t + 3; | ||
121 | /* copy literals */ | ||
122 | copy_literal_run: | ||
123 | *op++ = *ip++; | ||
124 | *op++ = *ip++; | ||
125 | *op++ = *ip++; | ||
126 | first_literal_run: | ||
127 | do *op++ = *ip++; while (--t > 0); | ||
128 | |||
129 | t = *ip++; | ||
130 | |||
131 | if (t >= 16) | ||
132 | goto match; | ||
133 | #if defined(LZO1X) | ||
134 | m_pos = op - 1 - 0x800; | ||
135 | #elif defined(LZO1Y) | ||
136 | m_pos = op - 1 - 0x400; | ||
137 | #endif | ||
138 | m_pos -= t >> 2; | ||
139 | m_pos -= *ip++ << 2; | ||
140 | *op++ = *m_pos++; | ||
141 | *op++ = *m_pos++; | ||
142 | *op++ = *m_pos++; | ||
143 | lit = 0; | ||
144 | goto match_done; | ||
145 | |||
146 | |||
147 | /* handle matches */ | ||
148 | do { | ||
149 | if (t < 16) { /* a M1 match */ | ||
150 | m_pos = op - 1; | ||
151 | m_pos -= t >> 2; | ||
152 | m_pos -= *ip++ << 2; | ||
153 | |||
154 | if (litp == NULL) | ||
155 | goto copy_m1; | ||
156 | |||
157 | nl = ip[-2] & 3; | ||
158 | /* test if a match follows */ | ||
159 | if (nl == 0 && lit == 1 && ip[0] >= 16) { | ||
160 | next_lit = nl; | ||
161 | /* adjust length of previous short run */ | ||
162 | lit += 2; | ||
163 | *litp = (unsigned char)((*litp & ~3) | lit); | ||
164 | /* copy over the 2 literals that replace the match */ | ||
165 | copy2(ip-2, m_pos, pd(op, m_pos)); | ||
166 | o_m1_a++; | ||
167 | } | ||
168 | /* test if a literal run follows */ | ||
169 | else if (nl == 0 && ip[0] < 16 && ip[0] != 0 && | ||
170 | (lit + 2 + ip[0] < 16)) | ||
171 | { | ||
172 | t = *ip++; | ||
173 | /* remove short run */ | ||
174 | *litp &= ~3; | ||
175 | /* copy over the 2 literals that replace the match */ | ||
176 | copy2(ip-3+1,m_pos,pd(op,m_pos)); | ||
177 | /* move literals 1 byte ahead */ | ||
178 | litp += 2; | ||
179 | if (lit > 0) | ||
180 | memmove(litp+1, litp, lit); | ||
181 | /* insert new length of long literal run */ | ||
182 | lit += 2 + t + 3; | ||
183 | *litp = (unsigned char)(lit - 3); | ||
184 | |||
185 | o_m1_b++; | ||
186 | *op++ = *m_pos++; *op++ = *m_pos++; | ||
187 | goto copy_literal_run; | ||
188 | } | ||
189 | copy_m1: | ||
190 | *op++ = *m_pos++; | ||
191 | *op++ = *m_pos++; | ||
192 | } else { | ||
193 | match: | ||
194 | if (t >= 64) { /* a M2 match */ | ||
195 | m_pos = op - 1; | ||
196 | #if defined(LZO1X) | ||
197 | m_pos -= (t >> 2) & 7; | ||
198 | m_pos -= *ip++ << 3; | ||
199 | t = (t >> 5) - 1; | ||
200 | #elif defined(LZO1Y) | ||
201 | m_pos -= (t >> 2) & 3; | ||
202 | m_pos -= *ip++ << 2; | ||
203 | t = (t >> 4) - 3; | ||
204 | #endif | ||
205 | if (litp == NULL) | ||
206 | goto copy_m; | ||
207 | |||
208 | nl = ip[-2] & 3; | ||
209 | /* test if in beetween two long literal runs */ | ||
210 | if (t == 1 && lit > 3 && nl == 0 | ||
211 | && ip[0] < 16 && ip[0] != 0 && (lit + 3 + ip[0] < 16) | ||
212 | ) { | ||
213 | t = *ip++; | ||
214 | /* copy over the 3 literals that replace the match */ | ||
215 | copy3(ip-1-2,m_pos,pd(op,m_pos)); | ||
216 | /* set new length of previous literal run */ | ||
217 | lit += 3 + t + 3; | ||
218 | *litp = (unsigned char)(lit - 3); | ||
219 | o_m2++; | ||
220 | *op++ = *m_pos++; | ||
221 | *op++ = *m_pos++; | ||
222 | *op++ = *m_pos++; | ||
223 | goto copy_literal_run; | ||
224 | } | ||
225 | } else { | ||
226 | if (t >= 32) { /* a M3 match */ | ||
227 | t &= 31; | ||
228 | if (t == 0) { | ||
229 | t = 31; | ||
230 | while (*ip == 0) | ||
231 | t += 255, ip++; | ||
232 | t += *ip++; | ||
233 | } | ||
234 | m_pos = op - 1; | ||
235 | m_pos -= *ip++ >> 2; | ||
236 | m_pos -= *ip++ << 6; | ||
237 | } else { /* a M4 match */ | ||
238 | m_pos = op; | ||
239 | m_pos -= (t & 8) << 11; | ||
240 | t &= 7; | ||
241 | if (t == 0) { | ||
242 | t = 7; | ||
243 | while (*ip == 0) | ||
244 | t += 255, ip++; | ||
245 | t += *ip++; | ||
246 | } | ||
247 | m_pos -= *ip++ >> 2; | ||
248 | m_pos -= *ip++ << 6; | ||
249 | if (m_pos == op) | ||
250 | goto eof_found; | ||
251 | m_pos -= 0x4000; | ||
252 | } | ||
253 | if (litp == NULL) | ||
254 | goto copy_m; | ||
255 | |||
256 | nl = ip[-2] & 3; | ||
257 | /* test if in beetween two matches */ | ||
258 | if (t == 1 && lit == 0 && nl == 0 && ip[0] >= 16) { | ||
259 | next_lit = nl; | ||
260 | /* make a previous short run */ | ||
261 | lit += 3; | ||
262 | *litp = (unsigned char)((*litp & ~3) | lit); | ||
263 | /* copy over the 3 literals that replace the match */ | ||
264 | copy3(ip-3,m_pos,pd(op,m_pos)); | ||
265 | o_m3_a++; | ||
266 | } | ||
267 | /* test if a literal run follows */ | ||
268 | else if (t == 1 && lit <= 3 && nl == 0 | ||
269 | && ip[0] < 16 && ip[0] != 0 && (lit + 3 + ip[0] < 16) | ||
270 | ) { | ||
271 | t = *ip++; | ||
272 | /* remove short run */ | ||
273 | *litp &= ~3; | ||
274 | /* copy over the 3 literals that replace the match */ | ||
275 | copy3(ip-4+1,m_pos,pd(op,m_pos)); | ||
276 | /* move literals 1 byte ahead */ | ||
277 | litp += 2; | ||
278 | if (lit > 0) | ||
279 | memmove(litp+1,litp,lit); | ||
280 | /* insert new length of long literal run */ | ||
281 | lit += 3 + t + 3; | ||
282 | *litp = (unsigned char)(lit - 3); | ||
283 | |||
284 | o_m3_b++; | ||
285 | *op++ = *m_pos++; | ||
286 | *op++ = *m_pos++; | ||
287 | *op++ = *m_pos++; | ||
288 | goto copy_literal_run; | ||
289 | } | ||
290 | } | ||
291 | copy_m: | ||
292 | *op++ = *m_pos++; | ||
293 | *op++ = *m_pos++; | ||
294 | do *op++ = *m_pos++; while (--t > 0); | ||
295 | } | ||
296 | |||
297 | match_done: | ||
298 | if (next_lit == NO_LIT) { | ||
299 | t = ip[-2] & 3; | ||
300 | lit = t; | ||
301 | litp = ip - 2; | ||
302 | } | ||
303 | else | ||
304 | t = next_lit; | ||
305 | next_lit = NO_LIT; | ||
306 | if (t == 0) | ||
307 | break; | ||
308 | /* copy literals */ | ||
309 | match_next: | ||
310 | do *op++ = *ip++; while (--t > 0); | ||
311 | t = *ip++; | ||
312 | } while (TEST_IP && TEST_OP); | ||
313 | } | ||
314 | |||
315 | /* no EOF code was found */ | ||
316 | *out_len = pd(op, out); | ||
317 | return LZO_E_EOF_NOT_FOUND; | ||
318 | |||
319 | eof_found: | ||
320 | // LZO_UNUSED(o_m1_a); LZO_UNUSED(o_m1_b); LZO_UNUSED(o_m2); | ||
321 | // LZO_UNUSED(o_m3_a); LZO_UNUSED(o_m3_b); | ||
322 | *out_len = pd(op, out); | ||
323 | return (ip == ip_end ? LZO_E_OK : | ||
324 | (ip < ip_end ? LZO_E_INPUT_NOT_CONSUMED : LZO_E_INPUT_OVERRUN)); | ||
325 | } | ||
326 | |||
327 | /**********************************************************************/ | ||
328 | #define F_OS F_OS_UNIX | ||
329 | #define F_CS F_CS_NATIVE | ||
330 | |||
331 | /**********************************************************************/ | ||
332 | #define ADLER32_INIT_VALUE 1 | ||
333 | #define CRC32_INIT_VALUE 0 | ||
334 | |||
335 | /**********************************************************************/ | ||
336 | enum { | ||
337 | M_LZO1X_1 = 1, | ||
338 | M_LZO1X_1_15 = 2, | ||
339 | M_LZO1X_999 = 3, | ||
340 | }; | ||
341 | |||
342 | /**********************************************************************/ | ||
343 | /* header flags */ | ||
344 | #define F_ADLER32_D 0x00000001L | ||
345 | #define F_ADLER32_C 0x00000002L | ||
346 | #define F_H_EXTRA_FIELD 0x00000040L | ||
347 | #define F_H_GMTDIFF 0x00000080L | ||
348 | #define F_CRC32_D 0x00000100L | ||
349 | #define F_CRC32_C 0x00000200L | ||
350 | #define F_H_FILTER 0x00000800L | ||
351 | #define F_H_CRC32 0x00001000L | ||
352 | #define F_MASK 0x00003FFFL | ||
353 | |||
354 | /* operating system & file system that created the file [mostly unused] */ | ||
355 | #define F_OS_UNIX 0x03000000L | ||
356 | #define F_OS_SHIFT 24 | ||
357 | #define F_OS_MASK 0xff000000L | ||
358 | |||
359 | /* character set for file name encoding [mostly unused] */ | ||
360 | #define F_CS_NATIVE 0x00000000L | ||
361 | #define F_CS_SHIFT 20 | ||
362 | #define F_CS_MASK 0x00f00000L | ||
363 | |||
364 | /* these bits must be zero */ | ||
365 | #define F_RESERVED ((F_MASK | F_OS_MASK | F_CS_MASK) ^ 0xffffffffL) | ||
366 | |||
367 | typedef struct chksum_t { | ||
368 | uint32_t f_adler32; | ||
369 | uint32_t f_crc32; | ||
370 | } chksum_t; | ||
371 | |||
372 | typedef struct header_t { | ||
373 | unsigned version; | ||
374 | unsigned lib_version; | ||
375 | unsigned version_needed_to_extract; | ||
376 | uint32_t flags; | ||
377 | uint32_t mode; | ||
378 | uint32_t mtime; | ||
379 | uint32_t gmtdiff; | ||
380 | uint32_t header_checksum; | ||
381 | |||
382 | uint32_t extra_field_len; | ||
383 | uint32_t extra_field_checksum; | ||
384 | |||
385 | unsigned char method; | ||
386 | unsigned char level; | ||
387 | |||
388 | /* info */ | ||
389 | char name[255+1]; | ||
390 | } header_t; | ||
391 | |||
392 | struct globals { | ||
393 | const uint32_t *lzo_crc32_table; | ||
394 | chksum_t chksum_in; | ||
395 | chksum_t chksum_out; | ||
396 | }; | ||
397 | #define G (*(struct globals*)&bb_common_bufsiz1) | ||
398 | #define INIT_G() do { } while (0) | ||
399 | //#define G (*ptr_to_globals) | ||
400 | //#define INIT_G() do { | ||
401 | // SET_PTR_TO_GLOBALS(xzalloc(sizeof(G))); | ||
402 | //} while (0) | ||
403 | |||
404 | |||
405 | /**********************************************************************/ | ||
406 | #define LZOP_VERSION 0x1010 | ||
407 | //#define LZOP_VERSION_STRING "1.01" | ||
408 | //#define LZOP_VERSION_DATE "Apr 27th 2003" | ||
409 | |||
410 | #define OPTION_STRING "cfvdt123456789CF" | ||
411 | |||
412 | enum { | ||
413 | OPT_STDOUT = (1 << 0), | ||
414 | OPT_FORCE = (1 << 1), | ||
415 | OPT_VERBOSE = (1 << 2), | ||
416 | OPT_DECOMPRESS = (1 << 3), | ||
417 | OPT_TEST = (1 << 4), | ||
418 | OPT_1 = (1 << 5), | ||
419 | OPT_2 = (1 << 6), | ||
420 | OPT_3 = (1 << 7), | ||
421 | OPT_4 = (1 << 8), | ||
422 | OPT_5 = (1 << 9), | ||
423 | OPT_6 = (1 << 10), | ||
424 | OPT_789 = (7 << 11), | ||
425 | OPT_7 = (1 << 11), | ||
426 | OPT_8 = (1 << 12), | ||
427 | OPT_C = (1 << 14), | ||
428 | OPT_F = (1 << 15), | ||
429 | }; | ||
430 | |||
431 | /**********************************************************************/ | ||
432 | // adler32 checksum | ||
433 | // adapted from free code by Mark Adler <madler@alumni.caltech.edu> | ||
434 | // see http://www.zlib.org/ | ||
435 | /**********************************************************************/ | ||
436 | static FAST_FUNC uint32_t | ||
437 | lzo_adler32(uint32_t adler, const uint8_t* buf, unsigned len) | ||
438 | { | ||
439 | enum { | ||
440 | LZO_BASE = 65521, /* largest prime smaller than 65536 */ | ||
441 | /* NMAX is the largest n such that | ||
442 | * 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1 */ | ||
443 | LZO_NMAX = 5552, | ||
444 | }; | ||
445 | uint32_t s1 = adler & 0xffff; | ||
446 | uint32_t s2 = (adler >> 16) & 0xffff; | ||
447 | unsigned k; | ||
448 | |||
449 | if (buf == NULL) | ||
450 | return 1; | ||
451 | |||
452 | while (len > 0) { | ||
453 | k = len < LZO_NMAX ? (unsigned) len : LZO_NMAX; | ||
454 | len -= k; | ||
455 | if (k != 0) do { | ||
456 | s1 += *buf++; | ||
457 | s2 += s1; | ||
458 | } while (--k > 0); | ||
459 | s1 %= LZO_BASE; | ||
460 | s2 %= LZO_BASE; | ||
461 | } | ||
462 | return (s2 << 16) | s1; | ||
463 | } | ||
464 | |||
465 | static FAST_FUNC uint32_t | ||
466 | lzo_crc32(uint32_t c, const uint8_t* buf, unsigned len) | ||
467 | { | ||
468 | uint32_t crc; | ||
469 | |||
470 | if (buf == NULL) | ||
471 | return 0; | ||
472 | |||
473 | crc = ~c; | ||
474 | if (len != 0) do { | ||
475 | crc = G.lzo_crc32_table[((int)crc ^ *buf) & 0xff] ^ (crc >> 8); | ||
476 | buf += 1; | ||
477 | len -= 1; | ||
478 | } while (len > 0); | ||
479 | |||
480 | return ~crc; | ||
481 | } | ||
482 | |||
483 | /**********************************************************************/ | ||
484 | static void init_chksum(chksum_t *ct) | ||
485 | { | ||
486 | ct->f_adler32 = ADLER32_INIT_VALUE; | ||
487 | ct->f_crc32 = CRC32_INIT_VALUE; | ||
488 | } | ||
489 | |||
490 | static void add_bytes_to_chksum(chksum_t *ct, const void* buf, int cnt) | ||
491 | { | ||
492 | /* We need to handle the two checksums at once, because at the | ||
493 | * beginning of the header, we don't know yet which one we'll | ||
494 | * eventually need */ | ||
495 | ct->f_adler32 = lzo_adler32(ct->f_adler32, (const uint8_t*)buf, cnt); | ||
496 | ct->f_crc32 = lzo_crc32(ct->f_crc32, (const uint8_t*)buf, cnt); | ||
497 | } | ||
498 | |||
499 | static uint32_t chksum_getresult(chksum_t *ct, const header_t *h) | ||
500 | { | ||
501 | return (h->flags & F_H_CRC32) ? ct->f_crc32 : ct->f_adler32; | ||
502 | } | ||
503 | |||
504 | /**********************************************************************/ | ||
505 | static uint32_t read32(void) | ||
506 | { | ||
507 | uint32_t v; | ||
508 | xread(0, &v, 4); | ||
509 | return ntohl(v); | ||
510 | } | ||
511 | |||
512 | static void write32(uint32_t v) | ||
513 | { | ||
514 | v = htonl(v); | ||
515 | xwrite(1, &v, 4); | ||
516 | } | ||
517 | |||
518 | static void f_write(const void* buf, int cnt) | ||
519 | { | ||
520 | xwrite(1, buf, cnt); | ||
521 | add_bytes_to_chksum(&G.chksum_out, buf, cnt); | ||
522 | } | ||
523 | |||
524 | static void f_read(void* buf, int cnt) | ||
525 | { | ||
526 | xread(0, buf, cnt); | ||
527 | add_bytes_to_chksum(&G.chksum_in, buf, cnt); | ||
528 | } | ||
529 | |||
530 | static int f_read8(void) | ||
531 | { | ||
532 | uint8_t v; | ||
533 | f_read(&v, 1); | ||
534 | return v; | ||
535 | } | ||
536 | |||
537 | static void f_write8(uint8_t v) | ||
538 | { | ||
539 | f_write(&v, 1); | ||
540 | } | ||
541 | |||
542 | static unsigned f_read16(void) | ||
543 | { | ||
544 | uint16_t v; | ||
545 | f_read(&v, 2); | ||
546 | return ntohs(v); | ||
547 | } | ||
548 | |||
549 | static void f_write16(uint16_t v) | ||
550 | { | ||
551 | v = htons(v); | ||
552 | f_write(&v, 2); | ||
553 | } | ||
554 | |||
555 | static uint32_t f_read32(void) | ||
556 | { | ||
557 | uint32_t v; | ||
558 | f_read(&v, 4); | ||
559 | return ntohl(v); | ||
560 | } | ||
561 | |||
562 | static void f_write32(uint32_t v) | ||
563 | { | ||
564 | v = htonl(v); | ||
565 | f_write(&v, 4); | ||
566 | } | ||
567 | |||
568 | /**********************************************************************/ | ||
569 | static int lzo_get_method(header_t *h) | ||
570 | { | ||
571 | /* check method */ | ||
572 | if (h->method == M_LZO1X_1) { | ||
573 | if (h->level == 0) | ||
574 | h->level = 3; | ||
575 | } else if (h->method == M_LZO1X_1_15) { | ||
576 | if (h->level == 0) | ||
577 | h->level = 1; | ||
578 | } else if (h->method == M_LZO1X_999) { | ||
579 | if (h->level == 0) | ||
580 | h->level = 9; | ||
581 | } else | ||
582 | return -1; /* not a LZO method */ | ||
583 | |||
584 | /* check compression level */ | ||
585 | if (h->level < 1 || h->level > 9) | ||
586 | return 15; | ||
587 | |||
588 | return 0; | ||
589 | } | ||
590 | |||
591 | /**********************************************************************/ | ||
592 | #define LZO_BLOCK_SIZE (256 * 1024l) | ||
593 | #define MAX_BLOCK_SIZE (64 * 1024l * 1024l) /* DO NOT CHANGE */ | ||
594 | |||
595 | /* LZO may expand uncompressible data by a small amount */ | ||
596 | #define MAX_COMPRESSED_SIZE(x) ((x) + (x) / 16 + 64 + 3) | ||
597 | |||
598 | /**********************************************************************/ | ||
599 | // compress a file | ||
600 | /**********************************************************************/ | ||
601 | static smallint lzo_compress(const header_t *h) | ||
602 | { | ||
603 | unsigned block_size = LZO_BLOCK_SIZE; | ||
604 | int r = 0; /* LZO_E_OK */ | ||
605 | uint8_t *const b1 = xzalloc(block_size); | ||
606 | uint8_t *const b2 = xzalloc(MAX_COMPRESSED_SIZE(block_size)); | ||
607 | unsigned src_len = 0, dst_len = 0; | ||
608 | uint32_t d_adler32 = ADLER32_INIT_VALUE; | ||
609 | uint32_t d_crc32 = CRC32_INIT_VALUE; | ||
610 | int l; | ||
611 | smallint ok = 1; | ||
612 | uint8_t *wrk_mem = NULL; | ||
613 | |||
614 | if (h->method == M_LZO1X_1) | ||
615 | wrk_mem = xzalloc(LZO1X_1_MEM_COMPRESS); | ||
616 | else if (h->method == M_LZO1X_1_15) | ||
617 | wrk_mem = xzalloc(LZO1X_1_15_MEM_COMPRESS); | ||
618 | else if (h->method == M_LZO1X_999) | ||
619 | wrk_mem = xzalloc(LZO1X_999_MEM_COMPRESS); | ||
620 | |||
621 | for (;;) { | ||
622 | /* read a block */ | ||
623 | l = full_read(0, b1, block_size); | ||
624 | src_len = (l > 0 ? l : 0); | ||
625 | |||
626 | /* write uncompressed block size */ | ||
627 | write32(src_len); | ||
628 | |||
629 | /* exit if last block */ | ||
630 | if (src_len == 0) | ||
631 | break; | ||
632 | |||
633 | /* compute checksum of uncompressed block */ | ||
634 | if (h->flags & F_ADLER32_D) | ||
635 | d_adler32 = lzo_adler32(ADLER32_INIT_VALUE, b1, src_len); | ||
636 | if (h->flags & F_CRC32_D) | ||
637 | d_crc32 = lzo_crc32(CRC32_INIT_VALUE, b1, src_len); | ||
638 | |||
639 | /* compress */ | ||
640 | if (h->method == M_LZO1X_1) | ||
641 | r = lzo1x_1_compress(b1, src_len, b2, &dst_len, wrk_mem); | ||
642 | else if (h->method == M_LZO1X_1_15) | ||
643 | r = lzo1x_1_15_compress(b1, src_len, b2, &dst_len, wrk_mem); | ||
644 | #if ENABLE_LZOP_COMPR_HIGH | ||
645 | else if (h->method == M_LZO1X_999) | ||
646 | r = lzo1x_999_compress_level(b1, src_len, b2, &dst_len, | ||
647 | wrk_mem, h->level); | ||
648 | #endif | ||
649 | else | ||
650 | bb_error_msg_and_die("internal error"); | ||
651 | |||
652 | if (r != 0) /* not LZO_E_OK */ | ||
653 | bb_error_msg_and_die("internal error - compression failed"); | ||
654 | |||
655 | /* write compressed block size */ | ||
656 | if (dst_len < src_len) { | ||
657 | /* optimize */ | ||
658 | if (h->method == M_LZO1X_999) { | ||
659 | unsigned new_len = src_len; | ||
660 | r = lzo1x_optimize(b2, dst_len, b1, &new_len, NULL); | ||
661 | if (r != 0 /*LZO_E_OK*/ || new_len != src_len) | ||
662 | bb_error_msg_and_die("internal error - optimization failed"); | ||
663 | } | ||
664 | write32(dst_len); | ||
665 | } else { | ||
666 | /* data actually expanded => store data uncompressed */ | ||
667 | write32(src_len); | ||
668 | } | ||
669 | |||
670 | /* write checksum of uncompressed block */ | ||
671 | if (h->flags & F_ADLER32_D) | ||
672 | write32(d_adler32); | ||
673 | if (h->flags & F_CRC32_D) | ||
674 | write32(d_crc32); | ||
675 | |||
676 | if (dst_len < src_len) { | ||
677 | /* write checksum of compressed block */ | ||
678 | if (h->flags & F_ADLER32_C) | ||
679 | write32(lzo_adler32(ADLER32_INIT_VALUE, b2, | ||
680 | dst_len)); | ||
681 | if (h->flags & F_CRC32_C) | ||
682 | write32(lzo_crc32(CRC32_INIT_VALUE, b2, dst_len)); | ||
683 | /* write compressed block data */ | ||
684 | xwrite(1, b2, dst_len); | ||
685 | } else { | ||
686 | /* write uncompressed block data */ | ||
687 | xwrite(1, b1, src_len); | ||
688 | } | ||
689 | } | ||
690 | |||
691 | free(wrk_mem); | ||
692 | free(b1); | ||
693 | free(b2); | ||
694 | return ok; | ||
695 | } | ||
696 | |||
697 | static void lzo_check(uint32_t FAST_FUNC (*fn)(uint32_t, const uint8_t*, unsigned), | ||
698 | uint32_t ref, uint32_t init, | ||
699 | uint8_t* buf, unsigned len) | ||
700 | { | ||
701 | uint32_t c = fn(init, buf, len); | ||
702 | if (c != ref) | ||
703 | bb_error_msg_and_die("checksum error"); | ||
704 | } | ||
705 | |||
706 | /**********************************************************************/ | ||
707 | // decompress a file | ||
708 | /**********************************************************************/ | ||
709 | static smallint lzo_decompress(const header_t *h) | ||
710 | { | ||
711 | unsigned block_size = LZO_BLOCK_SIZE; | ||
712 | int r; | ||
713 | uint32_t src_len, dst_len; | ||
714 | uint32_t c_adler32 = ADLER32_INIT_VALUE; | ||
715 | uint32_t d_adler32 = ADLER32_INIT_VALUE; | ||
716 | uint32_t c_crc32 = CRC32_INIT_VALUE, d_crc32 = CRC32_INIT_VALUE; | ||
717 | smallint ok = 1; | ||
718 | uint8_t *b1; | ||
719 | uint32_t mcs_block_size = MAX_COMPRESSED_SIZE(block_size); | ||
720 | uint8_t *b2 = NULL; | ||
721 | |||
722 | for (;;) { | ||
723 | uint8_t *dst; | ||
724 | |||
725 | /* read uncompressed block size */ | ||
726 | dst_len = read32(); | ||
727 | |||
728 | /* exit if last block */ | ||
729 | if (dst_len == 0) | ||
730 | break; | ||
731 | |||
732 | /* error if split file */ | ||
733 | if (dst_len == 0xffffffffL) | ||
734 | /* should not happen - not yet implemented */ | ||
735 | bb_error_msg_and_die("this file is a split lzop file"); | ||
736 | |||
737 | if (dst_len > MAX_BLOCK_SIZE) | ||
738 | bb_error_msg_and_die("lzop file corrupted"); | ||
739 | |||
740 | /* read compressed block size */ | ||
741 | src_len = read32(); | ||
742 | if (src_len <= 0 || src_len > dst_len) | ||
743 | bb_error_msg_and_die("lzop file corrupted"); | ||
744 | |||
745 | if (dst_len > block_size) { | ||
746 | if (b2) { | ||
747 | //FIXME! | ||
748 | b2 = NULL; | ||
749 | free(b2); | ||
750 | } | ||
751 | block_size = dst_len; | ||
752 | mcs_block_size = MAX_COMPRESSED_SIZE(block_size); | ||
753 | } | ||
754 | |||
755 | /* read checksum of uncompressed block */ | ||
756 | if (h->flags & F_ADLER32_D) | ||
757 | d_adler32 = read32(); | ||
758 | if (h->flags & F_CRC32_D) | ||
759 | d_crc32 = read32(); | ||
760 | |||
761 | /* read checksum of compressed block */ | ||
762 | if (src_len < dst_len) { | ||
763 | if (h->flags & F_ADLER32_C) | ||
764 | c_adler32 = read32(); | ||
765 | if (h->flags & F_CRC32_C) | ||
766 | c_crc32 = read32(); | ||
767 | } | ||
768 | |||
769 | if (b2 == NULL) | ||
770 | b2 = xzalloc(mcs_block_size); | ||
771 | /* read the block into the end of our buffer */ | ||
772 | b1 = b2 + mcs_block_size - src_len; | ||
773 | xread(0, b1, src_len); | ||
774 | |||
775 | if (src_len < dst_len) { | ||
776 | unsigned d = dst_len; | ||
777 | |||
778 | if (!(option_mask32 & OPT_F)) { | ||
779 | /* verify checksum of compressed block */ | ||
780 | if (h->flags & F_ADLER32_C) | ||
781 | lzo_check(lzo_adler32, c_adler32, | ||
782 | ADLER32_INIT_VALUE, | ||
783 | b1, src_len); | ||
784 | if (h->flags & F_CRC32_C) | ||
785 | lzo_check(lzo_crc32, c_crc32, | ||
786 | CRC32_INIT_VALUE, | ||
787 | b1, src_len); | ||
788 | } | ||
789 | |||
790 | /* decompress */ | ||
791 | // if (option_mask32 & OPT_F) | ||
792 | // r = lzo1x_decompress(b1, src_len, b2, &d, NULL); | ||
793 | // else | ||
794 | r = lzo1x_decompress_safe(b1, src_len, b2, &d, NULL); | ||
795 | |||
796 | if (r != 0 /*LZO_E_OK*/ || dst_len != d) { | ||
797 | bb_error_msg_and_die("corrupted compressed data"); | ||
798 | } | ||
799 | dst = b2; | ||
800 | } else { | ||
801 | /* "stored" block => no decompression */ | ||
802 | dst = b1; | ||
803 | } | ||
804 | |||
805 | if (!(option_mask32 & OPT_F)) { | ||
806 | /* verify checksum of uncompressed block */ | ||
807 | if (h->flags & F_ADLER32_D) | ||
808 | lzo_check(lzo_adler32, d_adler32, ADLER32_INIT_VALUE, | ||
809 | dst, dst_len); | ||
810 | if (h->flags & F_CRC32_D) | ||
811 | lzo_check(lzo_crc32, d_crc32, CRC32_INIT_VALUE, | ||
812 | dst, dst_len); | ||
813 | } | ||
814 | |||
815 | /* write uncompressed block data */ | ||
816 | xwrite(1, dst, dst_len); | ||
817 | } | ||
818 | |||
819 | free(b2); | ||
820 | return ok; | ||
821 | } | ||
822 | |||
823 | /**********************************************************************/ | ||
824 | // lzop file signature (shamelessly borrowed from PNG) | ||
825 | /**********************************************************************/ | ||
826 | /* | ||
827 | * The first nine bytes of a lzop file always contain the following values: | ||
828 | * | ||
829 | * 0 1 2 3 4 5 6 7 8 | ||
830 | * --- --- --- --- --- --- --- --- --- | ||
831 | * (hex) 89 4c 5a 4f 00 0d 0a 1a 0a | ||
832 | * (decimal) 137 76 90 79 0 13 10 26 10 | ||
833 | * (C notation - ASCII) \211 L Z O \0 \r \n \032 \n | ||
834 | */ | ||
835 | |||
836 | /* (vda) comparison with lzop v1.02rc1 ("lzop -1 <FILE" cmd): | ||
837 | * Only slight differences in header: | ||
838 | * -00000000 89 4c 5a 4f 00 0d 0a 1a 0a 10 20 20 20 09 40 02 | ||
839 | * +00000000 89 4c 5a 4f 00 0d 0a 1a 0a 10 10 20 30 09 40 02 | ||
840 | * ^^^^^ ^^^^^ | ||
841 | * version lib_version | ||
842 | * -00000010 01 03 00 00 0d 00 00 81 a4 49 f7 a6 3f 00 00 00 | ||
843 | * +00000010 01 03 00 00 01 00 00 00 00 00 00 00 00 00 00 00 | ||
844 | * ^^^^^^^^^^^ ^^^^^^^^^^^ ^^^^^^^^^^^ | ||
845 | * flags mode mtime | ||
846 | * -00000020 00 00 2d 67 04 17 00 04 00 00 00 03 ed ec 9d 6d | ||
847 | * +00000020 00 00 10 5f 00 c1 00 04 00 00 00 03 ed ec 9d 6d | ||
848 | * ^^^^^^^^^^^ | ||
849 | * chksum_out | ||
850 | * The rest is identical. | ||
851 | */ | ||
852 | static const unsigned char lzop_magic[9] = { | ||
853 | 0x89, 0x4c, 0x5a, 0x4f, 0x00, 0x0d, 0x0a, 0x1a, 0x0a | ||
854 | }; | ||
855 | |||
856 | /* This coding is derived from Alexander Lehmann's pngcheck code. */ | ||
857 | static void check_magic(void) | ||
858 | { | ||
859 | unsigned char magic[sizeof(lzop_magic)]; | ||
860 | xread(0, magic, sizeof(magic)); | ||
861 | if (memcmp(magic, lzop_magic, sizeof(lzop_magic)) != 0) | ||
862 | bb_error_msg_and_die("bad magic number"); | ||
863 | } | ||
864 | |||
865 | /**********************************************************************/ | ||
866 | // lzop file header | ||
867 | /**********************************************************************/ | ||
868 | static void write_header(const header_t *h) | ||
869 | { | ||
870 | int l; | ||
871 | |||
872 | xwrite(1, lzop_magic, sizeof(lzop_magic)); | ||
873 | |||
874 | init_chksum(&G.chksum_out); | ||
875 | |||
876 | f_write16(h->version); | ||
877 | f_write16(h->lib_version); | ||
878 | f_write16(h->version_needed_to_extract); | ||
879 | f_write8(h->method); | ||
880 | f_write8(h->level); | ||
881 | f_write32(h->flags); | ||
882 | f_write32(h->mode); | ||
883 | f_write32(h->mtime); | ||
884 | f_write32(h->gmtdiff); | ||
885 | |||
886 | l = (int) strlen(h->name); | ||
887 | f_write8(l); | ||
888 | if (l) | ||
889 | f_write(h->name, l); | ||
890 | |||
891 | f_write32(chksum_getresult(&G.chksum_out, h)); | ||
892 | } | ||
893 | |||
894 | static int read_header(header_t *h) | ||
895 | { | ||
896 | int r; | ||
897 | int l; | ||
898 | uint32_t checksum; | ||
899 | |||
900 | memset(h, 0, sizeof(*h)); | ||
901 | h->version_needed_to_extract = 0x0900; /* first lzop version */ | ||
902 | h->level = 0; | ||
903 | |||
904 | init_chksum(&G.chksum_in); | ||
905 | |||
906 | h->version = f_read16(); | ||
907 | if (h->version < 0x0900) | ||
908 | return 3; | ||
909 | h->lib_version = f_read16(); | ||
910 | if (h->version >= 0x0940) { | ||
911 | h->version_needed_to_extract = f_read16(); | ||
912 | if (h->version_needed_to_extract > LZOP_VERSION) | ||
913 | return 16; | ||
914 | if (h->version_needed_to_extract < 0x0900) | ||
915 | return 3; | ||
916 | } | ||
917 | h->method = f_read8(); | ||
918 | if (h->version >= 0x0940) | ||
919 | h->level = f_read8(); | ||
920 | h->flags = f_read32(); | ||
921 | if (h->flags & F_H_FILTER) | ||
922 | return 16; /* filter not supported */ | ||
923 | h->mode = f_read32(); | ||
924 | h->mtime = f_read32(); | ||
925 | if (h->version >= 0x0940) | ||
926 | h->gmtdiff = f_read32(); | ||
927 | |||
928 | l = f_read8(); | ||
929 | if (l > 0) | ||
930 | f_read(h->name, l); | ||
931 | h->name[l] = 0; | ||
932 | |||
933 | checksum = chksum_getresult(&G.chksum_in, h); | ||
934 | h->header_checksum = f_read32(); | ||
935 | if (h->header_checksum != checksum) | ||
936 | return 2; | ||
937 | |||
938 | if (h->method <= 0) | ||
939 | return 14; | ||
940 | r = lzo_get_method(h); | ||
941 | if (r != 0) | ||
942 | return r; | ||
943 | |||
944 | /* check reserved flags */ | ||
945 | if (h->flags & F_RESERVED) | ||
946 | return -13; | ||
947 | |||
948 | /* skip extra field [not used yet] */ | ||
949 | if (h->flags & F_H_EXTRA_FIELD) { | ||
950 | uint32_t k; | ||
951 | |||
952 | /* note: the checksum also covers the length */ | ||
953 | init_chksum(&G.chksum_in); | ||
954 | h->extra_field_len = f_read32(); | ||
955 | for (k = 0; k < h->extra_field_len; k++) | ||
956 | f_read8(); | ||
957 | checksum = chksum_getresult(&G.chksum_in, h); | ||
958 | h->extra_field_checksum = f_read32(); | ||
959 | if (h->extra_field_checksum != checksum) | ||
960 | return 3; | ||
961 | } | ||
962 | |||
963 | return 0; | ||
964 | } | ||
965 | |||
966 | static void p_header(header_t *h) | ||
967 | { | ||
968 | int r; | ||
969 | |||
970 | r = read_header(h); | ||
971 | if (r == 0) | ||
972 | return; | ||
973 | bb_error_msg_and_die("header_error %d", r); | ||
974 | } | ||
975 | |||
976 | /**********************************************************************/ | ||
977 | // compress | ||
978 | /**********************************************************************/ | ||
979 | static void lzo_set_method(header_t *h) | ||
980 | { | ||
981 | int level = 1; | ||
982 | |||
983 | if (option_mask32 & OPT_1) { | ||
984 | h->method = M_LZO1X_1_15; | ||
985 | } else if (option_mask32 & OPT_789) { | ||
986 | #if ENABLE_LZOP_COMPR_HIGH | ||
987 | h->method = M_LZO1X_999; | ||
988 | if (option_mask32 & OPT_7) | ||
989 | level = 7; | ||
990 | else if (option_mask32 & OPT_8) | ||
991 | level = 8; | ||
992 | else | ||
993 | level = 9; | ||
994 | #else | ||
995 | bb_error_msg_and_die("high compression not compiled in"); | ||
996 | #endif | ||
997 | } else { /* levels 2..6 or none (defaults to level 3) */ | ||
998 | h->method = M_LZO1X_1; | ||
999 | level = 5; /* levels 2-6 are actually the same */ | ||
1000 | } | ||
1001 | |||
1002 | h->level = level; | ||
1003 | } | ||
1004 | |||
1005 | static smallint do_lzo_compress(void) | ||
1006 | { | ||
1007 | header_t header; | ||
1008 | |||
1009 | #define h (&header) | ||
1010 | memset(h, 0, sizeof(*h)); | ||
1011 | |||
1012 | lzo_set_method(h); | ||
1013 | |||
1014 | h->version = (LZOP_VERSION & 0xffff); | ||
1015 | h->version_needed_to_extract = 0x0940; | ||
1016 | h->lib_version = lzo_version() & 0xffff; | ||
1017 | |||
1018 | h->flags = (F_OS & F_OS_MASK) | (F_CS & F_CS_MASK); | ||
1019 | |||
1020 | if (!(option_mask32 & OPT_F) || h->method == M_LZO1X_999) { | ||
1021 | h->flags |= F_ADLER32_D; | ||
1022 | if (option_mask32 & OPT_C) | ||
1023 | h->flags |= F_ADLER32_C; | ||
1024 | } | ||
1025 | write_header(h); | ||
1026 | return lzo_compress(h); | ||
1027 | #undef h | ||
1028 | } | ||
1029 | |||
1030 | /**********************************************************************/ | ||
1031 | // decompress | ||
1032 | /**********************************************************************/ | ||
1033 | static smallint do_lzo_decompress(void) | ||
1034 | { | ||
1035 | header_t header; | ||
1036 | |||
1037 | check_magic(); | ||
1038 | p_header(&header); | ||
1039 | return lzo_decompress(&header); | ||
1040 | } | ||
1041 | |||
1042 | static char* make_new_name_lzop(char *filename) | ||
1043 | { | ||
1044 | if (option_mask32 & OPT_DECOMPRESS) { | ||
1045 | char *extension = strrchr(filename, '.'); | ||
1046 | if (!extension || strcmp(extension + 1, "lzo") != 0) | ||
1047 | return xasprintf("%s.out", filename); | ||
1048 | *extension = '\0'; | ||
1049 | return filename; | ||
1050 | } | ||
1051 | return xasprintf("%s.lzo", filename); | ||
1052 | } | ||
1053 | |||
1054 | static IF_DESKTOP(long long) int pack_lzop(unpack_info_t *info UNUSED_PARAM) | ||
1055 | { | ||
1056 | if (option_mask32 & OPT_DECOMPRESS) | ||
1057 | return do_lzo_decompress(); | ||
1058 | return do_lzo_compress(); | ||
1059 | } | ||
1060 | |||
1061 | int lzop_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | ||
1062 | int lzop_main(int argc UNUSED_PARAM, char **argv) | ||
1063 | { | ||
1064 | getopt32(argv, OPTION_STRING); | ||
1065 | argv += optind; | ||
1066 | /* lzopcat? */ | ||
1067 | if (applet_name[4] == 'c') | ||
1068 | option_mask32 |= (OPT_STDOUT | OPT_DECOMPRESS); | ||
1069 | /* unlzop? */ | ||
1070 | if (applet_name[0] == 'u') | ||
1071 | option_mask32 |= OPT_DECOMPRESS; | ||
1072 | |||
1073 | G.lzo_crc32_table = crc32_filltable(NULL, 0); | ||
1074 | return bbunpack(argv, make_new_name_lzop, pack_lzop); | ||
1075 | } | ||
diff --git a/include/applets.h b/include/applets.h index a41f75e31..359440def 100644 --- a/include/applets.h +++ b/include/applets.h | |||
@@ -242,6 +242,8 @@ IF_LSATTR(APPLET(lsattr, _BB_DIR_BIN, _BB_SUID_NEVER)) | |||
242 | IF_LSMOD(APPLET(lsmod, _BB_DIR_SBIN, _BB_SUID_NEVER)) | 242 | IF_LSMOD(APPLET(lsmod, _BB_DIR_SBIN, _BB_SUID_NEVER)) |
243 | IF_MODPROBE_SMALL(APPLET_ODDNAME(lsmod, modprobe, _BB_DIR_SBIN, _BB_SUID_NEVER, modprobe)) | 243 | IF_MODPROBE_SMALL(APPLET_ODDNAME(lsmod, modprobe, _BB_DIR_SBIN, _BB_SUID_NEVER, modprobe)) |
244 | IF_UNLZMA(APPLET_ODDNAME(lzmacat, unlzma, _BB_DIR_USR_BIN, _BB_SUID_NEVER, lzmacat)) | 244 | IF_UNLZMA(APPLET_ODDNAME(lzmacat, unlzma, _BB_DIR_USR_BIN, _BB_SUID_NEVER, lzmacat)) |
245 | IF_LZOP(APPLET(lzop, _BB_DIR_BIN, _BB_SUID_NEVER)) | ||
246 | IF_LZOP(APPLET_ODDNAME(lzopcat, lzop, _BB_DIR_USR_BIN, _BB_SUID_NEVER, lzopcat)) | ||
245 | IF_MAKEDEVS(APPLET(makedevs, _BB_DIR_SBIN, _BB_SUID_NEVER)) | 247 | IF_MAKEDEVS(APPLET(makedevs, _BB_DIR_SBIN, _BB_SUID_NEVER)) |
246 | IF_MAKEMIME(APPLET(makemime, _BB_DIR_BIN, _BB_SUID_NEVER)) | 248 | IF_MAKEMIME(APPLET(makemime, _BB_DIR_BIN, _BB_SUID_NEVER)) |
247 | IF_MAN(APPLET(man, _BB_DIR_SBIN, _BB_SUID_NEVER)) | 249 | 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 | |||
401 | IF_UNIQ(APPLET(uniq, _BB_DIR_USR_BIN, _BB_SUID_NEVER)) | 403 | IF_UNIQ(APPLET(uniq, _BB_DIR_USR_BIN, _BB_SUID_NEVER)) |
402 | IF_UNIX2DOS(APPLET_ODDNAME(unix2dos, dos2unix, _BB_DIR_USR_BIN, _BB_SUID_NEVER, unix2dos)) | 404 | IF_UNIX2DOS(APPLET_ODDNAME(unix2dos, dos2unix, _BB_DIR_USR_BIN, _BB_SUID_NEVER, unix2dos)) |
403 | IF_UNLZMA(APPLET(unlzma, _BB_DIR_USR_BIN, _BB_SUID_NEVER)) | 405 | IF_UNLZMA(APPLET(unlzma, _BB_DIR_USR_BIN, _BB_SUID_NEVER)) |
406 | IF_LZOP(APPLET_ODDNAME(unlzop, lzop, _BB_DIR_USR_BIN, _BB_SUID_NEVER, unlzop)) | ||
404 | IF_UNZIP(APPLET(unzip, _BB_DIR_USR_BIN, _BB_SUID_NEVER)) | 407 | IF_UNZIP(APPLET(unzip, _BB_DIR_USR_BIN, _BB_SUID_NEVER)) |
405 | IF_UPTIME(APPLET(uptime, _BB_DIR_USR_BIN, _BB_SUID_NEVER)) | 408 | IF_UPTIME(APPLET(uptime, _BB_DIR_USR_BIN, _BB_SUID_NEVER)) |
406 | IF_USLEEP(APPLET_NOFORK(usleep, usleep, _BB_DIR_BIN, _BB_SUID_NEVER, usleep)) | 409 | IF_USLEEP(APPLET_NOFORK(usleep, usleep, _BB_DIR_BIN, _BB_SUID_NEVER, usleep)) |
diff --git a/include/usage.h b/include/usage.h index 3fb996126..123462a02 100644 --- a/include/usage.h +++ b/include/usage.h | |||
@@ -202,6 +202,31 @@ | |||
202 | #define busybox_notes_usage \ | 202 | #define busybox_notes_usage \ |
203 | "Hello world!\n" | 203 | "Hello world!\n" |
204 | 204 | ||
205 | #define lzop_trivial_usage \ | ||
206 | "[-cfvd123456789CF] [file..]" | ||
207 | #define lzop_full_usage "\n\n" \ | ||
208 | " -c Write to standard output" \ | ||
209 | "\n -f Force" \ | ||
210 | "\n -v Verbose" \ | ||
211 | "\n -d Decompress" \ | ||
212 | "\n -F Don't store or verify checksum" \ | ||
213 | "\n -C Also write checksum of compressed block" \ | ||
214 | "\n -1..9 Compression level" \ | ||
215 | |||
216 | #define lzopcat_trivial_usage \ | ||
217 | "[-vCF] [file..]" | ||
218 | #define lzopcat_full_usage "\n\n" \ | ||
219 | " -v Verbose" \ | ||
220 | "\n -F Don't store or verify checksum" \ | ||
221 | |||
222 | #define unlzop_trivial_usage \ | ||
223 | "[-cfvCF] [file..]" | ||
224 | #define unlzop_full_usage "\n\n" \ | ||
225 | " -c Write to standard output" \ | ||
226 | "\n -f Force" \ | ||
227 | "\n -v Verbose" \ | ||
228 | "\n -F Don't store or verify checksum" \ | ||
229 | |||
205 | #define bzcat_trivial_usage \ | 230 | #define bzcat_trivial_usage \ |
206 | "FILE" | 231 | "FILE" |
207 | #define bzcat_full_usage "\n\n" \ | 232 | #define bzcat_full_usage "\n\n" \ |