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