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