source: MondoRescue/branches/3.3/mindi-busybox/archival/lzop.c@ 3803

Last change on this file since 3803 was 3621, checked in by Bruno Cornec, 10 years ago

New 3?3 banch for incorporation of latest busybox 1.25. Changing minor version to handle potential incompatibilities.

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