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