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