[3320] | 1 | /*
|
---|
| 2 | * bzip2 is written by Julian Seward <jseward@bzip.org>.
|
---|
| 3 | * Adapted for busybox by Denys Vlasenko <vda.linux@googlemail.com>.
|
---|
| 4 | * See README and LICENSE files in this directory for more information.
|
---|
| 5 | */
|
---|
| 6 |
|
---|
| 7 | /*-------------------------------------------------------------*/
|
---|
| 8 | /*--- Library top-level functions. ---*/
|
---|
| 9 | /*--- bzlib.c ---*/
|
---|
| 10 | /*-------------------------------------------------------------*/
|
---|
| 11 |
|
---|
| 12 | /* ------------------------------------------------------------------
|
---|
| 13 | This file is part of bzip2/libbzip2, a program and library for
|
---|
| 14 | lossless, block-sorting data compression.
|
---|
| 15 |
|
---|
| 16 | bzip2/libbzip2 version 1.0.4 of 20 December 2006
|
---|
| 17 | Copyright (C) 1996-2006 Julian Seward <jseward@bzip.org>
|
---|
| 18 |
|
---|
| 19 | Please read the WARNING, DISCLAIMER and PATENTS sections in the
|
---|
| 20 | README file.
|
---|
| 21 |
|
---|
| 22 | This program is released under the terms of the license contained
|
---|
| 23 | in the file LICENSE.
|
---|
| 24 | ------------------------------------------------------------------ */
|
---|
| 25 |
|
---|
| 26 | /* CHANGES
|
---|
| 27 | * 0.9.0 -- original version.
|
---|
| 28 | * 0.9.0a/b -- no changes in this file.
|
---|
| 29 | * 0.9.0c -- made zero-length BZ_FLUSH work correctly in bzCompress().
|
---|
| 30 | * fixed bzWrite/bzRead to ignore zero-length requests.
|
---|
| 31 | * fixed bzread to correctly handle read requests after EOF.
|
---|
| 32 | * wrong parameter order in call to bzDecompressInit in
|
---|
| 33 | * bzBuffToBuffDecompress. Fixed.
|
---|
| 34 | */
|
---|
| 35 |
|
---|
| 36 | /* #include "bzlib_private.h" */
|
---|
| 37 |
|
---|
| 38 | /*---------------------------------------------------*/
|
---|
| 39 | /*--- Compression stuff ---*/
|
---|
| 40 | /*---------------------------------------------------*/
|
---|
| 41 |
|
---|
| 42 | /*---------------------------------------------------*/
|
---|
| 43 | #if BZ_LIGHT_DEBUG
|
---|
| 44 | static
|
---|
| 45 | void bz_assert_fail(int errcode)
|
---|
| 46 | {
|
---|
| 47 | /* if (errcode == 1007) bb_error_msg_and_die("probably bad RAM"); */
|
---|
| 48 | bb_error_msg_and_die("internal error %d", errcode);
|
---|
| 49 | }
|
---|
| 50 | #endif
|
---|
| 51 |
|
---|
| 52 | /*---------------------------------------------------*/
|
---|
| 53 | static
|
---|
| 54 | void prepare_new_block(EState* s)
|
---|
| 55 | {
|
---|
| 56 | int i;
|
---|
| 57 | s->nblock = 0;
|
---|
| 58 | s->numZ = 0;
|
---|
| 59 | s->state_out_pos = 0;
|
---|
| 60 | BZ_INITIALISE_CRC(s->blockCRC);
|
---|
| 61 | /* inlined memset would be nice to have here */
|
---|
| 62 | for (i = 0; i < 256; i++)
|
---|
| 63 | s->inUse[i] = 0;
|
---|
| 64 | s->blockNo++;
|
---|
| 65 | }
|
---|
| 66 |
|
---|
| 67 |
|
---|
| 68 | /*---------------------------------------------------*/
|
---|
| 69 | static
|
---|
| 70 | ALWAYS_INLINE
|
---|
| 71 | void init_RL(EState* s)
|
---|
| 72 | {
|
---|
| 73 | s->state_in_ch = 256;
|
---|
| 74 | s->state_in_len = 0;
|
---|
| 75 | }
|
---|
| 76 |
|
---|
| 77 |
|
---|
| 78 | static
|
---|
| 79 | int isempty_RL(EState* s)
|
---|
| 80 | {
|
---|
| 81 | return (s->state_in_ch >= 256 || s->state_in_len <= 0);
|
---|
| 82 | }
|
---|
| 83 |
|
---|
| 84 |
|
---|
| 85 | /*---------------------------------------------------*/
|
---|
| 86 | static
|
---|
| 87 | void BZ2_bzCompressInit(bz_stream *strm, int blockSize100k)
|
---|
| 88 | {
|
---|
| 89 | int32_t n;
|
---|
| 90 | EState* s;
|
---|
| 91 |
|
---|
| 92 | s = xzalloc(sizeof(EState));
|
---|
| 93 | s->strm = strm;
|
---|
| 94 |
|
---|
| 95 | n = 100000 * blockSize100k;
|
---|
| 96 | s->arr1 = xmalloc(n * sizeof(uint32_t));
|
---|
| 97 | s->mtfv = (uint16_t*)s->arr1;
|
---|
| 98 | s->ptr = (uint32_t*)s->arr1;
|
---|
| 99 | s->arr2 = xmalloc((n + BZ_N_OVERSHOOT) * sizeof(uint32_t));
|
---|
| 100 | s->block = (uint8_t*)s->arr2;
|
---|
| 101 | s->ftab = xmalloc(65537 * sizeof(uint32_t));
|
---|
| 102 |
|
---|
| 103 | s->crc32table = crc32_filltable(NULL, 1);
|
---|
| 104 |
|
---|
| 105 | s->state = BZ_S_INPUT;
|
---|
| 106 | s->mode = BZ_M_RUNNING;
|
---|
| 107 | s->blockSize100k = blockSize100k;
|
---|
| 108 | s->nblockMAX = n - 19;
|
---|
| 109 |
|
---|
| 110 | strm->state = s;
|
---|
| 111 | /*strm->total_in = 0;*/
|
---|
| 112 | strm->total_out = 0;
|
---|
| 113 | init_RL(s);
|
---|
| 114 | prepare_new_block(s);
|
---|
| 115 | }
|
---|
| 116 |
|
---|
| 117 |
|
---|
| 118 | /*---------------------------------------------------*/
|
---|
| 119 | static
|
---|
| 120 | void add_pair_to_block(EState* s)
|
---|
| 121 | {
|
---|
| 122 | int32_t i;
|
---|
| 123 | uint8_t ch = (uint8_t)(s->state_in_ch);
|
---|
| 124 | for (i = 0; i < s->state_in_len; i++) {
|
---|
| 125 | BZ_UPDATE_CRC(s, s->blockCRC, ch);
|
---|
| 126 | }
|
---|
| 127 | s->inUse[s->state_in_ch] = 1;
|
---|
| 128 | switch (s->state_in_len) {
|
---|
| 129 | case 3:
|
---|
| 130 | s->block[s->nblock] = (uint8_t)ch; s->nblock++;
|
---|
| 131 | /* fall through */
|
---|
| 132 | case 2:
|
---|
| 133 | s->block[s->nblock] = (uint8_t)ch; s->nblock++;
|
---|
| 134 | /* fall through */
|
---|
| 135 | case 1:
|
---|
| 136 | s->block[s->nblock] = (uint8_t)ch; s->nblock++;
|
---|
| 137 | break;
|
---|
| 138 | default:
|
---|
| 139 | s->inUse[s->state_in_len - 4] = 1;
|
---|
| 140 | s->block[s->nblock] = (uint8_t)ch; s->nblock++;
|
---|
| 141 | s->block[s->nblock] = (uint8_t)ch; s->nblock++;
|
---|
| 142 | s->block[s->nblock] = (uint8_t)ch; s->nblock++;
|
---|
| 143 | s->block[s->nblock] = (uint8_t)ch; s->nblock++;
|
---|
| 144 | s->block[s->nblock] = (uint8_t)(s->state_in_len - 4);
|
---|
| 145 | s->nblock++;
|
---|
| 146 | break;
|
---|
| 147 | }
|
---|
| 148 | }
|
---|
| 149 |
|
---|
| 150 |
|
---|
| 151 | /*---------------------------------------------------*/
|
---|
| 152 | static
|
---|
| 153 | void flush_RL(EState* s)
|
---|
| 154 | {
|
---|
| 155 | if (s->state_in_ch < 256) add_pair_to_block(s);
|
---|
| 156 | init_RL(s);
|
---|
| 157 | }
|
---|
| 158 |
|
---|
| 159 |
|
---|
| 160 | /*---------------------------------------------------*/
|
---|
| 161 | #define ADD_CHAR_TO_BLOCK(zs, zchh0) \
|
---|
| 162 | { \
|
---|
| 163 | uint32_t zchh = (uint32_t)(zchh0); \
|
---|
| 164 | /*-- fast track the common case --*/ \
|
---|
| 165 | if (zchh != zs->state_in_ch && zs->state_in_len == 1) { \
|
---|
| 166 | uint8_t ch = (uint8_t)(zs->state_in_ch); \
|
---|
| 167 | BZ_UPDATE_CRC(zs, zs->blockCRC, ch); \
|
---|
| 168 | zs->inUse[zs->state_in_ch] = 1; \
|
---|
| 169 | zs->block[zs->nblock] = (uint8_t)ch; \
|
---|
| 170 | zs->nblock++; \
|
---|
| 171 | zs->state_in_ch = zchh; \
|
---|
| 172 | } \
|
---|
| 173 | else \
|
---|
| 174 | /*-- general, uncommon cases --*/ \
|
---|
| 175 | if (zchh != zs->state_in_ch || zs->state_in_len == 255) { \
|
---|
| 176 | if (zs->state_in_ch < 256) \
|
---|
| 177 | add_pair_to_block(zs); \
|
---|
| 178 | zs->state_in_ch = zchh; \
|
---|
| 179 | zs->state_in_len = 1; \
|
---|
| 180 | } else { \
|
---|
| 181 | zs->state_in_len++; \
|
---|
| 182 | } \
|
---|
| 183 | }
|
---|
| 184 |
|
---|
| 185 |
|
---|
| 186 | /*---------------------------------------------------*/
|
---|
| 187 | static
|
---|
| 188 | void /*Bool*/ copy_input_until_stop(EState* s)
|
---|
| 189 | {
|
---|
| 190 | /*Bool progress_in = False;*/
|
---|
| 191 |
|
---|
| 192 | #ifdef SAME_CODE_AS_BELOW
|
---|
| 193 | if (s->mode == BZ_M_RUNNING) {
|
---|
| 194 | /*-- fast track the common case --*/
|
---|
| 195 | while (1) {
|
---|
| 196 | /*-- no input? --*/
|
---|
| 197 | if (s->strm->avail_in == 0) break;
|
---|
| 198 | /*-- block full? --*/
|
---|
| 199 | if (s->nblock >= s->nblockMAX) break;
|
---|
| 200 | /*progress_in = True;*/
|
---|
| 201 | ADD_CHAR_TO_BLOCK(s, (uint32_t)(*(uint8_t*)(s->strm->next_in)));
|
---|
| 202 | s->strm->next_in++;
|
---|
| 203 | s->strm->avail_in--;
|
---|
| 204 | /*s->strm->total_in++;*/
|
---|
| 205 | }
|
---|
| 206 | } else
|
---|
| 207 | #endif
|
---|
| 208 | {
|
---|
| 209 | /*-- general, uncommon case --*/
|
---|
| 210 | while (1) {
|
---|
| 211 | /*-- no input? --*/
|
---|
| 212 | if (s->strm->avail_in == 0) break;
|
---|
| 213 | /*-- block full? --*/
|
---|
| 214 | if (s->nblock >= s->nblockMAX) break;
|
---|
| 215 | //# /*-- flush/finish end? --*/
|
---|
| 216 | //# if (s->avail_in_expect == 0) break;
|
---|
| 217 | /*progress_in = True;*/
|
---|
| 218 | ADD_CHAR_TO_BLOCK(s, *(uint8_t*)(s->strm->next_in));
|
---|
| 219 | s->strm->next_in++;
|
---|
| 220 | s->strm->avail_in--;
|
---|
| 221 | /*s->strm->total_in++;*/
|
---|
| 222 | //# s->avail_in_expect--;
|
---|
| 223 | }
|
---|
| 224 | }
|
---|
| 225 | /*return progress_in;*/
|
---|
| 226 | }
|
---|
| 227 |
|
---|
| 228 |
|
---|
| 229 | /*---------------------------------------------------*/
|
---|
| 230 | static
|
---|
| 231 | void /*Bool*/ copy_output_until_stop(EState* s)
|
---|
| 232 | {
|
---|
| 233 | /*Bool progress_out = False;*/
|
---|
| 234 |
|
---|
| 235 | while (1) {
|
---|
| 236 | /*-- no output space? --*/
|
---|
| 237 | if (s->strm->avail_out == 0) break;
|
---|
| 238 |
|
---|
| 239 | /*-- block done? --*/
|
---|
| 240 | if (s->state_out_pos >= s->numZ) break;
|
---|
| 241 |
|
---|
| 242 | /*progress_out = True;*/
|
---|
| 243 | *(s->strm->next_out) = s->zbits[s->state_out_pos];
|
---|
| 244 | s->state_out_pos++;
|
---|
| 245 | s->strm->avail_out--;
|
---|
| 246 | s->strm->next_out++;
|
---|
| 247 | s->strm->total_out++;
|
---|
| 248 | }
|
---|
| 249 | /*return progress_out;*/
|
---|
| 250 | }
|
---|
| 251 |
|
---|
| 252 |
|
---|
| 253 | /*---------------------------------------------------*/
|
---|
| 254 | static
|
---|
| 255 | void /*Bool*/ handle_compress(bz_stream *strm)
|
---|
| 256 | {
|
---|
| 257 | /*Bool progress_in = False;*/
|
---|
| 258 | /*Bool progress_out = False;*/
|
---|
| 259 | EState* s = strm->state;
|
---|
| 260 |
|
---|
| 261 | while (1) {
|
---|
| 262 | if (s->state == BZ_S_OUTPUT) {
|
---|
| 263 | /*progress_out |=*/ copy_output_until_stop(s);
|
---|
| 264 | if (s->state_out_pos < s->numZ) break;
|
---|
| 265 | if (s->mode == BZ_M_FINISHING
|
---|
| 266 | //# && s->avail_in_expect == 0
|
---|
| 267 | && s->strm->avail_in == 0
|
---|
| 268 | && isempty_RL(s))
|
---|
| 269 | break;
|
---|
| 270 | prepare_new_block(s);
|
---|
| 271 | s->state = BZ_S_INPUT;
|
---|
| 272 | #ifdef FLUSH_IS_UNUSED
|
---|
| 273 | if (s->mode == BZ_M_FLUSHING
|
---|
| 274 | && s->avail_in_expect == 0
|
---|
| 275 | && isempty_RL(s))
|
---|
| 276 | break;
|
---|
| 277 | #endif
|
---|
| 278 | }
|
---|
| 279 |
|
---|
| 280 | if (s->state == BZ_S_INPUT) {
|
---|
| 281 | /*progress_in |=*/ copy_input_until_stop(s);
|
---|
| 282 | //#if (s->mode != BZ_M_RUNNING && s->avail_in_expect == 0) {
|
---|
| 283 | if (s->mode != BZ_M_RUNNING && s->strm->avail_in == 0) {
|
---|
| 284 | flush_RL(s);
|
---|
| 285 | BZ2_compressBlock(s, (s->mode == BZ_M_FINISHING));
|
---|
| 286 | s->state = BZ_S_OUTPUT;
|
---|
| 287 | } else
|
---|
| 288 | if (s->nblock >= s->nblockMAX) {
|
---|
| 289 | BZ2_compressBlock(s, 0);
|
---|
| 290 | s->state = BZ_S_OUTPUT;
|
---|
| 291 | } else
|
---|
| 292 | if (s->strm->avail_in == 0) {
|
---|
| 293 | break;
|
---|
| 294 | }
|
---|
| 295 | }
|
---|
| 296 | }
|
---|
| 297 |
|
---|
| 298 | /*return progress_in || progress_out;*/
|
---|
| 299 | }
|
---|
| 300 |
|
---|
| 301 |
|
---|
| 302 | /*---------------------------------------------------*/
|
---|
| 303 | static
|
---|
| 304 | int BZ2_bzCompress(bz_stream *strm, int action)
|
---|
| 305 | {
|
---|
| 306 | /*Bool progress;*/
|
---|
| 307 | EState* s;
|
---|
| 308 |
|
---|
| 309 | s = strm->state;
|
---|
| 310 |
|
---|
| 311 | switch (s->mode) {
|
---|
| 312 | case BZ_M_RUNNING:
|
---|
| 313 | if (action == BZ_RUN) {
|
---|
| 314 | /*progress =*/ handle_compress(strm);
|
---|
| 315 | /*return progress ? BZ_RUN_OK : BZ_PARAM_ERROR;*/
|
---|
| 316 | return BZ_RUN_OK;
|
---|
| 317 | }
|
---|
| 318 | #ifdef FLUSH_IS_UNUSED
|
---|
| 319 | else
|
---|
| 320 | if (action == BZ_FLUSH) {
|
---|
| 321 | //#s->avail_in_expect = strm->avail_in;
|
---|
| 322 | s->mode = BZ_M_FLUSHING;
|
---|
| 323 | goto case_BZ_M_FLUSHING;
|
---|
| 324 | }
|
---|
| 325 | #endif
|
---|
| 326 | else
|
---|
| 327 | /*if (action == BZ_FINISH)*/ {
|
---|
| 328 | //#s->avail_in_expect = strm->avail_in;
|
---|
| 329 | s->mode = BZ_M_FINISHING;
|
---|
| 330 | goto case_BZ_M_FINISHING;
|
---|
| 331 | }
|
---|
| 332 |
|
---|
| 333 | #ifdef FLUSH_IS_UNUSED
|
---|
| 334 | case_BZ_M_FLUSHING:
|
---|
| 335 | case BZ_M_FLUSHING:
|
---|
| 336 | /*if (s->avail_in_expect != s->strm->avail_in)
|
---|
| 337 | return BZ_SEQUENCE_ERROR;*/
|
---|
| 338 | /*progress =*/ handle_compress(strm);
|
---|
| 339 | if (s->avail_in_expect > 0 || !isempty_RL(s) || s->state_out_pos < s->numZ)
|
---|
| 340 | return BZ_FLUSH_OK;
|
---|
| 341 | s->mode = BZ_M_RUNNING;
|
---|
| 342 | return BZ_RUN_OK;
|
---|
| 343 | #endif
|
---|
| 344 |
|
---|
| 345 | case_BZ_M_FINISHING:
|
---|
| 346 | /*case BZ_M_FINISHING:*/
|
---|
| 347 | default:
|
---|
| 348 | /*if (s->avail_in_expect != s->strm->avail_in)
|
---|
| 349 | return BZ_SEQUENCE_ERROR;*/
|
---|
| 350 | /*progress =*/ handle_compress(strm);
|
---|
| 351 | /*if (!progress) return BZ_SEQUENCE_ERROR;*/
|
---|
| 352 | //#if (s->avail_in_expect > 0 || !isempty_RL(s) || s->state_out_pos < s->numZ)
|
---|
| 353 | //# return BZ_FINISH_OK;
|
---|
| 354 | if (s->strm->avail_in > 0 || !isempty_RL(s) || s->state_out_pos < s->numZ)
|
---|
| 355 | return BZ_FINISH_OK;
|
---|
| 356 | /*s->mode = BZ_M_IDLE;*/
|
---|
| 357 | return BZ_STREAM_END;
|
---|
| 358 | }
|
---|
| 359 | /* return BZ_OK; --not reached--*/
|
---|
| 360 | }
|
---|
| 361 |
|
---|
| 362 |
|
---|
| 363 | /*---------------------------------------------------*/
|
---|
| 364 | static
|
---|
| 365 | void BZ2_bzCompressEnd(bz_stream *strm)
|
---|
| 366 | {
|
---|
| 367 | EState* s;
|
---|
| 368 |
|
---|
| 369 | s = strm->state;
|
---|
| 370 | free(s->arr1);
|
---|
| 371 | free(s->arr2);
|
---|
| 372 | free(s->ftab);
|
---|
| 373 | free(s->crc32table);
|
---|
| 374 | free(s);
|
---|
| 375 | }
|
---|
| 376 |
|
---|
| 377 |
|
---|
| 378 | /*---------------------------------------------------*/
|
---|
| 379 | /*--- Misc convenience stuff ---*/
|
---|
| 380 | /*---------------------------------------------------*/
|
---|
| 381 |
|
---|
| 382 | /*---------------------------------------------------*/
|
---|
| 383 | #ifdef EXAMPLE_CODE_FOR_MEM_TO_MEM_COMPRESSION
|
---|
| 384 | static
|
---|
| 385 | int BZ2_bzBuffToBuffCompress(char* dest,
|
---|
| 386 | unsigned int* destLen,
|
---|
| 387 | char* source,
|
---|
| 388 | unsigned int sourceLen,
|
---|
| 389 | int blockSize100k)
|
---|
| 390 | {
|
---|
| 391 | bz_stream strm;
|
---|
| 392 | int ret;
|
---|
| 393 |
|
---|
| 394 | if (dest == NULL || destLen == NULL
|
---|
| 395 | || source == NULL
|
---|
| 396 | || blockSize100k < 1 || blockSize100k > 9
|
---|
| 397 | ) {
|
---|
| 398 | return BZ_PARAM_ERROR;
|
---|
| 399 | }
|
---|
| 400 |
|
---|
| 401 | BZ2_bzCompressInit(&strm, blockSize100k);
|
---|
| 402 |
|
---|
| 403 | strm.next_in = source;
|
---|
| 404 | strm.next_out = dest;
|
---|
| 405 | strm.avail_in = sourceLen;
|
---|
| 406 | strm.avail_out = *destLen;
|
---|
| 407 |
|
---|
| 408 | ret = BZ2_bzCompress(&strm, BZ_FINISH);
|
---|
| 409 | if (ret == BZ_FINISH_OK) goto output_overflow;
|
---|
| 410 | if (ret != BZ_STREAM_END) goto errhandler;
|
---|
| 411 |
|
---|
| 412 | /* normal termination */
|
---|
| 413 | *destLen -= strm.avail_out;
|
---|
| 414 | BZ2_bzCompressEnd(&strm);
|
---|
| 415 | return BZ_OK;
|
---|
| 416 |
|
---|
| 417 | output_overflow:
|
---|
| 418 | BZ2_bzCompressEnd(&strm);
|
---|
| 419 | return BZ_OUTBUFF_FULL;
|
---|
| 420 |
|
---|
| 421 | errhandler:
|
---|
| 422 | BZ2_bzCompressEnd(&strm);
|
---|
| 423 | return ret;
|
---|
| 424 | }
|
---|
| 425 | #endif
|
---|
| 426 |
|
---|
| 427 | /*-------------------------------------------------------------*/
|
---|
| 428 | /*--- end bzlib.c ---*/
|
---|
| 429 | /*-------------------------------------------------------------*/
|
---|