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