blob: fef8cdba368ba6c6e1d83789376741eaf3f54eff [file] [log] [blame]
Denis Vlasenko052ad9a2009-04-29 12:01:51 +00001/*
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
Denys Vlasenko60cb48c2013-01-14 15:57:44 +010017 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
Denis Vlasenko052ad9a2009-04-29 12:01:51 +000018 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*/
Denys Vlasenkof6beef62013-11-14 11:39:00 +010027//config:config LZOP
Denys Vlasenko4eed2c62017-07-18 22:01:24 +020028//config: bool "lzop (13 kb)"
Denys Vlasenkof6beef62013-11-14 11:39:00 +010029//config: default y
30//config: help
Denys Vlasenko72089cf2017-07-21 09:50:55 +020031//config: Lzop compression/decompresion.
Denys Vlasenkof6beef62013-11-14 11:39:00 +010032//config:
Denys Vlasenkoeb3fdc82016-11-16 15:45:05 +010033//config:config UNLZOP
Denys Vlasenko4eed2c62017-07-18 22:01:24 +020034//config: bool "unlzop (13 kb)"
Denys Vlasenko1c013fa2017-06-15 18:07:04 +020035//config: default n # INCOMPAT: upstream lzop does not provide such tool
Denys Vlasenkoeb3fdc82016-11-16 15:45:05 +010036//config: help
Denys Vlasenko72089cf2017-07-21 09:50:55 +020037//config: Lzop decompresion.
Denys Vlasenkoeb3fdc82016-11-16 15:45:05 +010038//config:
39//config:config LZOPCAT
Denys Vlasenko4eed2c62017-07-18 22:01:24 +020040//config: bool "lzopcat (13 kb)"
Denys Vlasenko1c013fa2017-06-15 18:07:04 +020041//config: default n # INCOMPAT: upstream lzop does not provide such tool
Denys Vlasenkoeb3fdc82016-11-16 15:45:05 +010042//config: help
Denys Vlasenko72089cf2017-07-21 09:50:55 +020043//config: Alias to "lzop -dc".
Denys Vlasenkoeb3fdc82016-11-16 15:45:05 +010044//config:
Denys Vlasenkof6beef62013-11-14 11:39:00 +010045//config:config LZOP_COMPR_HIGH
46//config: bool "lzop compression levels 7,8,9 (not very useful)"
47//config: default n
Denys Vlasenkoeb3fdc82016-11-16 15:45:05 +010048//config: depends on LZOP || UNLZOP || LZOPCAT
Denys Vlasenkof6beef62013-11-14 11:39:00 +010049//config: help
Denys Vlasenko72089cf2017-07-21 09:50:55 +020050//config: High levels (7,8,9) of lzop compression. These levels
51//config: are actually slower than gzip at equivalent compression ratios
52//config: and take up 3.2K of code.
Denys Vlasenkof6beef62013-11-14 11:39:00 +010053
Denys Vlasenkoac216872013-11-14 11:38:18 +010054//applet:IF_LZOP(APPLET(lzop, BB_DIR_BIN, BB_SUID_DROP))
Denys Vlasenko205d48e2017-01-29 14:57:33 +010055// APPLET_ODDNAME:name main location suid_type help
56//applet:IF_UNLZOP( APPLET_ODDNAME(unlzop, lzop, BB_DIR_USR_BIN, BB_SUID_DROP, unlzop))
Denys Vlasenkoeb3fdc82016-11-16 15:45:05 +010057//applet:IF_LZOPCAT(APPLET_ODDNAME(lzopcat, lzop, BB_DIR_USR_BIN, BB_SUID_DROP, lzopcat))
Denys Vlasenko0c4dbd42017-09-18 16:28:43 +020058
Denys Vlasenko66620fa2013-11-14 09:53:52 +010059//kbuild:lib-$(CONFIG_LZOP) += lzop.o
Denys Vlasenkoeb3fdc82016-11-16 15:45:05 +010060//kbuild:lib-$(CONFIG_UNLZOP) += lzop.o
61//kbuild:lib-$(CONFIG_LZOPCAT) += lzop.o
Denys Vlasenko66620fa2013-11-14 09:53:52 +010062
Pere Orga1f4447b2011-03-27 22:40:30 +020063//usage:#define lzop_trivial_usage
Denys Vlasenko1c013fa2017-06-15 18:07:04 +020064//usage: "[-cfUvd123456789CF] [FILE]..."
Pere Orga1f4447b2011-03-27 22:40:30 +020065//usage:#define lzop_full_usage "\n\n"
Denys Vlasenko66426762011-06-05 03:58:28 +020066//usage: " -1..9 Compression level"
Pere Orga1f4447b2011-03-27 22:40:30 +020067//usage: "\n -d Decompress"
68//usage: "\n -c Write to stdout"
69//usage: "\n -f Force"
Denys Vlasenko1c013fa2017-06-15 18:07:04 +020070//usage: "\n -U Delete input files"
71///////: "\n -k Keep input files" (default, so why bother documenting?)
Pere Orga1f4447b2011-03-27 22:40:30 +020072//usage: "\n -v Verbose"
73//usage: "\n -F Don't store or verify checksum"
74//usage: "\n -C Also write checksum of compressed block"
75//usage:
76//usage:#define lzopcat_trivial_usage
Denys Vlasenkoeb3fdc82016-11-16 15:45:05 +010077//usage: "[-vF] [FILE]..."
Pere Orga1f4447b2011-03-27 22:40:30 +020078//usage:#define lzopcat_full_usage "\n\n"
79//usage: " -v Verbose"
Denys Vlasenkoeb3fdc82016-11-16 15:45:05 +010080//usage: "\n -F Don't verify checksum"
Pere Orga1f4447b2011-03-27 22:40:30 +020081//usage:
82//usage:#define unlzop_trivial_usage
Denys Vlasenko97058d02018-02-01 01:03:50 +010083//usage: "[-cfUvF] [FILE]..."
Pere Orga1f4447b2011-03-27 22:40:30 +020084//usage:#define unlzop_full_usage "\n\n"
Denys Vlasenko66426762011-06-05 03:58:28 +020085//usage: " -c Write to stdout"
Pere Orga1f4447b2011-03-27 22:40:30 +020086//usage: "\n -f Force"
Denys Vlasenko1c013fa2017-06-15 18:07:04 +020087//usage: "\n -U Delete input files"
88///////: "\n -k Keep input files" (default, so why bother documenting?)
Pere Orga1f4447b2011-03-27 22:40:30 +020089//usage: "\n -v Verbose"
Denys Vlasenkoeb3fdc82016-11-16 15:45:05 +010090//usage: "\n -F Don't verify checksum"
Pere Orga1f4447b2011-03-27 22:40:30 +020091
Denis Vlasenko052ad9a2009-04-29 12:01:51 +000092#include "libbb.h"
Denys Vlasenkoe6a2f4c2016-04-21 16:26:30 +020093#include "common_bufsiz.h"
Denys Vlasenkod184a722011-09-22 12:45:14 +020094#include "bb_archive.h"
Denis Vlasenko052ad9a2009-04-29 12:01:51 +000095#include "liblzo_interface.h"
96
97/* lzo-2.03/src/lzo_ptr.h */
98#define pd(a,b) ((unsigned)((a)-(b)))
99
100#define lzo_version() LZO_VERSION
101#define lzo_sizeof_dict_t (sizeof(uint8_t*))
102
103/* lzo-2.03/include/lzo/lzo1x.h */
104#define LZO1X_1_MEM_COMPRESS (16384 * lzo_sizeof_dict_t)
105#define LZO1X_1_15_MEM_COMPRESS (32768 * lzo_sizeof_dict_t)
106#define LZO1X_999_MEM_COMPRESS (14 * 16384 * sizeof(short))
107
108/* lzo-2.03/src/lzo1x_oo.c */
109#define NO_LIT UINT_MAX
110
111/**********************************************************************/
112static void copy2(uint8_t* ip, const uint8_t* m_pos, unsigned off)
113{
114 ip[0] = m_pos[0];
115 if (off == 1)
116 ip[1] = m_pos[0];
117 else
118 ip[1] = m_pos[1];
119}
120
121static void copy3(uint8_t* ip, const uint8_t* m_pos, unsigned off)
122{
123 ip[0] = m_pos[0];
124 if (off == 1) {
125 ip[2] = ip[1] = m_pos[0];
126 }
127 else if (off == 2) {
128 ip[1] = m_pos[1];
129 ip[2] = m_pos[0];
130 }
131 else {
132 ip[1] = m_pos[1];
133 ip[2] = m_pos[2];
134 }
135}
136
137/**********************************************************************/
138// optimize a block of data.
139/**********************************************************************/
140#define TEST_IP (ip < ip_end)
141#define TEST_OP (op <= op_end)
142
Denys Vlasenkoa7bb3c12009-10-08 12:28:08 +0200143static NOINLINE int lzo1x_optimize(uint8_t *in, unsigned in_len,
Denys Vlasenko99ac1752018-02-01 01:41:31 +0100144 uint8_t *out, unsigned *out_len /*, void* wrkmem */)
Denis Vlasenko052ad9a2009-04-29 12:01:51 +0000145{
146 uint8_t* op;
147 uint8_t* ip;
148 unsigned t;
149 uint8_t* m_pos;
150 uint8_t* const ip_end = in + in_len;
151 uint8_t* const op_end = out + *out_len;
152 uint8_t* litp = NULL;
153 unsigned lit = 0;
154 unsigned next_lit = NO_LIT;
155 unsigned nl;
156 unsigned long o_m1_a = 0, o_m1_b = 0, o_m2 = 0, o_m3_a = 0, o_m3_b = 0;
157
Denys Vlasenko60cb48c2013-01-14 15:57:44 +0100158// LZO_UNUSED(wrkmem);
Denis Vlasenko052ad9a2009-04-29 12:01:51 +0000159
160 *out_len = 0;
161
162 op = out;
163 ip = in;
164
165 if (*ip > 17) {
166 t = *ip++ - 17;
167 if (t < 4)
168 goto match_next;
169 goto first_literal_run;
170 }
171
172 while (TEST_IP && TEST_OP) {
173 t = *ip++;
174 if (t >= 16)
175 goto match;
176 /* a literal run */
177 litp = ip - 1;
178 if (t == 0) {
179 t = 15;
180 while (*ip == 0)
181 t += 255, ip++;
182 t += *ip++;
183 }
184 lit = t + 3;
185 /* copy literals */
186 copy_literal_run:
187 *op++ = *ip++;
188 *op++ = *ip++;
189 *op++ = *ip++;
190 first_literal_run:
191 do *op++ = *ip++; while (--t > 0);
192
193 t = *ip++;
194
195 if (t >= 16)
196 goto match;
197#if defined(LZO1X)
198 m_pos = op - 1 - 0x800;
199#elif defined(LZO1Y)
200 m_pos = op - 1 - 0x400;
201#endif
202 m_pos -= t >> 2;
203 m_pos -= *ip++ << 2;
204 *op++ = *m_pos++;
205 *op++ = *m_pos++;
206 *op++ = *m_pos++;
207 lit = 0;
208 goto match_done;
209
210
211 /* handle matches */
212 do {
213 if (t < 16) { /* a M1 match */
214 m_pos = op - 1;
215 m_pos -= t >> 2;
216 m_pos -= *ip++ << 2;
217
218 if (litp == NULL)
219 goto copy_m1;
220
221 nl = ip[-2] & 3;
222 /* test if a match follows */
223 if (nl == 0 && lit == 1 && ip[0] >= 16) {
224 next_lit = nl;
225 /* adjust length of previous short run */
226 lit += 2;
227 *litp = (unsigned char)((*litp & ~3) | lit);
228 /* copy over the 2 literals that replace the match */
229 copy2(ip-2, m_pos, pd(op, m_pos));
230 o_m1_a++;
231 }
232 /* test if a literal run follows */
Denys Vlasenko6b9f1632010-01-28 02:24:24 +0100233 else
234 if (nl == 0
235 && ip[0] < 16
236 && ip[0] != 0
237 && (lit + 2 + ip[0] < 16)
238 ) {
Denis Vlasenko052ad9a2009-04-29 12:01:51 +0000239 t = *ip++;
240 /* remove short run */
241 *litp &= ~3;
242 /* copy over the 2 literals that replace the match */
Denys Vlasenkod6f50002011-12-15 12:39:25 +0100243 copy2(ip-3+1, m_pos, pd(op, m_pos));
Denis Vlasenko052ad9a2009-04-29 12:01:51 +0000244 /* move literals 1 byte ahead */
245 litp += 2;
246 if (lit > 0)
247 memmove(litp+1, litp, lit);
248 /* insert new length of long literal run */
249 lit += 2 + t + 3;
250 *litp = (unsigned char)(lit - 3);
251
252 o_m1_b++;
Denys Vlasenkod6f50002011-12-15 12:39:25 +0100253 *op++ = *m_pos++;
254 *op++ = *m_pos++;
Denis Vlasenko052ad9a2009-04-29 12:01:51 +0000255 goto copy_literal_run;
256 }
257 copy_m1:
258 *op++ = *m_pos++;
259 *op++ = *m_pos++;
260 } else {
261 match:
262 if (t >= 64) { /* a M2 match */
263 m_pos = op - 1;
264#if defined(LZO1X)
265 m_pos -= (t >> 2) & 7;
266 m_pos -= *ip++ << 3;
267 t = (t >> 5) - 1;
268#elif defined(LZO1Y)
269 m_pos -= (t >> 2) & 3;
270 m_pos -= *ip++ << 2;
271 t = (t >> 4) - 3;
272#endif
273 if (litp == NULL)
274 goto copy_m;
275
276 nl = ip[-2] & 3;
277 /* test if in beetween two long literal runs */
278 if (t == 1 && lit > 3 && nl == 0
279 && ip[0] < 16 && ip[0] != 0 && (lit + 3 + ip[0] < 16)
280 ) {
281 t = *ip++;
282 /* copy over the 3 literals that replace the match */
Denys Vlasenkod6f50002011-12-15 12:39:25 +0100283 copy3(ip-1-2, m_pos, pd(op, m_pos));
Denis Vlasenko052ad9a2009-04-29 12:01:51 +0000284 /* set new length of previous literal run */
285 lit += 3 + t + 3;
286 *litp = (unsigned char)(lit - 3);
287 o_m2++;
288 *op++ = *m_pos++;
289 *op++ = *m_pos++;
290 *op++ = *m_pos++;
291 goto copy_literal_run;
292 }
293 } else {
294 if (t >= 32) { /* a M3 match */
295 t &= 31;
296 if (t == 0) {
297 t = 31;
298 while (*ip == 0)
299 t += 255, ip++;
300 t += *ip++;
301 }
302 m_pos = op - 1;
303 m_pos -= *ip++ >> 2;
304 m_pos -= *ip++ << 6;
305 } else { /* a M4 match */
306 m_pos = op;
307 m_pos -= (t & 8) << 11;
308 t &= 7;
309 if (t == 0) {
310 t = 7;
311 while (*ip == 0)
312 t += 255, ip++;
313 t += *ip++;
314 }
315 m_pos -= *ip++ >> 2;
316 m_pos -= *ip++ << 6;
317 if (m_pos == op)
318 goto eof_found;
319 m_pos -= 0x4000;
320 }
321 if (litp == NULL)
322 goto copy_m;
323
324 nl = ip[-2] & 3;
325 /* test if in beetween two matches */
326 if (t == 1 && lit == 0 && nl == 0 && ip[0] >= 16) {
327 next_lit = nl;
328 /* make a previous short run */
329 lit += 3;
330 *litp = (unsigned char)((*litp & ~3) | lit);
331 /* copy over the 3 literals that replace the match */
Denys Vlasenkod6f50002011-12-15 12:39:25 +0100332 copy3(ip-3, m_pos, pd(op, m_pos));
Denis Vlasenko052ad9a2009-04-29 12:01:51 +0000333 o_m3_a++;
334 }
335 /* test if a literal run follows */
336 else if (t == 1 && lit <= 3 && nl == 0
337 && ip[0] < 16 && ip[0] != 0 && (lit + 3 + ip[0] < 16)
338 ) {
339 t = *ip++;
340 /* remove short run */
341 *litp &= ~3;
342 /* copy over the 3 literals that replace the match */
Denys Vlasenkod6f50002011-12-15 12:39:25 +0100343 copy3(ip-4+1, m_pos, pd(op, m_pos));
Denis Vlasenko052ad9a2009-04-29 12:01:51 +0000344 /* move literals 1 byte ahead */
345 litp += 2;
346 if (lit > 0)
347 memmove(litp+1,litp,lit);
348 /* insert new length of long literal run */
349 lit += 3 + t + 3;
350 *litp = (unsigned char)(lit - 3);
351
352 o_m3_b++;
353 *op++ = *m_pos++;
354 *op++ = *m_pos++;
355 *op++ = *m_pos++;
356 goto copy_literal_run;
357 }
358 }
359 copy_m:
360 *op++ = *m_pos++;
361 *op++ = *m_pos++;
362 do *op++ = *m_pos++; while (--t > 0);
363 }
364
365 match_done:
366 if (next_lit == NO_LIT) {
367 t = ip[-2] & 3;
368 lit = t;
369 litp = ip - 2;
370 }
371 else
372 t = next_lit;
373 next_lit = NO_LIT;
374 if (t == 0)
375 break;
376 /* copy literals */
377 match_next:
378 do *op++ = *ip++; while (--t > 0);
379 t = *ip++;
380 } while (TEST_IP && TEST_OP);
381 }
382
383 /* no EOF code was found */
384 *out_len = pd(op, out);
385 return LZO_E_EOF_NOT_FOUND;
386
387 eof_found:
Denys Vlasenko60cb48c2013-01-14 15:57:44 +0100388// LZO_UNUSED(o_m1_a); LZO_UNUSED(o_m1_b); LZO_UNUSED(o_m2);
389// LZO_UNUSED(o_m3_a); LZO_UNUSED(o_m3_b);
Denis Vlasenko052ad9a2009-04-29 12:01:51 +0000390 *out_len = pd(op, out);
391 return (ip == ip_end ? LZO_E_OK :
Denys Vlasenko69675782013-01-14 01:34:48 +0100392 (ip < ip_end ? LZO_E_INPUT_NOT_CONSUMED : LZO_E_INPUT_OVERRUN));
Denis Vlasenko052ad9a2009-04-29 12:01:51 +0000393}
394
395/**********************************************************************/
396#define F_OS F_OS_UNIX
397#define F_CS F_CS_NATIVE
398
399/**********************************************************************/
400#define ADLER32_INIT_VALUE 1
401#define CRC32_INIT_VALUE 0
402
403/**********************************************************************/
404enum {
405 M_LZO1X_1 = 1,
406 M_LZO1X_1_15 = 2,
407 M_LZO1X_999 = 3,
408};
409
410/**********************************************************************/
411/* header flags */
412#define F_ADLER32_D 0x00000001L
413#define F_ADLER32_C 0x00000002L
414#define F_H_EXTRA_FIELD 0x00000040L
415#define F_H_GMTDIFF 0x00000080L
416#define F_CRC32_D 0x00000100L
417#define F_CRC32_C 0x00000200L
418#define F_H_FILTER 0x00000800L
419#define F_H_CRC32 0x00001000L
420#define F_MASK 0x00003FFFL
421
422/* operating system & file system that created the file [mostly unused] */
423#define F_OS_UNIX 0x03000000L
424#define F_OS_SHIFT 24
425#define F_OS_MASK 0xff000000L
426
427/* character set for file name encoding [mostly unused] */
428#define F_CS_NATIVE 0x00000000L
429#define F_CS_SHIFT 20
430#define F_CS_MASK 0x00f00000L
431
432/* these bits must be zero */
433#define F_RESERVED ((F_MASK | F_OS_MASK | F_CS_MASK) ^ 0xffffffffL)
434
435typedef struct chksum_t {
436 uint32_t f_adler32;
437 uint32_t f_crc32;
438} chksum_t;
439
440typedef struct header_t {
441 unsigned version;
442 unsigned lib_version;
443 unsigned version_needed_to_extract;
444 uint32_t flags;
445 uint32_t mode;
446 uint32_t mtime;
447 uint32_t gmtdiff;
448 uint32_t header_checksum;
449
450 uint32_t extra_field_len;
451 uint32_t extra_field_checksum;
452
453 unsigned char method;
454 unsigned char level;
455
456 /* info */
457 char name[255+1];
458} header_t;
459
460struct globals {
Denys Vlasenko9ce642f2010-10-27 15:26:45 +0200461 /*const uint32_t *lzo_crc32_table;*/
Denis Vlasenko052ad9a2009-04-29 12:01:51 +0000462 chksum_t chksum_in;
463 chksum_t chksum_out;
Denys Vlasenko98a4c7c2010-02-04 15:00:15 +0100464} FIX_ALIASING;
Denys Vlasenkoe6a2f4c2016-04-21 16:26:30 +0200465#define G (*(struct globals*)bb_common_bufsiz1)
Denys Vlasenko47cfbf32016-04-21 18:18:48 +0200466#define INIT_G() do { setup_common_bufsiz(); } while (0)
Denis Vlasenko052ad9a2009-04-29 12:01:51 +0000467//#define G (*ptr_to_globals)
468//#define INIT_G() do {
Denys Vlasenkob7c9fb22011-02-03 00:05:48 +0100469// SET_PTR_TO_GLOBALS(xzalloc(sizeof(G)));
Denis Vlasenko052ad9a2009-04-29 12:01:51 +0000470//} while (0)
471
472
473/**********************************************************************/
474#define LZOP_VERSION 0x1010
475//#define LZOP_VERSION_STRING "1.01"
476//#define LZOP_VERSION_DATE "Apr 27th 2003"
477
Denys Vlasenko1c013fa2017-06-15 18:07:04 +0200478// lzop wants to be weird:
479// unlike all other compressosrs, its -k "keep" option is the default,
480// and -U is used to delete the source. We will invert the bit after getopt().
481#define OPTION_STRING "cfUvqdt123456789CFk"
Denis Vlasenko052ad9a2009-04-29 12:01:51 +0000482
Mike Frysinger93b51812013-03-03 00:48:53 -0500483/* Note: must be kept in sync with archival/bbunzip.c */
Denis Vlasenko052ad9a2009-04-29 12:01:51 +0000484enum {
485 OPT_STDOUT = (1 << 0),
486 OPT_FORCE = (1 << 1),
Denys Vlasenko1c013fa2017-06-15 18:07:04 +0200487 OPT_KEEP = (1 << 2),
488 OPT_VERBOSE = (1 << 3),
489 OPT_QUIET = (1 << 4),
490 OPT_DECOMPRESS = (1 << 5),
491 OPT_TEST = (1 << 6),
492 OPT_1 = (1 << 7),
493 OPT_2 = (1 << 8),
494 OPT_3 = (1 << 9),
495 OPT_4 = (1 << 10),
496 OPT_5 = (1 << 11),
497 OPT_6 = (1 << 12),
Denys Vlasenko2fe5fed2013-03-01 08:25:45 +0100498 OPT_7 = (1 << 13),
499 OPT_8 = (1 << 14),
Denys Vlasenko1c013fa2017-06-15 18:07:04 +0200500 OPT_9 = (1 << 15),
501 OPT_C = (1 << 16),
502 OPT_F = (1 << 17),
503 OPT_k = (1 << 18),
504 OPT_789 = OPT_7 | OPT_8 | OPT_9
Denis Vlasenko052ad9a2009-04-29 12:01:51 +0000505};
506
507/**********************************************************************/
508// adler32 checksum
509// adapted from free code by Mark Adler <madler@alumni.caltech.edu>
510// see http://www.zlib.org/
511/**********************************************************************/
512static FAST_FUNC uint32_t
513lzo_adler32(uint32_t adler, const uint8_t* buf, unsigned len)
514{
515 enum {
516 LZO_BASE = 65521, /* largest prime smaller than 65536 */
517 /* NMAX is the largest n such that
518 * 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1 */
519 LZO_NMAX = 5552,
520 };
521 uint32_t s1 = adler & 0xffff;
522 uint32_t s2 = (adler >> 16) & 0xffff;
523 unsigned k;
524
525 if (buf == NULL)
526 return 1;
527
528 while (len > 0) {
529 k = len < LZO_NMAX ? (unsigned) len : LZO_NMAX;
530 len -= k;
531 if (k != 0) do {
532 s1 += *buf++;
533 s2 += s1;
534 } while (--k > 0);
535 s1 %= LZO_BASE;
536 s2 %= LZO_BASE;
537 }
538 return (s2 << 16) | s1;
539}
540
541static FAST_FUNC uint32_t
542lzo_crc32(uint32_t c, const uint8_t* buf, unsigned len)
543{
Denys Vlasenko9ce642f2010-10-27 15:26:45 +0200544 //if (buf == NULL) - impossible
545 // return 0;
Denis Vlasenko052ad9a2009-04-29 12:01:51 +0000546
Denys Vlasenko9ce642f2010-10-27 15:26:45 +0200547 return ~crc32_block_endian0(~c, buf, len, global_crc32_table);
Denis Vlasenko052ad9a2009-04-29 12:01:51 +0000548}
549
550/**********************************************************************/
551static void init_chksum(chksum_t *ct)
552{
553 ct->f_adler32 = ADLER32_INIT_VALUE;
554 ct->f_crc32 = CRC32_INIT_VALUE;
555}
556
557static void add_bytes_to_chksum(chksum_t *ct, const void* buf, int cnt)
558{
559 /* We need to handle the two checksums at once, because at the
560 * beginning of the header, we don't know yet which one we'll
561 * eventually need */
562 ct->f_adler32 = lzo_adler32(ct->f_adler32, (const uint8_t*)buf, cnt);
563 ct->f_crc32 = lzo_crc32(ct->f_crc32, (const uint8_t*)buf, cnt);
564}
565
566static uint32_t chksum_getresult(chksum_t *ct, const header_t *h)
567{
568 return (h->flags & F_H_CRC32) ? ct->f_crc32 : ct->f_adler32;
569}
570
571/**********************************************************************/
572static uint32_t read32(void)
573{
574 uint32_t v;
575 xread(0, &v, 4);
576 return ntohl(v);
577}
578
579static void write32(uint32_t v)
580{
581 v = htonl(v);
582 xwrite(1, &v, 4);
583}
584
585static void f_write(const void* buf, int cnt)
586{
587 xwrite(1, buf, cnt);
588 add_bytes_to_chksum(&G.chksum_out, buf, cnt);
589}
590
591static void f_read(void* buf, int cnt)
592{
593 xread(0, buf, cnt);
594 add_bytes_to_chksum(&G.chksum_in, buf, cnt);
595}
596
597static int f_read8(void)
598{
599 uint8_t v;
600 f_read(&v, 1);
601 return v;
602}
603
604static void f_write8(uint8_t v)
605{
606 f_write(&v, 1);
607}
608
609static unsigned f_read16(void)
610{
611 uint16_t v;
612 f_read(&v, 2);
613 return ntohs(v);
614}
615
616static void f_write16(uint16_t v)
617{
618 v = htons(v);
619 f_write(&v, 2);
620}
621
622static uint32_t f_read32(void)
623{
624 uint32_t v;
625 f_read(&v, 4);
626 return ntohl(v);
627}
628
629static void f_write32(uint32_t v)
630{
631 v = htonl(v);
632 f_write(&v, 4);
633}
634
635/**********************************************************************/
636static int lzo_get_method(header_t *h)
637{
638 /* check method */
639 if (h->method == M_LZO1X_1) {
640 if (h->level == 0)
641 h->level = 3;
642 } else if (h->method == M_LZO1X_1_15) {
643 if (h->level == 0)
644 h->level = 1;
645 } else if (h->method == M_LZO1X_999) {
646 if (h->level == 0)
647 h->level = 9;
648 } else
649 return -1; /* not a LZO method */
650
651 /* check compression level */
652 if (h->level < 1 || h->level > 9)
653 return 15;
654
655 return 0;
656}
657
658/**********************************************************************/
659#define LZO_BLOCK_SIZE (256 * 1024l)
660#define MAX_BLOCK_SIZE (64 * 1024l * 1024l) /* DO NOT CHANGE */
661
662/* LZO may expand uncompressible data by a small amount */
663#define MAX_COMPRESSED_SIZE(x) ((x) + (x) / 16 + 64 + 3)
664
665/**********************************************************************/
666// compress a file
667/**********************************************************************/
Denys Vlasenko48403252015-10-28 15:33:19 +0100668static NOINLINE int lzo_compress(const header_t *h)
Denis Vlasenko052ad9a2009-04-29 12:01:51 +0000669{
670 unsigned block_size = LZO_BLOCK_SIZE;
671 int r = 0; /* LZO_E_OK */
672 uint8_t *const b1 = xzalloc(block_size);
673 uint8_t *const b2 = xzalloc(MAX_COMPRESSED_SIZE(block_size));
674 unsigned src_len = 0, dst_len = 0;
675 uint32_t d_adler32 = ADLER32_INIT_VALUE;
676 uint32_t d_crc32 = CRC32_INIT_VALUE;
677 int l;
Denis Vlasenko052ad9a2009-04-29 12:01:51 +0000678 uint8_t *wrk_mem = NULL;
679
680 if (h->method == M_LZO1X_1)
681 wrk_mem = xzalloc(LZO1X_1_MEM_COMPRESS);
682 else if (h->method == M_LZO1X_1_15)
683 wrk_mem = xzalloc(LZO1X_1_15_MEM_COMPRESS);
684 else if (h->method == M_LZO1X_999)
685 wrk_mem = xzalloc(LZO1X_999_MEM_COMPRESS);
686
687 for (;;) {
688 /* read a block */
689 l = full_read(0, b1, block_size);
690 src_len = (l > 0 ? l : 0);
691
692 /* write uncompressed block size */
693 write32(src_len);
694
695 /* exit if last block */
696 if (src_len == 0)
697 break;
698
699 /* compute checksum of uncompressed block */
700 if (h->flags & F_ADLER32_D)
701 d_adler32 = lzo_adler32(ADLER32_INIT_VALUE, b1, src_len);
702 if (h->flags & F_CRC32_D)
703 d_crc32 = lzo_crc32(CRC32_INIT_VALUE, b1, src_len);
704
705 /* compress */
706 if (h->method == M_LZO1X_1)
707 r = lzo1x_1_compress(b1, src_len, b2, &dst_len, wrk_mem);
708 else if (h->method == M_LZO1X_1_15)
709 r = lzo1x_1_15_compress(b1, src_len, b2, &dst_len, wrk_mem);
710#if ENABLE_LZOP_COMPR_HIGH
711 else if (h->method == M_LZO1X_999)
712 r = lzo1x_999_compress_level(b1, src_len, b2, &dst_len,
713 wrk_mem, h->level);
714#endif
715 else
716 bb_error_msg_and_die("internal error");
717
718 if (r != 0) /* not LZO_E_OK */
719 bb_error_msg_and_die("internal error - compression failed");
720
721 /* write compressed block size */
722 if (dst_len < src_len) {
723 /* optimize */
724 if (h->method == M_LZO1X_999) {
725 unsigned new_len = src_len;
Denys Vlasenko99ac1752018-02-01 01:41:31 +0100726 r = lzo1x_optimize(b2, dst_len, b1, &new_len /*, NULL*/);
Denis Vlasenko052ad9a2009-04-29 12:01:51 +0000727 if (r != 0 /*LZO_E_OK*/ || new_len != src_len)
728 bb_error_msg_and_die("internal error - optimization failed");
729 }
730 write32(dst_len);
731 } else {
732 /* data actually expanded => store data uncompressed */
733 write32(src_len);
734 }
735
736 /* write checksum of uncompressed block */
737 if (h->flags & F_ADLER32_D)
738 write32(d_adler32);
739 if (h->flags & F_CRC32_D)
740 write32(d_crc32);
741
742 if (dst_len < src_len) {
743 /* write checksum of compressed block */
744 if (h->flags & F_ADLER32_C)
Denys Vlasenko9ce642f2010-10-27 15:26:45 +0200745 write32(lzo_adler32(ADLER32_INIT_VALUE, b2, dst_len));
Denis Vlasenko052ad9a2009-04-29 12:01:51 +0000746 if (h->flags & F_CRC32_C)
747 write32(lzo_crc32(CRC32_INIT_VALUE, b2, dst_len));
748 /* write compressed block data */
749 xwrite(1, b2, dst_len);
750 } else {
751 /* write uncompressed block data */
752 xwrite(1, b1, src_len);
753 }
754 }
755
756 free(wrk_mem);
757 free(b1);
758 free(b2);
Denys Vlasenko48403252015-10-28 15:33:19 +0100759 return 1;
Denis Vlasenko052ad9a2009-04-29 12:01:51 +0000760}
761
Denys Vlasenko8ae6e9b2010-09-04 19:46:52 +0200762static FAST_FUNC void lzo_check(
763 uint32_t init,
764 uint8_t* buf, unsigned len,
765 uint32_t FAST_FUNC (*fn)(uint32_t, const uint8_t*, unsigned),
766 uint32_t ref)
Denis Vlasenko052ad9a2009-04-29 12:01:51 +0000767{
Denys Vlasenko8ae6e9b2010-09-04 19:46:52 +0200768 /* This function, by having the same order of parameters
769 * as fn, and by being marked FAST_FUNC (same as fn),
770 * saves a dozen bytes of code.
771 */
Denis Vlasenko052ad9a2009-04-29 12:01:51 +0000772 uint32_t c = fn(init, buf, len);
773 if (c != ref)
774 bb_error_msg_and_die("checksum error");
775}
776
777/**********************************************************************/
778// decompress a file
779/**********************************************************************/
Denys Vlasenko48403252015-10-28 15:33:19 +0100780static NOINLINE int lzo_decompress(const header_t *h)
Denis Vlasenko052ad9a2009-04-29 12:01:51 +0000781{
782 unsigned block_size = LZO_BLOCK_SIZE;
783 int r;
784 uint32_t src_len, dst_len;
785 uint32_t c_adler32 = ADLER32_INIT_VALUE;
786 uint32_t d_adler32 = ADLER32_INIT_VALUE;
787 uint32_t c_crc32 = CRC32_INIT_VALUE, d_crc32 = CRC32_INIT_VALUE;
Denis Vlasenko052ad9a2009-04-29 12:01:51 +0000788 uint8_t *b1;
789 uint32_t mcs_block_size = MAX_COMPRESSED_SIZE(block_size);
790 uint8_t *b2 = NULL;
791
792 for (;;) {
793 uint8_t *dst;
794
795 /* read uncompressed block size */
796 dst_len = read32();
797
798 /* exit if last block */
799 if (dst_len == 0)
800 break;
801
802 /* error if split file */
803 if (dst_len == 0xffffffffL)
804 /* should not happen - not yet implemented */
805 bb_error_msg_and_die("this file is a split lzop file");
806
807 if (dst_len > MAX_BLOCK_SIZE)
Denys Vlasenkoccb88a62010-05-27 02:22:54 +0200808 bb_error_msg_and_die("corrupted data");
Denis Vlasenko052ad9a2009-04-29 12:01:51 +0000809
810 /* read compressed block size */
811 src_len = read32();
812 if (src_len <= 0 || src_len > dst_len)
Denys Vlasenkoccb88a62010-05-27 02:22:54 +0200813 bb_error_msg_and_die("corrupted data");
Denis Vlasenko052ad9a2009-04-29 12:01:51 +0000814
815 if (dst_len > block_size) {
816 if (b2) {
Denis Vlasenko052ad9a2009-04-29 12:01:51 +0000817 free(b2);
Denys Vlasenko8ae6e9b2010-09-04 19:46:52 +0200818 b2 = NULL;
Denis Vlasenko052ad9a2009-04-29 12:01:51 +0000819 }
820 block_size = dst_len;
821 mcs_block_size = MAX_COMPRESSED_SIZE(block_size);
822 }
823
824 /* read checksum of uncompressed block */
825 if (h->flags & F_ADLER32_D)
826 d_adler32 = read32();
827 if (h->flags & F_CRC32_D)
828 d_crc32 = read32();
829
830 /* read checksum of compressed block */
831 if (src_len < dst_len) {
832 if (h->flags & F_ADLER32_C)
833 c_adler32 = read32();
834 if (h->flags & F_CRC32_C)
835 c_crc32 = read32();
836 }
837
838 if (b2 == NULL)
839 b2 = xzalloc(mcs_block_size);
840 /* read the block into the end of our buffer */
841 b1 = b2 + mcs_block_size - src_len;
842 xread(0, b1, src_len);
843
844 if (src_len < dst_len) {
845 unsigned d = dst_len;
846
847 if (!(option_mask32 & OPT_F)) {
848 /* verify checksum of compressed block */
849 if (h->flags & F_ADLER32_C)
Denys Vlasenko8ae6e9b2010-09-04 19:46:52 +0200850 lzo_check(ADLER32_INIT_VALUE,
851 b1, src_len,
852 lzo_adler32, c_adler32);
Denis Vlasenko052ad9a2009-04-29 12:01:51 +0000853 if (h->flags & F_CRC32_C)
Denys Vlasenko8ae6e9b2010-09-04 19:46:52 +0200854 lzo_check(CRC32_INIT_VALUE,
855 b1, src_len,
856 lzo_crc32, c_crc32);
Denis Vlasenko052ad9a2009-04-29 12:01:51 +0000857 }
858
859 /* decompress */
860// if (option_mask32 & OPT_F)
Denys Vlasenko99ac1752018-02-01 01:41:31 +0100861// r = lzo1x_decompress(b1, src_len, b2, &d /*, NULL*/);
Denis Vlasenko052ad9a2009-04-29 12:01:51 +0000862// else
Denys Vlasenko99ac1752018-02-01 01:41:31 +0100863 r = lzo1x_decompress_safe(b1, src_len, b2, &d /*, NULL*/);
Denis Vlasenko052ad9a2009-04-29 12:01:51 +0000864
865 if (r != 0 /*LZO_E_OK*/ || dst_len != d) {
Denys Vlasenkoccb88a62010-05-27 02:22:54 +0200866 bb_error_msg_and_die("corrupted data");
Denis Vlasenko052ad9a2009-04-29 12:01:51 +0000867 }
868 dst = b2;
869 } else {
870 /* "stored" block => no decompression */
871 dst = b1;
872 }
873
874 if (!(option_mask32 & OPT_F)) {
875 /* verify checksum of uncompressed block */
876 if (h->flags & F_ADLER32_D)
Denys Vlasenko8ae6e9b2010-09-04 19:46:52 +0200877 lzo_check(ADLER32_INIT_VALUE,
878 dst, dst_len,
879 lzo_adler32, d_adler32);
Denis Vlasenko052ad9a2009-04-29 12:01:51 +0000880 if (h->flags & F_CRC32_D)
Denys Vlasenko8ae6e9b2010-09-04 19:46:52 +0200881 lzo_check(CRC32_INIT_VALUE,
882 dst, dst_len,
883 lzo_crc32, d_crc32);
Denis Vlasenko052ad9a2009-04-29 12:01:51 +0000884 }
885
886 /* write uncompressed block data */
887 xwrite(1, dst, dst_len);
888 }
889
890 free(b2);
Denys Vlasenko48403252015-10-28 15:33:19 +0100891 return 1;
Denis Vlasenko052ad9a2009-04-29 12:01:51 +0000892}
893
894/**********************************************************************/
895// lzop file signature (shamelessly borrowed from PNG)
896/**********************************************************************/
897/*
898 * The first nine bytes of a lzop file always contain the following values:
899 *
900 * 0 1 2 3 4 5 6 7 8
901 * --- --- --- --- --- --- --- --- ---
902 * (hex) 89 4c 5a 4f 00 0d 0a 1a 0a
903 * (decimal) 137 76 90 79 0 13 10 26 10
904 * (C notation - ASCII) \211 L Z O \0 \r \n \032 \n
905 */
906
907/* (vda) comparison with lzop v1.02rc1 ("lzop -1 <FILE" cmd):
908 * Only slight differences in header:
909 * -00000000 89 4c 5a 4f 00 0d 0a 1a 0a 10 20 20 20 09 40 02
910 * +00000000 89 4c 5a 4f 00 0d 0a 1a 0a 10 10 20 30 09 40 02
911 * ^^^^^ ^^^^^
912 * version lib_version
913 * -00000010 01 03 00 00 0d 00 00 81 a4 49 f7 a6 3f 00 00 00
914 * +00000010 01 03 00 00 01 00 00 00 00 00 00 00 00 00 00 00
915 * ^^^^^^^^^^^ ^^^^^^^^^^^ ^^^^^^^^^^^
916 * flags mode mtime
917 * -00000020 00 00 2d 67 04 17 00 04 00 00 00 03 ed ec 9d 6d
918 * +00000020 00 00 10 5f 00 c1 00 04 00 00 00 03 ed ec 9d 6d
919 * ^^^^^^^^^^^
920 * chksum_out
921 * The rest is identical.
922*/
Denys Vlasenko3e134eb2016-04-22 18:09:21 +0200923static const unsigned char lzop_magic[9] ALIGN1 = {
Denis Vlasenko052ad9a2009-04-29 12:01:51 +0000924 0x89, 0x4c, 0x5a, 0x4f, 0x00, 0x0d, 0x0a, 0x1a, 0x0a
925};
926
927/* This coding is derived from Alexander Lehmann's pngcheck code. */
928static void check_magic(void)
929{
Denys Vlasenko9038d6f2009-07-15 20:02:19 +0200930 unsigned char magic[sizeof(lzop_magic)];
Denis Vlasenko052ad9a2009-04-29 12:01:51 +0000931 xread(0, magic, sizeof(magic));
932 if (memcmp(magic, lzop_magic, sizeof(lzop_magic)) != 0)
933 bb_error_msg_and_die("bad magic number");
934}
935
936/**********************************************************************/
937// lzop file header
938/**********************************************************************/
939static void write_header(const header_t *h)
940{
941 int l;
942
943 xwrite(1, lzop_magic, sizeof(lzop_magic));
944
945 init_chksum(&G.chksum_out);
946
947 f_write16(h->version);
948 f_write16(h->lib_version);
949 f_write16(h->version_needed_to_extract);
950 f_write8(h->method);
951 f_write8(h->level);
952 f_write32(h->flags);
953 f_write32(h->mode);
954 f_write32(h->mtime);
955 f_write32(h->gmtdiff);
956
957 l = (int) strlen(h->name);
958 f_write8(l);
959 if (l)
960 f_write(h->name, l);
961
962 f_write32(chksum_getresult(&G.chksum_out, h));
963}
964
965static int read_header(header_t *h)
966{
967 int r;
968 int l;
969 uint32_t checksum;
970
971 memset(h, 0, sizeof(*h));
972 h->version_needed_to_extract = 0x0900; /* first lzop version */
973 h->level = 0;
974
975 init_chksum(&G.chksum_in);
976
977 h->version = f_read16();
978 if (h->version < 0x0900)
979 return 3;
980 h->lib_version = f_read16();
981 if (h->version >= 0x0940) {
982 h->version_needed_to_extract = f_read16();
983 if (h->version_needed_to_extract > LZOP_VERSION)
984 return 16;
985 if (h->version_needed_to_extract < 0x0900)
986 return 3;
987 }
988 h->method = f_read8();
989 if (h->version >= 0x0940)
990 h->level = f_read8();
991 h->flags = f_read32();
992 if (h->flags & F_H_FILTER)
993 return 16; /* filter not supported */
994 h->mode = f_read32();
995 h->mtime = f_read32();
996 if (h->version >= 0x0940)
997 h->gmtdiff = f_read32();
998
999 l = f_read8();
1000 if (l > 0)
1001 f_read(h->name, l);
1002 h->name[l] = 0;
1003
1004 checksum = chksum_getresult(&G.chksum_in, h);
1005 h->header_checksum = f_read32();
1006 if (h->header_checksum != checksum)
1007 return 2;
1008
1009 if (h->method <= 0)
1010 return 14;
1011 r = lzo_get_method(h);
1012 if (r != 0)
1013 return r;
1014
1015 /* check reserved flags */
1016 if (h->flags & F_RESERVED)
1017 return -13;
1018
1019 /* skip extra field [not used yet] */
1020 if (h->flags & F_H_EXTRA_FIELD) {
1021 uint32_t k;
Denys Vlasenko9038d6f2009-07-15 20:02:19 +02001022
Denis Vlasenko052ad9a2009-04-29 12:01:51 +00001023 /* note: the checksum also covers the length */
1024 init_chksum(&G.chksum_in);
1025 h->extra_field_len = f_read32();
1026 for (k = 0; k < h->extra_field_len; k++)
1027 f_read8();
1028 checksum = chksum_getresult(&G.chksum_in, h);
1029 h->extra_field_checksum = f_read32();
1030 if (h->extra_field_checksum != checksum)
1031 return 3;
1032 }
1033
1034 return 0;
1035}
1036
1037static void p_header(header_t *h)
1038{
1039 int r;
1040
1041 r = read_header(h);
1042 if (r == 0)
1043 return;
1044 bb_error_msg_and_die("header_error %d", r);
1045}
1046
1047/**********************************************************************/
1048// compress
1049/**********************************************************************/
1050static void lzo_set_method(header_t *h)
1051{
1052 int level = 1;
1053
1054 if (option_mask32 & OPT_1) {
1055 h->method = M_LZO1X_1_15;
1056 } else if (option_mask32 & OPT_789) {
1057#if ENABLE_LZOP_COMPR_HIGH
1058 h->method = M_LZO1X_999;
1059 if (option_mask32 & OPT_7)
1060 level = 7;
1061 else if (option_mask32 & OPT_8)
1062 level = 8;
1063 else
1064 level = 9;
1065#else
1066 bb_error_msg_and_die("high compression not compiled in");
1067#endif
1068 } else { /* levels 2..6 or none (defaults to level 3) */
1069 h->method = M_LZO1X_1;
1070 level = 5; /* levels 2-6 are actually the same */
1071 }
1072
1073 h->level = level;
1074}
1075
Denys Vlasenko48403252015-10-28 15:33:19 +01001076static int do_lzo_compress(void)
Denis Vlasenko052ad9a2009-04-29 12:01:51 +00001077{
1078 header_t header;
1079
1080#define h (&header)
1081 memset(h, 0, sizeof(*h));
1082
1083 lzo_set_method(h);
1084
1085 h->version = (LZOP_VERSION & 0xffff);
1086 h->version_needed_to_extract = 0x0940;
1087 h->lib_version = lzo_version() & 0xffff;
1088
1089 h->flags = (F_OS & F_OS_MASK) | (F_CS & F_CS_MASK);
1090
1091 if (!(option_mask32 & OPT_F) || h->method == M_LZO1X_999) {
1092 h->flags |= F_ADLER32_D;
1093 if (option_mask32 & OPT_C)
1094 h->flags |= F_ADLER32_C;
1095 }
1096 write_header(h);
1097 return lzo_compress(h);
1098#undef h
1099}
1100
1101/**********************************************************************/
1102// decompress
1103/**********************************************************************/
Denys Vlasenko48403252015-10-28 15:33:19 +01001104static int do_lzo_decompress(void)
Denis Vlasenko052ad9a2009-04-29 12:01:51 +00001105{
1106 header_t header;
Denys Vlasenko9038d6f2009-07-15 20:02:19 +02001107
Denis Vlasenko052ad9a2009-04-29 12:01:51 +00001108 check_magic();
1109 p_header(&header);
1110 return lzo_decompress(&header);
1111}
1112
Denys Vlasenko39a04f72010-05-31 14:18:57 +02001113static char* FAST_FUNC make_new_name_lzop(char *filename, const char *expected_ext UNUSED_PARAM)
Denis Vlasenko052ad9a2009-04-29 12:01:51 +00001114{
1115 if (option_mask32 & OPT_DECOMPRESS) {
1116 char *extension = strrchr(filename, '.');
1117 if (!extension || strcmp(extension + 1, "lzo") != 0)
1118 return xasprintf("%s.out", filename);
1119 *extension = '\0';
1120 return filename;
1121 }
1122 return xasprintf("%s.lzo", filename);
1123}
1124
Denys Vlasenkoe7800f32014-12-07 00:42:49 +01001125static IF_DESKTOP(long long) int FAST_FUNC pack_lzop(transformer_state_t *xstate UNUSED_PARAM)
Denis Vlasenko052ad9a2009-04-29 12:01:51 +00001126{
1127 if (option_mask32 & OPT_DECOMPRESS)
1128 return do_lzo_decompress();
1129 return do_lzo_compress();
1130}
1131
1132int lzop_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
1133int lzop_main(int argc UNUSED_PARAM, char **argv)
1134{
1135 getopt32(argv, OPTION_STRING);
1136 argv += optind;
Denys Vlasenko1c013fa2017-06-15 18:07:04 +02001137 /* -U is "anti -k", invert bit for bbunpack(): */
1138 option_mask32 ^= OPT_KEEP;
1139 /* -k disables -U (if any): */
Denys Vlasenko22542ec2017-08-08 21:55:02 +02001140 /* opt_complementary "k-U"? - nope, only handles -Uk, not -kU */
Denys Vlasenko1c013fa2017-06-15 18:07:04 +02001141 if (option_mask32 & OPT_k)
1142 option_mask32 |= OPT_KEEP;
1143
Denis Vlasenko052ad9a2009-04-29 12:01:51 +00001144 /* lzopcat? */
Denys Vlasenkoeb3fdc82016-11-16 15:45:05 +01001145 if (ENABLE_LZOPCAT && applet_name[4] == 'c')
Denis Vlasenko052ad9a2009-04-29 12:01:51 +00001146 option_mask32 |= (OPT_STDOUT | OPT_DECOMPRESS);
1147 /* unlzop? */
Denys Vlasenkoeb3fdc82016-11-16 15:45:05 +01001148 if (ENABLE_UNLZOP && applet_name[4] == 'o')
Denis Vlasenko052ad9a2009-04-29 12:01:51 +00001149 option_mask32 |= OPT_DECOMPRESS;
1150
Denys Vlasenkoddacb032018-02-01 10:56:19 +01001151 global_crc32_new_table_le();
Denys Vlasenko39a04f72010-05-31 14:18:57 +02001152 return bbunpack(argv, pack_lzop, make_new_name_lzop, /*unused:*/ NULL);
Denis Vlasenko052ad9a2009-04-29 12:01:51 +00001153}