| /* |
| * bzip2 is written by Julian Seward <jseward@bzip.org>. |
| * Adapted for busybox by Denys Vlasenko <vda.linux@googlemail.com>. |
| * See README and LICENSE files in this directory for more information. |
| */ |
| |
| /*-------------------------------------------------------------*/ |
| /*--- Library top-level functions. ---*/ |
| /*--- bzlib.c ---*/ |
| /*-------------------------------------------------------------*/ |
| |
| /* ------------------------------------------------------------------ |
| This file is part of bzip2/libbzip2, a program and library for |
| lossless, block-sorting data compression. |
| |
| bzip2/libbzip2 version 1.0.4 of 20 December 2006 |
| Copyright (C) 1996-2006 Julian Seward <jseward@bzip.org> |
| |
| Please read the WARNING, DISCLAIMER and PATENTS sections in the |
| README file. |
| |
| This program is released under the terms of the license contained |
| in the file LICENSE. |
| ------------------------------------------------------------------ */ |
| |
| /* CHANGES |
| * 0.9.0 -- original version. |
| * 0.9.0a/b -- no changes in this file. |
| * 0.9.0c -- made zero-length BZ_FLUSH work correctly in bzCompress(). |
| * fixed bzWrite/bzRead to ignore zero-length requests. |
| * fixed bzread to correctly handle read requests after EOF. |
| * wrong parameter order in call to bzDecompressInit in |
| * bzBuffToBuffDecompress. Fixed. |
| */ |
| |
| /* #include "bzlib_private.h" */ |
| |
| /*---------------------------------------------------*/ |
| /*--- Compression stuff ---*/ |
| /*---------------------------------------------------*/ |
| |
| /*---------------------------------------------------*/ |
| #if BZ_LIGHT_DEBUG |
| static |
| void bz_assert_fail(int errcode) |
| { |
| /* if (errcode == 1007) bb_error_msg_and_die("probably bad RAM"); */ |
| bb_error_msg_and_die("internal error %d", errcode); |
| } |
| #endif |
| |
| /*---------------------------------------------------*/ |
| static |
| void prepare_new_block(EState* s) |
| { |
| int i; |
| s->nblock = 0; |
| s->numZ = 0; |
| s->state_out_pos = 0; |
| BZ_INITIALISE_CRC(s->blockCRC); |
| /* inlined memset would be nice to have here */ |
| for (i = 0; i < 256; i++) |
| s->inUse[i] = 0; |
| s->blockNo++; |
| } |
| |
| |
| /*---------------------------------------------------*/ |
| static |
| ALWAYS_INLINE |
| void init_RL(EState* s) |
| { |
| s->state_in_ch = 256; |
| s->state_in_len = 0; |
| } |
| |
| |
| static |
| Bool isempty_RL(EState* s) |
| { |
| if (s->state_in_ch < 256 && s->state_in_len > 0) |
| return False; |
| return True; |
| } |
| |
| |
| /*---------------------------------------------------*/ |
| static |
| void BZ2_bzCompressInit(bz_stream *strm, int blockSize100k) |
| { |
| int32_t n; |
| EState* s; |
| |
| s = xzalloc(sizeof(EState)); |
| s->strm = strm; |
| |
| n = 100000 * blockSize100k; |
| s->arr1 = xmalloc(n * sizeof(uint32_t)); |
| s->mtfv = (uint16_t*)s->arr1; |
| s->ptr = (uint32_t*)s->arr1; |
| s->arr2 = xmalloc((n + BZ_N_OVERSHOOT) * sizeof(uint32_t)); |
| s->block = (uint8_t*)s->arr2; |
| s->ftab = xmalloc(65537 * sizeof(uint32_t)); |
| |
| s->crc32table = crc32_filltable(NULL, 1); |
| |
| s->state = BZ_S_INPUT; |
| s->mode = BZ_M_RUNNING; |
| s->blockSize100k = blockSize100k; |
| s->nblockMAX = n - 19; |
| |
| strm->state = s; |
| /*strm->total_in = 0;*/ |
| strm->total_out = 0; |
| init_RL(s); |
| prepare_new_block(s); |
| } |
| |
| |
| /*---------------------------------------------------*/ |
| static |
| void add_pair_to_block(EState* s) |
| { |
| int32_t i; |
| uint8_t ch = (uint8_t)(s->state_in_ch); |
| for (i = 0; i < s->state_in_len; i++) { |
| BZ_UPDATE_CRC(s, s->blockCRC, ch); |
| } |
| s->inUse[s->state_in_ch] = 1; |
| switch (s->state_in_len) { |
| case 3: |
| s->block[s->nblock] = (uint8_t)ch; s->nblock++; |
| /* fall through */ |
| case 2: |
| s->block[s->nblock] = (uint8_t)ch; s->nblock++; |
| /* fall through */ |
| case 1: |
| s->block[s->nblock] = (uint8_t)ch; s->nblock++; |
| break; |
| default: |
| s->inUse[s->state_in_len - 4] = 1; |
| s->block[s->nblock] = (uint8_t)ch; s->nblock++; |
| s->block[s->nblock] = (uint8_t)ch; s->nblock++; |
| s->block[s->nblock] = (uint8_t)ch; s->nblock++; |
| s->block[s->nblock] = (uint8_t)ch; s->nblock++; |
| s->block[s->nblock] = (uint8_t)(s->state_in_len - 4); |
| s->nblock++; |
| break; |
| } |
| } |
| |
| |
| /*---------------------------------------------------*/ |
| static |
| void flush_RL(EState* s) |
| { |
| if (s->state_in_ch < 256) add_pair_to_block(s); |
| init_RL(s); |
| } |
| |
| |
| /*---------------------------------------------------*/ |
| #define ADD_CHAR_TO_BLOCK(zs, zchh0) \ |
| { \ |
| uint32_t zchh = (uint32_t)(zchh0); \ |
| /*-- fast track the common case --*/ \ |
| if (zchh != zs->state_in_ch && zs->state_in_len == 1) { \ |
| uint8_t ch = (uint8_t)(zs->state_in_ch); \ |
| BZ_UPDATE_CRC(zs, zs->blockCRC, ch); \ |
| zs->inUse[zs->state_in_ch] = 1; \ |
| zs->block[zs->nblock] = (uint8_t)ch; \ |
| zs->nblock++; \ |
| zs->state_in_ch = zchh; \ |
| } \ |
| else \ |
| /*-- general, uncommon cases --*/ \ |
| if (zchh != zs->state_in_ch || zs->state_in_len == 255) { \ |
| if (zs->state_in_ch < 256) \ |
| add_pair_to_block(zs); \ |
| zs->state_in_ch = zchh; \ |
| zs->state_in_len = 1; \ |
| } else { \ |
| zs->state_in_len++; \ |
| } \ |
| } |
| |
| |
| /*---------------------------------------------------*/ |
| static |
| void /*Bool*/ copy_input_until_stop(EState* s) |
| { |
| /*Bool progress_in = False;*/ |
| |
| #ifdef SAME_CODE_AS_BELOW |
| if (s->mode == BZ_M_RUNNING) { |
| /*-- fast track the common case --*/ |
| while (1) { |
| /*-- no input? --*/ |
| if (s->strm->avail_in == 0) break; |
| /*-- block full? --*/ |
| if (s->nblock >= s->nblockMAX) break; |
| /*progress_in = True;*/ |
| ADD_CHAR_TO_BLOCK(s, (uint32_t)(*(uint8_t*)(s->strm->next_in))); |
| s->strm->next_in++; |
| s->strm->avail_in--; |
| /*s->strm->total_in++;*/ |
| } |
| } else |
| #endif |
| { |
| /*-- general, uncommon case --*/ |
| while (1) { |
| /*-- no input? --*/ |
| if (s->strm->avail_in == 0) break; |
| /*-- block full? --*/ |
| if (s->nblock >= s->nblockMAX) break; |
| //# /*-- flush/finish end? --*/ |
| //# if (s->avail_in_expect == 0) break; |
| /*progress_in = True;*/ |
| ADD_CHAR_TO_BLOCK(s, *(uint8_t*)(s->strm->next_in)); |
| s->strm->next_in++; |
| s->strm->avail_in--; |
| /*s->strm->total_in++;*/ |
| //# s->avail_in_expect--; |
| } |
| } |
| /*return progress_in;*/ |
| } |
| |
| |
| /*---------------------------------------------------*/ |
| static |
| void /*Bool*/ copy_output_until_stop(EState* s) |
| { |
| /*Bool progress_out = False;*/ |
| |
| while (1) { |
| /*-- no output space? --*/ |
| if (s->strm->avail_out == 0) break; |
| |
| /*-- block done? --*/ |
| if (s->state_out_pos >= s->numZ) break; |
| |
| /*progress_out = True;*/ |
| *(s->strm->next_out) = s->zbits[s->state_out_pos]; |
| s->state_out_pos++; |
| s->strm->avail_out--; |
| s->strm->next_out++; |
| s->strm->total_out++; |
| } |
| /*return progress_out;*/ |
| } |
| |
| |
| /*---------------------------------------------------*/ |
| static |
| void /*Bool*/ handle_compress(bz_stream *strm) |
| { |
| /*Bool progress_in = False;*/ |
| /*Bool progress_out = False;*/ |
| EState* s = strm->state; |
| |
| while (1) { |
| if (s->state == BZ_S_OUTPUT) { |
| /*progress_out |=*/ copy_output_until_stop(s); |
| if (s->state_out_pos < s->numZ) break; |
| if (s->mode == BZ_M_FINISHING |
| //# && s->avail_in_expect == 0 |
| && s->strm->avail_in == 0 |
| && isempty_RL(s)) |
| break; |
| prepare_new_block(s); |
| s->state = BZ_S_INPUT; |
| #ifdef FLUSH_IS_UNUSED |
| if (s->mode == BZ_M_FLUSHING |
| && s->avail_in_expect == 0 |
| && isempty_RL(s)) |
| break; |
| #endif |
| } |
| |
| if (s->state == BZ_S_INPUT) { |
| /*progress_in |=*/ copy_input_until_stop(s); |
| //#if (s->mode != BZ_M_RUNNING && s->avail_in_expect == 0) { |
| if (s->mode != BZ_M_RUNNING && s->strm->avail_in == 0) { |
| flush_RL(s); |
| BZ2_compressBlock(s, (s->mode == BZ_M_FINISHING)); |
| s->state = BZ_S_OUTPUT; |
| } else |
| if (s->nblock >= s->nblockMAX) { |
| BZ2_compressBlock(s, 0); |
| s->state = BZ_S_OUTPUT; |
| } else |
| if (s->strm->avail_in == 0) { |
| break; |
| } |
| } |
| } |
| |
| /*return progress_in || progress_out;*/ |
| } |
| |
| |
| /*---------------------------------------------------*/ |
| static |
| int BZ2_bzCompress(bz_stream *strm, int action) |
| { |
| /*Bool progress;*/ |
| EState* s; |
| |
| s = strm->state; |
| |
| switch (s->mode) { |
| case BZ_M_RUNNING: |
| if (action == BZ_RUN) { |
| /*progress =*/ handle_compress(strm); |
| /*return progress ? BZ_RUN_OK : BZ_PARAM_ERROR;*/ |
| return BZ_RUN_OK; |
| } |
| #ifdef FLUSH_IS_UNUSED |
| else |
| if (action == BZ_FLUSH) { |
| //#s->avail_in_expect = strm->avail_in; |
| s->mode = BZ_M_FLUSHING; |
| goto case_BZ_M_FLUSHING; |
| } |
| #endif |
| else |
| /*if (action == BZ_FINISH)*/ { |
| //#s->avail_in_expect = strm->avail_in; |
| s->mode = BZ_M_FINISHING; |
| goto case_BZ_M_FINISHING; |
| } |
| |
| #ifdef FLUSH_IS_UNUSED |
| case_BZ_M_FLUSHING: |
| case BZ_M_FLUSHING: |
| /*if (s->avail_in_expect != s->strm->avail_in) |
| return BZ_SEQUENCE_ERROR;*/ |
| /*progress =*/ handle_compress(strm); |
| if (s->avail_in_expect > 0 || !isempty_RL(s) || s->state_out_pos < s->numZ) |
| return BZ_FLUSH_OK; |
| s->mode = BZ_M_RUNNING; |
| return BZ_RUN_OK; |
| #endif |
| |
| case_BZ_M_FINISHING: |
| /*case BZ_M_FINISHING:*/ |
| default: |
| /*if (s->avail_in_expect != s->strm->avail_in) |
| return BZ_SEQUENCE_ERROR;*/ |
| /*progress =*/ handle_compress(strm); |
| /*if (!progress) return BZ_SEQUENCE_ERROR;*/ |
| //#if (s->avail_in_expect > 0 || !isempty_RL(s) || s->state_out_pos < s->numZ) |
| //# return BZ_FINISH_OK; |
| if (s->strm->avail_in > 0 || !isempty_RL(s) || s->state_out_pos < s->numZ) |
| return BZ_FINISH_OK; |
| /*s->mode = BZ_M_IDLE;*/ |
| return BZ_STREAM_END; |
| } |
| /* return BZ_OK; --not reached--*/ |
| } |
| |
| |
| /*---------------------------------------------------*/ |
| static |
| void BZ2_bzCompressEnd(bz_stream *strm) |
| { |
| EState* s; |
| |
| s = strm->state; |
| free(s->arr1); |
| free(s->arr2); |
| free(s->ftab); |
| free(s->crc32table); |
| free(strm->state); |
| } |
| |
| |
| /*---------------------------------------------------*/ |
| /*--- Misc convenience stuff ---*/ |
| /*---------------------------------------------------*/ |
| |
| /*---------------------------------------------------*/ |
| #ifdef EXAMPLE_CODE_FOR_MEM_TO_MEM_COMPRESSION |
| static |
| int BZ2_bzBuffToBuffCompress(char* dest, |
| unsigned int* destLen, |
| char* source, |
| unsigned int sourceLen, |
| int blockSize100k) |
| { |
| bz_stream strm; |
| int ret; |
| |
| if (dest == NULL || destLen == NULL || |
| source == NULL || |
| blockSize100k < 1 || blockSize100k > 9) |
| return BZ_PARAM_ERROR; |
| |
| BZ2_bzCompressInit(&strm, blockSize100k); |
| |
| strm.next_in = source; |
| strm.next_out = dest; |
| strm.avail_in = sourceLen; |
| strm.avail_out = *destLen; |
| |
| ret = BZ2_bzCompress(&strm, BZ_FINISH); |
| if (ret == BZ_FINISH_OK) goto output_overflow; |
| if (ret != BZ_STREAM_END) goto errhandler; |
| |
| /* normal termination */ |
| *destLen -= strm.avail_out; |
| BZ2_bzCompressEnd(&strm); |
| return BZ_OK; |
| |
| output_overflow: |
| BZ2_bzCompressEnd(&strm); |
| return BZ_OUTBUFF_FULL; |
| |
| errhandler: |
| BZ2_bzCompressEnd(&strm); |
| return ret; |
| } |
| #endif |
| |
| /*-------------------------------------------------------------*/ |
| /*--- end bzlib.c ---*/ |
| /*-------------------------------------------------------------*/ |