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