cannam@89: cannam@89: /*-------------------------------------------------------------*/ cannam@89: /*--- Library top-level functions. ---*/ cannam@89: /*--- bzlib.c ---*/ cannam@89: /*-------------------------------------------------------------*/ cannam@89: cannam@89: /* ------------------------------------------------------------------ cannam@89: This file is part of bzip2/libbzip2, a program and library for cannam@89: lossless, block-sorting data compression. cannam@89: cannam@89: bzip2/libbzip2 version 1.0.6 of 6 September 2010 cannam@89: Copyright (C) 1996-2010 Julian Seward cannam@89: cannam@89: Please read the WARNING, DISCLAIMER and PATENTS sections in the cannam@89: README file. cannam@89: cannam@89: This program is released under the terms of the license contained cannam@89: in the file LICENSE. cannam@89: ------------------------------------------------------------------ */ cannam@89: cannam@89: /* CHANGES cannam@89: 0.9.0 -- original version. cannam@89: 0.9.0a/b -- no changes in this file. cannam@89: 0.9.0c -- made zero-length BZ_FLUSH work correctly in bzCompress(). cannam@89: fixed bzWrite/bzRead to ignore zero-length requests. cannam@89: fixed bzread to correctly handle read requests after EOF. cannam@89: wrong parameter order in call to bzDecompressInit in cannam@89: bzBuffToBuffDecompress. Fixed. cannam@89: */ cannam@89: cannam@89: #include "bzlib_private.h" cannam@89: cannam@89: cannam@89: /*---------------------------------------------------*/ cannam@89: /*--- Compression stuff ---*/ cannam@89: /*---------------------------------------------------*/ cannam@89: cannam@89: cannam@89: /*---------------------------------------------------*/ cannam@89: #ifndef BZ_NO_STDIO cannam@89: void BZ2_bz__AssertH__fail ( int errcode ) cannam@89: { cannam@89: fprintf(stderr, cannam@89: "\n\nbzip2/libbzip2: internal error number %d.\n" cannam@89: "This is a bug in bzip2/libbzip2, %s.\n" cannam@89: "Please report it to me at: jseward@bzip.org. If this happened\n" cannam@89: "when you were using some program which uses libbzip2 as a\n" cannam@89: "component, you should also report this bug to the author(s)\n" cannam@89: "of that program. Please make an effort to report this bug;\n" cannam@89: "timely and accurate bug reports eventually lead to higher\n" cannam@89: "quality software. Thanks. Julian Seward, 10 December 2007.\n\n", cannam@89: errcode, cannam@89: BZ2_bzlibVersion() cannam@89: ); cannam@89: cannam@89: if (errcode == 1007) { cannam@89: fprintf(stderr, cannam@89: "\n*** A special note about internal error number 1007 ***\n" cannam@89: "\n" cannam@89: "Experience suggests that a common cause of i.e. 1007\n" cannam@89: "is unreliable memory or other hardware. The 1007 assertion\n" cannam@89: "just happens to cross-check the results of huge numbers of\n" cannam@89: "memory reads/writes, and so acts (unintendedly) as a stress\n" cannam@89: "test of your memory system.\n" cannam@89: "\n" cannam@89: "I suggest the following: try compressing the file again,\n" cannam@89: "possibly monitoring progress in detail with the -vv flag.\n" cannam@89: "\n" cannam@89: "* If the error cannot be reproduced, and/or happens at different\n" cannam@89: " points in compression, you may have a flaky memory system.\n" cannam@89: " Try a memory-test program. I have used Memtest86\n" cannam@89: " (www.memtest86.com). At the time of writing it is free (GPLd).\n" cannam@89: " Memtest86 tests memory much more thorougly than your BIOSs\n" cannam@89: " power-on test, and may find failures that the BIOS doesn't.\n" cannam@89: "\n" cannam@89: "* If the error can be repeatably reproduced, this is a bug in\n" cannam@89: " bzip2, and I would very much like to hear about it. Please\n" cannam@89: " let me know, and, ideally, save a copy of the file causing the\n" cannam@89: " problem -- without which I will be unable to investigate it.\n" cannam@89: "\n" cannam@89: ); cannam@89: } cannam@89: cannam@89: exit(3); cannam@89: } cannam@89: #endif cannam@89: cannam@89: cannam@89: /*---------------------------------------------------*/ cannam@89: static cannam@89: int bz_config_ok ( void ) cannam@89: { cannam@89: if (sizeof(int) != 4) return 0; cannam@89: if (sizeof(short) != 2) return 0; cannam@89: if (sizeof(char) != 1) return 0; cannam@89: return 1; cannam@89: } cannam@89: cannam@89: cannam@89: /*---------------------------------------------------*/ cannam@89: static cannam@89: void* default_bzalloc ( void* opaque, Int32 items, Int32 size ) cannam@89: { cannam@89: void* v = malloc ( items * size ); cannam@89: return v; cannam@89: } cannam@89: cannam@89: static cannam@89: void default_bzfree ( void* opaque, void* addr ) cannam@89: { cannam@89: if (addr != NULL) free ( addr ); cannam@89: } cannam@89: cannam@89: cannam@89: /*---------------------------------------------------*/ cannam@89: static cannam@89: void prepare_new_block ( EState* s ) cannam@89: { cannam@89: Int32 i; cannam@89: s->nblock = 0; cannam@89: s->numZ = 0; cannam@89: s->state_out_pos = 0; cannam@89: BZ_INITIALISE_CRC ( s->blockCRC ); cannam@89: for (i = 0; i < 256; i++) s->inUse[i] = False; cannam@89: s->blockNo++; cannam@89: } cannam@89: cannam@89: cannam@89: /*---------------------------------------------------*/ cannam@89: static cannam@89: void init_RL ( EState* s ) cannam@89: { cannam@89: s->state_in_ch = 256; cannam@89: s->state_in_len = 0; cannam@89: } cannam@89: cannam@89: cannam@89: static cannam@89: Bool isempty_RL ( EState* s ) cannam@89: { cannam@89: if (s->state_in_ch < 256 && s->state_in_len > 0) cannam@89: return False; else cannam@89: return True; cannam@89: } cannam@89: cannam@89: cannam@89: /*---------------------------------------------------*/ cannam@89: int BZ_API(BZ2_bzCompressInit) cannam@89: ( bz_stream* strm, cannam@89: int blockSize100k, cannam@89: int verbosity, cannam@89: int workFactor ) cannam@89: { cannam@89: Int32 n; cannam@89: EState* s; cannam@89: cannam@89: if (!bz_config_ok()) return BZ_CONFIG_ERROR; cannam@89: cannam@89: if (strm == NULL || cannam@89: blockSize100k < 1 || blockSize100k > 9 || cannam@89: workFactor < 0 || workFactor > 250) cannam@89: return BZ_PARAM_ERROR; cannam@89: cannam@89: if (workFactor == 0) workFactor = 30; cannam@89: if (strm->bzalloc == NULL) strm->bzalloc = default_bzalloc; cannam@89: if (strm->bzfree == NULL) strm->bzfree = default_bzfree; cannam@89: cannam@89: s = BZALLOC( sizeof(EState) ); cannam@89: if (s == NULL) return BZ_MEM_ERROR; cannam@89: s->strm = strm; cannam@89: cannam@89: s->arr1 = NULL; cannam@89: s->arr2 = NULL; cannam@89: s->ftab = NULL; cannam@89: cannam@89: n = 100000 * blockSize100k; cannam@89: s->arr1 = BZALLOC( n * sizeof(UInt32) ); cannam@89: s->arr2 = BZALLOC( (n+BZ_N_OVERSHOOT) * sizeof(UInt32) ); cannam@89: s->ftab = BZALLOC( 65537 * sizeof(UInt32) ); cannam@89: cannam@89: if (s->arr1 == NULL || s->arr2 == NULL || s->ftab == NULL) { cannam@89: if (s->arr1 != NULL) BZFREE(s->arr1); cannam@89: if (s->arr2 != NULL) BZFREE(s->arr2); cannam@89: if (s->ftab != NULL) BZFREE(s->ftab); cannam@89: if (s != NULL) BZFREE(s); cannam@89: return BZ_MEM_ERROR; cannam@89: } cannam@89: cannam@89: s->blockNo = 0; cannam@89: s->state = BZ_S_INPUT; cannam@89: s->mode = BZ_M_RUNNING; cannam@89: s->combinedCRC = 0; cannam@89: s->blockSize100k = blockSize100k; cannam@89: s->nblockMAX = 100000 * blockSize100k - 19; cannam@89: s->verbosity = verbosity; cannam@89: s->workFactor = workFactor; cannam@89: cannam@89: s->block = (UChar*)s->arr2; cannam@89: s->mtfv = (UInt16*)s->arr1; cannam@89: s->zbits = NULL; cannam@89: s->ptr = (UInt32*)s->arr1; cannam@89: cannam@89: strm->state = s; cannam@89: strm->total_in_lo32 = 0; cannam@89: strm->total_in_hi32 = 0; cannam@89: strm->total_out_lo32 = 0; cannam@89: strm->total_out_hi32 = 0; cannam@89: init_RL ( s ); cannam@89: prepare_new_block ( s ); cannam@89: return BZ_OK; cannam@89: } cannam@89: cannam@89: cannam@89: /*---------------------------------------------------*/ cannam@89: static cannam@89: void add_pair_to_block ( EState* s ) cannam@89: { cannam@89: Int32 i; cannam@89: UChar ch = (UChar)(s->state_in_ch); cannam@89: for (i = 0; i < s->state_in_len; i++) { cannam@89: BZ_UPDATE_CRC( s->blockCRC, ch ); cannam@89: } cannam@89: s->inUse[s->state_in_ch] = True; cannam@89: switch (s->state_in_len) { cannam@89: case 1: cannam@89: s->block[s->nblock] = (UChar)ch; s->nblock++; cannam@89: break; cannam@89: case 2: cannam@89: s->block[s->nblock] = (UChar)ch; s->nblock++; cannam@89: s->block[s->nblock] = (UChar)ch; s->nblock++; cannam@89: break; cannam@89: case 3: cannam@89: s->block[s->nblock] = (UChar)ch; s->nblock++; cannam@89: s->block[s->nblock] = (UChar)ch; s->nblock++; cannam@89: s->block[s->nblock] = (UChar)ch; s->nblock++; cannam@89: break; cannam@89: default: cannam@89: s->inUse[s->state_in_len-4] = True; cannam@89: s->block[s->nblock] = (UChar)ch; s->nblock++; cannam@89: s->block[s->nblock] = (UChar)ch; s->nblock++; cannam@89: s->block[s->nblock] = (UChar)ch; s->nblock++; cannam@89: s->block[s->nblock] = (UChar)ch; s->nblock++; cannam@89: s->block[s->nblock] = ((UChar)(s->state_in_len-4)); cannam@89: s->nblock++; cannam@89: break; cannam@89: } cannam@89: } cannam@89: cannam@89: cannam@89: /*---------------------------------------------------*/ cannam@89: static cannam@89: void flush_RL ( EState* s ) cannam@89: { cannam@89: if (s->state_in_ch < 256) add_pair_to_block ( s ); cannam@89: init_RL ( s ); cannam@89: } cannam@89: cannam@89: cannam@89: /*---------------------------------------------------*/ cannam@89: #define ADD_CHAR_TO_BLOCK(zs,zchh0) \ cannam@89: { \ cannam@89: UInt32 zchh = (UInt32)(zchh0); \ cannam@89: /*-- fast track the common case --*/ \ cannam@89: if (zchh != zs->state_in_ch && \ cannam@89: zs->state_in_len == 1) { \ cannam@89: UChar ch = (UChar)(zs->state_in_ch); \ cannam@89: BZ_UPDATE_CRC( zs->blockCRC, ch ); \ cannam@89: zs->inUse[zs->state_in_ch] = True; \ cannam@89: zs->block[zs->nblock] = (UChar)ch; \ cannam@89: zs->nblock++; \ cannam@89: zs->state_in_ch = zchh; \ cannam@89: } \ cannam@89: else \ cannam@89: /*-- general, uncommon cases --*/ \ cannam@89: if (zchh != zs->state_in_ch || \ cannam@89: zs->state_in_len == 255) { \ cannam@89: if (zs->state_in_ch < 256) \ cannam@89: add_pair_to_block ( zs ); \ cannam@89: zs->state_in_ch = zchh; \ cannam@89: zs->state_in_len = 1; \ cannam@89: } else { \ cannam@89: zs->state_in_len++; \ cannam@89: } \ cannam@89: } cannam@89: cannam@89: cannam@89: /*---------------------------------------------------*/ cannam@89: static cannam@89: Bool copy_input_until_stop ( EState* s ) cannam@89: { cannam@89: Bool progress_in = False; cannam@89: cannam@89: if (s->mode == BZ_M_RUNNING) { cannam@89: cannam@89: /*-- fast track the common case --*/ cannam@89: while (True) { cannam@89: /*-- block full? --*/ cannam@89: if (s->nblock >= s->nblockMAX) break; cannam@89: /*-- no input? --*/ cannam@89: if (s->strm->avail_in == 0) break; cannam@89: progress_in = True; cannam@89: ADD_CHAR_TO_BLOCK ( s, (UInt32)(*((UChar*)(s->strm->next_in))) ); cannam@89: s->strm->next_in++; cannam@89: s->strm->avail_in--; cannam@89: s->strm->total_in_lo32++; cannam@89: if (s->strm->total_in_lo32 == 0) s->strm->total_in_hi32++; cannam@89: } cannam@89: cannam@89: } else { cannam@89: cannam@89: /*-- general, uncommon case --*/ cannam@89: while (True) { cannam@89: /*-- block full? --*/ cannam@89: if (s->nblock >= s->nblockMAX) break; cannam@89: /*-- no input? --*/ cannam@89: if (s->strm->avail_in == 0) break; cannam@89: /*-- flush/finish end? --*/ cannam@89: if (s->avail_in_expect == 0) break; cannam@89: progress_in = True; cannam@89: ADD_CHAR_TO_BLOCK ( s, (UInt32)(*((UChar*)(s->strm->next_in))) ); cannam@89: s->strm->next_in++; cannam@89: s->strm->avail_in--; cannam@89: s->strm->total_in_lo32++; cannam@89: if (s->strm->total_in_lo32 == 0) s->strm->total_in_hi32++; cannam@89: s->avail_in_expect--; cannam@89: } cannam@89: } cannam@89: return progress_in; cannam@89: } cannam@89: cannam@89: cannam@89: /*---------------------------------------------------*/ cannam@89: static cannam@89: Bool copy_output_until_stop ( EState* s ) cannam@89: { cannam@89: Bool progress_out = False; cannam@89: cannam@89: while (True) { cannam@89: cannam@89: /*-- no output space? --*/ cannam@89: if (s->strm->avail_out == 0) break; cannam@89: cannam@89: /*-- block done? --*/ cannam@89: if (s->state_out_pos >= s->numZ) break; cannam@89: cannam@89: progress_out = True; cannam@89: *(s->strm->next_out) = s->zbits[s->state_out_pos]; cannam@89: s->state_out_pos++; cannam@89: s->strm->avail_out--; cannam@89: s->strm->next_out++; cannam@89: s->strm->total_out_lo32++; cannam@89: if (s->strm->total_out_lo32 == 0) s->strm->total_out_hi32++; cannam@89: } cannam@89: cannam@89: return progress_out; cannam@89: } cannam@89: cannam@89: cannam@89: /*---------------------------------------------------*/ cannam@89: static cannam@89: Bool handle_compress ( bz_stream* strm ) cannam@89: { cannam@89: Bool progress_in = False; cannam@89: Bool progress_out = False; cannam@89: EState* s = strm->state; cannam@89: cannam@89: while (True) { cannam@89: cannam@89: if (s->state == BZ_S_OUTPUT) { cannam@89: progress_out |= copy_output_until_stop ( s ); cannam@89: if (s->state_out_pos < s->numZ) break; cannam@89: if (s->mode == BZ_M_FINISHING && cannam@89: s->avail_in_expect == 0 && cannam@89: isempty_RL(s)) break; cannam@89: prepare_new_block ( s ); cannam@89: s->state = BZ_S_INPUT; cannam@89: if (s->mode == BZ_M_FLUSHING && cannam@89: s->avail_in_expect == 0 && cannam@89: isempty_RL(s)) break; cannam@89: } cannam@89: cannam@89: if (s->state == BZ_S_INPUT) { cannam@89: progress_in |= copy_input_until_stop ( s ); cannam@89: if (s->mode != BZ_M_RUNNING && s->avail_in_expect == 0) { cannam@89: flush_RL ( s ); cannam@89: BZ2_compressBlock ( s, (Bool)(s->mode == BZ_M_FINISHING) ); cannam@89: s->state = BZ_S_OUTPUT; cannam@89: } cannam@89: else cannam@89: if (s->nblock >= s->nblockMAX) { cannam@89: BZ2_compressBlock ( s, False ); cannam@89: s->state = BZ_S_OUTPUT; cannam@89: } cannam@89: else cannam@89: if (s->strm->avail_in == 0) { cannam@89: break; cannam@89: } cannam@89: } cannam@89: cannam@89: } cannam@89: cannam@89: return progress_in || progress_out; cannam@89: } cannam@89: cannam@89: cannam@89: /*---------------------------------------------------*/ cannam@89: int BZ_API(BZ2_bzCompress) ( bz_stream *strm, int action ) cannam@89: { cannam@89: Bool progress; cannam@89: EState* s; cannam@89: if (strm == NULL) return BZ_PARAM_ERROR; cannam@89: s = strm->state; cannam@89: if (s == NULL) return BZ_PARAM_ERROR; cannam@89: if (s->strm != strm) return BZ_PARAM_ERROR; cannam@89: cannam@89: preswitch: cannam@89: switch (s->mode) { cannam@89: cannam@89: case BZ_M_IDLE: cannam@89: return BZ_SEQUENCE_ERROR; cannam@89: cannam@89: case BZ_M_RUNNING: cannam@89: if (action == BZ_RUN) { cannam@89: progress = handle_compress ( strm ); cannam@89: return progress ? BZ_RUN_OK : BZ_PARAM_ERROR; cannam@89: } cannam@89: else cannam@89: if (action == BZ_FLUSH) { cannam@89: s->avail_in_expect = strm->avail_in; cannam@89: s->mode = BZ_M_FLUSHING; cannam@89: goto preswitch; cannam@89: } cannam@89: else cannam@89: if (action == BZ_FINISH) { cannam@89: s->avail_in_expect = strm->avail_in; cannam@89: s->mode = BZ_M_FINISHING; cannam@89: goto preswitch; cannam@89: } cannam@89: else cannam@89: return BZ_PARAM_ERROR; cannam@89: cannam@89: case BZ_M_FLUSHING: cannam@89: if (action != BZ_FLUSH) return BZ_SEQUENCE_ERROR; cannam@89: if (s->avail_in_expect != s->strm->avail_in) cannam@89: return BZ_SEQUENCE_ERROR; cannam@89: progress = handle_compress ( strm ); cannam@89: if (s->avail_in_expect > 0 || !isempty_RL(s) || cannam@89: s->state_out_pos < s->numZ) return BZ_FLUSH_OK; cannam@89: s->mode = BZ_M_RUNNING; cannam@89: return BZ_RUN_OK; cannam@89: cannam@89: case BZ_M_FINISHING: cannam@89: if (action != BZ_FINISH) return BZ_SEQUENCE_ERROR; cannam@89: if (s->avail_in_expect != s->strm->avail_in) cannam@89: return BZ_SEQUENCE_ERROR; cannam@89: progress = handle_compress ( strm ); cannam@89: if (!progress) return BZ_SEQUENCE_ERROR; cannam@89: if (s->avail_in_expect > 0 || !isempty_RL(s) || cannam@89: s->state_out_pos < s->numZ) return BZ_FINISH_OK; cannam@89: s->mode = BZ_M_IDLE; cannam@89: return BZ_STREAM_END; cannam@89: } cannam@89: return BZ_OK; /*--not reached--*/ cannam@89: } cannam@89: cannam@89: cannam@89: /*---------------------------------------------------*/ cannam@89: int BZ_API(BZ2_bzCompressEnd) ( bz_stream *strm ) cannam@89: { cannam@89: EState* s; cannam@89: if (strm == NULL) return BZ_PARAM_ERROR; cannam@89: s = strm->state; cannam@89: if (s == NULL) return BZ_PARAM_ERROR; cannam@89: if (s->strm != strm) return BZ_PARAM_ERROR; cannam@89: cannam@89: if (s->arr1 != NULL) BZFREE(s->arr1); cannam@89: if (s->arr2 != NULL) BZFREE(s->arr2); cannam@89: if (s->ftab != NULL) BZFREE(s->ftab); cannam@89: BZFREE(strm->state); cannam@89: cannam@89: strm->state = NULL; cannam@89: cannam@89: return BZ_OK; cannam@89: } cannam@89: cannam@89: cannam@89: /*---------------------------------------------------*/ cannam@89: /*--- Decompression stuff ---*/ cannam@89: /*---------------------------------------------------*/ cannam@89: cannam@89: /*---------------------------------------------------*/ cannam@89: int BZ_API(BZ2_bzDecompressInit) cannam@89: ( bz_stream* strm, cannam@89: int verbosity, cannam@89: int small ) cannam@89: { cannam@89: DState* s; cannam@89: cannam@89: if (!bz_config_ok()) return BZ_CONFIG_ERROR; cannam@89: cannam@89: if (strm == NULL) return BZ_PARAM_ERROR; cannam@89: if (small != 0 && small != 1) return BZ_PARAM_ERROR; cannam@89: if (verbosity < 0 || verbosity > 4) return BZ_PARAM_ERROR; cannam@89: cannam@89: if (strm->bzalloc == NULL) strm->bzalloc = default_bzalloc; cannam@89: if (strm->bzfree == NULL) strm->bzfree = default_bzfree; cannam@89: cannam@89: s = BZALLOC( sizeof(DState) ); cannam@89: if (s == NULL) return BZ_MEM_ERROR; cannam@89: s->strm = strm; cannam@89: strm->state = s; cannam@89: s->state = BZ_X_MAGIC_1; cannam@89: s->bsLive = 0; cannam@89: s->bsBuff = 0; cannam@89: s->calculatedCombinedCRC = 0; cannam@89: strm->total_in_lo32 = 0; cannam@89: strm->total_in_hi32 = 0; cannam@89: strm->total_out_lo32 = 0; cannam@89: strm->total_out_hi32 = 0; cannam@89: s->smallDecompress = (Bool)small; cannam@89: s->ll4 = NULL; cannam@89: s->ll16 = NULL; cannam@89: s->tt = NULL; cannam@89: s->currBlockNo = 0; cannam@89: s->verbosity = verbosity; cannam@89: cannam@89: return BZ_OK; cannam@89: } cannam@89: cannam@89: cannam@89: /*---------------------------------------------------*/ cannam@89: /* Return True iff data corruption is discovered. cannam@89: Returns False if there is no problem. cannam@89: */ cannam@89: static cannam@89: Bool unRLE_obuf_to_output_FAST ( DState* s ) cannam@89: { cannam@89: UChar k1; cannam@89: cannam@89: if (s->blockRandomised) { cannam@89: cannam@89: while (True) { cannam@89: /* try to finish existing run */ cannam@89: while (True) { cannam@89: if (s->strm->avail_out == 0) return False; cannam@89: if (s->state_out_len == 0) break; cannam@89: *( (UChar*)(s->strm->next_out) ) = s->state_out_ch; cannam@89: BZ_UPDATE_CRC ( s->calculatedBlockCRC, s->state_out_ch ); cannam@89: s->state_out_len--; cannam@89: s->strm->next_out++; cannam@89: s->strm->avail_out--; cannam@89: s->strm->total_out_lo32++; cannam@89: if (s->strm->total_out_lo32 == 0) s->strm->total_out_hi32++; cannam@89: } cannam@89: cannam@89: /* can a new run be started? */ cannam@89: if (s->nblock_used == s->save_nblock+1) return False; cannam@89: cannam@89: /* Only caused by corrupt data stream? */ cannam@89: if (s->nblock_used > s->save_nblock+1) cannam@89: return True; cannam@89: cannam@89: s->state_out_len = 1; cannam@89: s->state_out_ch = s->k0; cannam@89: BZ_GET_FAST(k1); BZ_RAND_UPD_MASK; cannam@89: k1 ^= BZ_RAND_MASK; s->nblock_used++; cannam@89: if (s->nblock_used == s->save_nblock+1) continue; cannam@89: if (k1 != s->k0) { s->k0 = k1; continue; }; cannam@89: cannam@89: s->state_out_len = 2; cannam@89: BZ_GET_FAST(k1); BZ_RAND_UPD_MASK; cannam@89: k1 ^= BZ_RAND_MASK; s->nblock_used++; cannam@89: if (s->nblock_used == s->save_nblock+1) continue; cannam@89: if (k1 != s->k0) { s->k0 = k1; continue; }; cannam@89: cannam@89: s->state_out_len = 3; cannam@89: BZ_GET_FAST(k1); BZ_RAND_UPD_MASK; cannam@89: k1 ^= BZ_RAND_MASK; s->nblock_used++; cannam@89: if (s->nblock_used == s->save_nblock+1) continue; cannam@89: if (k1 != s->k0) { s->k0 = k1; continue; }; cannam@89: cannam@89: BZ_GET_FAST(k1); BZ_RAND_UPD_MASK; cannam@89: k1 ^= BZ_RAND_MASK; s->nblock_used++; cannam@89: s->state_out_len = ((Int32)k1) + 4; cannam@89: BZ_GET_FAST(s->k0); BZ_RAND_UPD_MASK; cannam@89: s->k0 ^= BZ_RAND_MASK; s->nblock_used++; cannam@89: } cannam@89: cannam@89: } else { cannam@89: cannam@89: /* restore */ cannam@89: UInt32 c_calculatedBlockCRC = s->calculatedBlockCRC; cannam@89: UChar c_state_out_ch = s->state_out_ch; cannam@89: Int32 c_state_out_len = s->state_out_len; cannam@89: Int32 c_nblock_used = s->nblock_used; cannam@89: Int32 c_k0 = s->k0; cannam@89: UInt32* c_tt = s->tt; cannam@89: UInt32 c_tPos = s->tPos; cannam@89: char* cs_next_out = s->strm->next_out; cannam@89: unsigned int cs_avail_out = s->strm->avail_out; cannam@89: Int32 ro_blockSize100k = s->blockSize100k; cannam@89: /* end restore */ cannam@89: cannam@89: UInt32 avail_out_INIT = cs_avail_out; cannam@89: Int32 s_save_nblockPP = s->save_nblock+1; cannam@89: unsigned int total_out_lo32_old; cannam@89: cannam@89: while (True) { cannam@89: cannam@89: /* try to finish existing run */ cannam@89: if (c_state_out_len > 0) { cannam@89: while (True) { cannam@89: if (cs_avail_out == 0) goto return_notr; cannam@89: if (c_state_out_len == 1) break; cannam@89: *( (UChar*)(cs_next_out) ) = c_state_out_ch; cannam@89: BZ_UPDATE_CRC ( c_calculatedBlockCRC, c_state_out_ch ); cannam@89: c_state_out_len--; cannam@89: cs_next_out++; cannam@89: cs_avail_out--; cannam@89: } cannam@89: s_state_out_len_eq_one: cannam@89: { cannam@89: if (cs_avail_out == 0) { cannam@89: c_state_out_len = 1; goto return_notr; cannam@89: }; cannam@89: *( (UChar*)(cs_next_out) ) = c_state_out_ch; cannam@89: BZ_UPDATE_CRC ( c_calculatedBlockCRC, c_state_out_ch ); cannam@89: cs_next_out++; cannam@89: cs_avail_out--; cannam@89: } cannam@89: } cannam@89: /* Only caused by corrupt data stream? */ cannam@89: if (c_nblock_used > s_save_nblockPP) cannam@89: return True; cannam@89: cannam@89: /* can a new run be started? */ cannam@89: if (c_nblock_used == s_save_nblockPP) { cannam@89: c_state_out_len = 0; goto return_notr; cannam@89: }; cannam@89: c_state_out_ch = c_k0; cannam@89: BZ_GET_FAST_C(k1); c_nblock_used++; cannam@89: if (k1 != c_k0) { cannam@89: c_k0 = k1; goto s_state_out_len_eq_one; cannam@89: }; cannam@89: if (c_nblock_used == s_save_nblockPP) cannam@89: goto s_state_out_len_eq_one; cannam@89: cannam@89: c_state_out_len = 2; cannam@89: BZ_GET_FAST_C(k1); c_nblock_used++; cannam@89: if (c_nblock_used == s_save_nblockPP) continue; cannam@89: if (k1 != c_k0) { c_k0 = k1; continue; }; cannam@89: cannam@89: c_state_out_len = 3; cannam@89: BZ_GET_FAST_C(k1); c_nblock_used++; cannam@89: if (c_nblock_used == s_save_nblockPP) continue; cannam@89: if (k1 != c_k0) { c_k0 = k1; continue; }; cannam@89: cannam@89: BZ_GET_FAST_C(k1); c_nblock_used++; cannam@89: c_state_out_len = ((Int32)k1) + 4; cannam@89: BZ_GET_FAST_C(c_k0); c_nblock_used++; cannam@89: } cannam@89: cannam@89: return_notr: cannam@89: total_out_lo32_old = s->strm->total_out_lo32; cannam@89: s->strm->total_out_lo32 += (avail_out_INIT - cs_avail_out); cannam@89: if (s->strm->total_out_lo32 < total_out_lo32_old) cannam@89: s->strm->total_out_hi32++; cannam@89: cannam@89: /* save */ cannam@89: s->calculatedBlockCRC = c_calculatedBlockCRC; cannam@89: s->state_out_ch = c_state_out_ch; cannam@89: s->state_out_len = c_state_out_len; cannam@89: s->nblock_used = c_nblock_used; cannam@89: s->k0 = c_k0; cannam@89: s->tt = c_tt; cannam@89: s->tPos = c_tPos; cannam@89: s->strm->next_out = cs_next_out; cannam@89: s->strm->avail_out = cs_avail_out; cannam@89: /* end save */ cannam@89: } cannam@89: return False; cannam@89: } cannam@89: cannam@89: cannam@89: cannam@89: /*---------------------------------------------------*/ cannam@89: __inline__ Int32 BZ2_indexIntoF ( Int32 indx, Int32 *cftab ) cannam@89: { cannam@89: Int32 nb, na, mid; cannam@89: nb = 0; cannam@89: na = 256; cannam@89: do { cannam@89: mid = (nb + na) >> 1; cannam@89: if (indx >= cftab[mid]) nb = mid; else na = mid; cannam@89: } cannam@89: while (na - nb != 1); cannam@89: return nb; cannam@89: } cannam@89: cannam@89: cannam@89: /*---------------------------------------------------*/ cannam@89: /* Return True iff data corruption is discovered. cannam@89: Returns False if there is no problem. cannam@89: */ cannam@89: static cannam@89: Bool unRLE_obuf_to_output_SMALL ( DState* s ) cannam@89: { cannam@89: UChar k1; cannam@89: cannam@89: if (s->blockRandomised) { cannam@89: cannam@89: while (True) { cannam@89: /* try to finish existing run */ cannam@89: while (True) { cannam@89: if (s->strm->avail_out == 0) return False; cannam@89: if (s->state_out_len == 0) break; cannam@89: *( (UChar*)(s->strm->next_out) ) = s->state_out_ch; cannam@89: BZ_UPDATE_CRC ( s->calculatedBlockCRC, s->state_out_ch ); cannam@89: s->state_out_len--; cannam@89: s->strm->next_out++; cannam@89: s->strm->avail_out--; cannam@89: s->strm->total_out_lo32++; cannam@89: if (s->strm->total_out_lo32 == 0) s->strm->total_out_hi32++; cannam@89: } cannam@89: cannam@89: /* can a new run be started? */ cannam@89: if (s->nblock_used == s->save_nblock+1) return False; cannam@89: cannam@89: /* Only caused by corrupt data stream? */ cannam@89: if (s->nblock_used > s->save_nblock+1) cannam@89: return True; cannam@89: cannam@89: s->state_out_len = 1; cannam@89: s->state_out_ch = s->k0; cannam@89: BZ_GET_SMALL(k1); BZ_RAND_UPD_MASK; cannam@89: k1 ^= BZ_RAND_MASK; s->nblock_used++; cannam@89: if (s->nblock_used == s->save_nblock+1) continue; cannam@89: if (k1 != s->k0) { s->k0 = k1; continue; }; cannam@89: cannam@89: s->state_out_len = 2; cannam@89: BZ_GET_SMALL(k1); BZ_RAND_UPD_MASK; cannam@89: k1 ^= BZ_RAND_MASK; s->nblock_used++; cannam@89: if (s->nblock_used == s->save_nblock+1) continue; cannam@89: if (k1 != s->k0) { s->k0 = k1; continue; }; cannam@89: cannam@89: s->state_out_len = 3; cannam@89: BZ_GET_SMALL(k1); BZ_RAND_UPD_MASK; cannam@89: k1 ^= BZ_RAND_MASK; s->nblock_used++; cannam@89: if (s->nblock_used == s->save_nblock+1) continue; cannam@89: if (k1 != s->k0) { s->k0 = k1; continue; }; cannam@89: cannam@89: BZ_GET_SMALL(k1); BZ_RAND_UPD_MASK; cannam@89: k1 ^= BZ_RAND_MASK; s->nblock_used++; cannam@89: s->state_out_len = ((Int32)k1) + 4; cannam@89: BZ_GET_SMALL(s->k0); BZ_RAND_UPD_MASK; cannam@89: s->k0 ^= BZ_RAND_MASK; s->nblock_used++; cannam@89: } cannam@89: cannam@89: } else { cannam@89: cannam@89: while (True) { cannam@89: /* try to finish existing run */ cannam@89: while (True) { cannam@89: if (s->strm->avail_out == 0) return False; cannam@89: if (s->state_out_len == 0) break; cannam@89: *( (UChar*)(s->strm->next_out) ) = s->state_out_ch; cannam@89: BZ_UPDATE_CRC ( s->calculatedBlockCRC, s->state_out_ch ); cannam@89: s->state_out_len--; cannam@89: s->strm->next_out++; cannam@89: s->strm->avail_out--; cannam@89: s->strm->total_out_lo32++; cannam@89: if (s->strm->total_out_lo32 == 0) s->strm->total_out_hi32++; cannam@89: } cannam@89: cannam@89: /* can a new run be started? */ cannam@89: if (s->nblock_used == s->save_nblock+1) return False; cannam@89: cannam@89: /* Only caused by corrupt data stream? */ cannam@89: if (s->nblock_used > s->save_nblock+1) cannam@89: return True; cannam@89: cannam@89: s->state_out_len = 1; cannam@89: s->state_out_ch = s->k0; cannam@89: BZ_GET_SMALL(k1); s->nblock_used++; cannam@89: if (s->nblock_used == s->save_nblock+1) continue; cannam@89: if (k1 != s->k0) { s->k0 = k1; continue; }; cannam@89: cannam@89: s->state_out_len = 2; cannam@89: BZ_GET_SMALL(k1); s->nblock_used++; cannam@89: if (s->nblock_used == s->save_nblock+1) continue; cannam@89: if (k1 != s->k0) { s->k0 = k1; continue; }; cannam@89: cannam@89: s->state_out_len = 3; cannam@89: BZ_GET_SMALL(k1); s->nblock_used++; cannam@89: if (s->nblock_used == s->save_nblock+1) continue; cannam@89: if (k1 != s->k0) { s->k0 = k1; continue; }; cannam@89: cannam@89: BZ_GET_SMALL(k1); s->nblock_used++; cannam@89: s->state_out_len = ((Int32)k1) + 4; cannam@89: BZ_GET_SMALL(s->k0); s->nblock_used++; cannam@89: } cannam@89: cannam@89: } cannam@89: } cannam@89: cannam@89: cannam@89: /*---------------------------------------------------*/ cannam@89: int BZ_API(BZ2_bzDecompress) ( bz_stream *strm ) cannam@89: { cannam@89: Bool corrupt; cannam@89: DState* s; cannam@89: if (strm == NULL) return BZ_PARAM_ERROR; cannam@89: s = strm->state; cannam@89: if (s == NULL) return BZ_PARAM_ERROR; cannam@89: if (s->strm != strm) return BZ_PARAM_ERROR; cannam@89: cannam@89: while (True) { cannam@89: if (s->state == BZ_X_IDLE) return BZ_SEQUENCE_ERROR; cannam@89: if (s->state == BZ_X_OUTPUT) { cannam@89: if (s->smallDecompress) cannam@89: corrupt = unRLE_obuf_to_output_SMALL ( s ); else cannam@89: corrupt = unRLE_obuf_to_output_FAST ( s ); cannam@89: if (corrupt) return BZ_DATA_ERROR; cannam@89: if (s->nblock_used == s->save_nblock+1 && s->state_out_len == 0) { cannam@89: BZ_FINALISE_CRC ( s->calculatedBlockCRC ); cannam@89: if (s->verbosity >= 3) cannam@89: VPrintf2 ( " {0x%08x, 0x%08x}", s->storedBlockCRC, cannam@89: s->calculatedBlockCRC ); cannam@89: if (s->verbosity >= 2) VPrintf0 ( "]" ); cannam@89: if (s->calculatedBlockCRC != s->storedBlockCRC) cannam@89: return BZ_DATA_ERROR; cannam@89: s->calculatedCombinedCRC cannam@89: = (s->calculatedCombinedCRC << 1) | cannam@89: (s->calculatedCombinedCRC >> 31); cannam@89: s->calculatedCombinedCRC ^= s->calculatedBlockCRC; cannam@89: s->state = BZ_X_BLKHDR_1; cannam@89: } else { cannam@89: return BZ_OK; cannam@89: } cannam@89: } cannam@89: if (s->state >= BZ_X_MAGIC_1) { cannam@89: Int32 r = BZ2_decompress ( s ); cannam@89: if (r == BZ_STREAM_END) { cannam@89: if (s->verbosity >= 3) cannam@89: VPrintf2 ( "\n combined CRCs: stored = 0x%08x, computed = 0x%08x", cannam@89: s->storedCombinedCRC, s->calculatedCombinedCRC ); cannam@89: if (s->calculatedCombinedCRC != s->storedCombinedCRC) cannam@89: return BZ_DATA_ERROR; cannam@89: return r; cannam@89: } cannam@89: if (s->state != BZ_X_OUTPUT) return r; cannam@89: } cannam@89: } cannam@89: cannam@89: AssertH ( 0, 6001 ); cannam@89: cannam@89: return 0; /*NOTREACHED*/ cannam@89: } cannam@89: cannam@89: cannam@89: /*---------------------------------------------------*/ cannam@89: int BZ_API(BZ2_bzDecompressEnd) ( bz_stream *strm ) cannam@89: { cannam@89: DState* s; cannam@89: if (strm == NULL) return BZ_PARAM_ERROR; cannam@89: s = strm->state; cannam@89: if (s == NULL) return BZ_PARAM_ERROR; cannam@89: if (s->strm != strm) return BZ_PARAM_ERROR; cannam@89: cannam@89: if (s->tt != NULL) BZFREE(s->tt); cannam@89: if (s->ll16 != NULL) BZFREE(s->ll16); cannam@89: if (s->ll4 != NULL) BZFREE(s->ll4); cannam@89: cannam@89: BZFREE(strm->state); cannam@89: strm->state = NULL; cannam@89: cannam@89: return BZ_OK; cannam@89: } cannam@89: cannam@89: cannam@89: #ifndef BZ_NO_STDIO cannam@89: /*---------------------------------------------------*/ cannam@89: /*--- File I/O stuff ---*/ cannam@89: /*---------------------------------------------------*/ cannam@89: cannam@89: #define BZ_SETERR(eee) \ cannam@89: { \ cannam@89: if (bzerror != NULL) *bzerror = eee; \ cannam@89: if (bzf != NULL) bzf->lastErr = eee; \ cannam@89: } cannam@89: cannam@89: typedef cannam@89: struct { cannam@89: FILE* handle; cannam@89: Char buf[BZ_MAX_UNUSED]; cannam@89: Int32 bufN; cannam@89: Bool writing; cannam@89: bz_stream strm; cannam@89: Int32 lastErr; cannam@89: Bool initialisedOk; cannam@89: } cannam@89: bzFile; cannam@89: cannam@89: cannam@89: /*---------------------------------------------*/ cannam@89: static Bool myfeof ( FILE* f ) cannam@89: { cannam@89: Int32 c = fgetc ( f ); cannam@89: if (c == EOF) return True; cannam@89: ungetc ( c, f ); cannam@89: return False; cannam@89: } cannam@89: cannam@89: cannam@89: /*---------------------------------------------------*/ cannam@89: BZFILE* BZ_API(BZ2_bzWriteOpen) cannam@89: ( int* bzerror, cannam@89: FILE* f, cannam@89: int blockSize100k, cannam@89: int verbosity, cannam@89: int workFactor ) cannam@89: { cannam@89: Int32 ret; cannam@89: bzFile* bzf = NULL; cannam@89: cannam@89: BZ_SETERR(BZ_OK); cannam@89: cannam@89: if (f == NULL || cannam@89: (blockSize100k < 1 || blockSize100k > 9) || cannam@89: (workFactor < 0 || workFactor > 250) || cannam@89: (verbosity < 0 || verbosity > 4)) cannam@89: { BZ_SETERR(BZ_PARAM_ERROR); return NULL; }; cannam@89: cannam@89: if (ferror(f)) cannam@89: { BZ_SETERR(BZ_IO_ERROR); return NULL; }; cannam@89: cannam@89: bzf = malloc ( sizeof(bzFile) ); cannam@89: if (bzf == NULL) cannam@89: { BZ_SETERR(BZ_MEM_ERROR); return NULL; }; cannam@89: cannam@89: BZ_SETERR(BZ_OK); cannam@89: bzf->initialisedOk = False; cannam@89: bzf->bufN = 0; cannam@89: bzf->handle = f; cannam@89: bzf->writing = True; cannam@89: bzf->strm.bzalloc = NULL; cannam@89: bzf->strm.bzfree = NULL; cannam@89: bzf->strm.opaque = NULL; cannam@89: cannam@89: if (workFactor == 0) workFactor = 30; cannam@89: ret = BZ2_bzCompressInit ( &(bzf->strm), blockSize100k, cannam@89: verbosity, workFactor ); cannam@89: if (ret != BZ_OK) cannam@89: { BZ_SETERR(ret); free(bzf); return NULL; }; cannam@89: cannam@89: bzf->strm.avail_in = 0; cannam@89: bzf->initialisedOk = True; cannam@89: return bzf; cannam@89: } cannam@89: cannam@89: cannam@89: cannam@89: /*---------------------------------------------------*/ cannam@89: void BZ_API(BZ2_bzWrite) cannam@89: ( int* bzerror, cannam@89: BZFILE* b, cannam@89: void* buf, cannam@89: int len ) cannam@89: { cannam@89: Int32 n, n2, ret; cannam@89: bzFile* bzf = (bzFile*)b; cannam@89: cannam@89: BZ_SETERR(BZ_OK); cannam@89: if (bzf == NULL || buf == NULL || len < 0) cannam@89: { BZ_SETERR(BZ_PARAM_ERROR); return; }; cannam@89: if (!(bzf->writing)) cannam@89: { BZ_SETERR(BZ_SEQUENCE_ERROR); return; }; cannam@89: if (ferror(bzf->handle)) cannam@89: { BZ_SETERR(BZ_IO_ERROR); return; }; cannam@89: cannam@89: if (len == 0) cannam@89: { BZ_SETERR(BZ_OK); return; }; cannam@89: cannam@89: bzf->strm.avail_in = len; cannam@89: bzf->strm.next_in = buf; cannam@89: cannam@89: while (True) { cannam@89: bzf->strm.avail_out = BZ_MAX_UNUSED; cannam@89: bzf->strm.next_out = bzf->buf; cannam@89: ret = BZ2_bzCompress ( &(bzf->strm), BZ_RUN ); cannam@89: if (ret != BZ_RUN_OK) cannam@89: { BZ_SETERR(ret); return; }; cannam@89: cannam@89: if (bzf->strm.avail_out < BZ_MAX_UNUSED) { cannam@89: n = BZ_MAX_UNUSED - bzf->strm.avail_out; cannam@89: n2 = fwrite ( (void*)(bzf->buf), sizeof(UChar), cannam@89: n, bzf->handle ); cannam@89: if (n != n2 || ferror(bzf->handle)) cannam@89: { BZ_SETERR(BZ_IO_ERROR); return; }; cannam@89: } cannam@89: cannam@89: if (bzf->strm.avail_in == 0) cannam@89: { BZ_SETERR(BZ_OK); return; }; cannam@89: } cannam@89: } cannam@89: cannam@89: cannam@89: /*---------------------------------------------------*/ cannam@89: void BZ_API(BZ2_bzWriteClose) cannam@89: ( int* bzerror, cannam@89: BZFILE* b, cannam@89: int abandon, cannam@89: unsigned int* nbytes_in, cannam@89: unsigned int* nbytes_out ) cannam@89: { cannam@89: BZ2_bzWriteClose64 ( bzerror, b, abandon, cannam@89: nbytes_in, NULL, nbytes_out, NULL ); cannam@89: } cannam@89: cannam@89: cannam@89: void BZ_API(BZ2_bzWriteClose64) cannam@89: ( int* bzerror, cannam@89: BZFILE* b, cannam@89: int abandon, cannam@89: unsigned int* nbytes_in_lo32, cannam@89: unsigned int* nbytes_in_hi32, cannam@89: unsigned int* nbytes_out_lo32, cannam@89: unsigned int* nbytes_out_hi32 ) cannam@89: { cannam@89: Int32 n, n2, ret; cannam@89: bzFile* bzf = (bzFile*)b; cannam@89: cannam@89: if (bzf == NULL) cannam@89: { BZ_SETERR(BZ_OK); return; }; cannam@89: if (!(bzf->writing)) cannam@89: { BZ_SETERR(BZ_SEQUENCE_ERROR); return; }; cannam@89: if (ferror(bzf->handle)) cannam@89: { BZ_SETERR(BZ_IO_ERROR); return; }; cannam@89: cannam@89: if (nbytes_in_lo32 != NULL) *nbytes_in_lo32 = 0; cannam@89: if (nbytes_in_hi32 != NULL) *nbytes_in_hi32 = 0; cannam@89: if (nbytes_out_lo32 != NULL) *nbytes_out_lo32 = 0; cannam@89: if (nbytes_out_hi32 != NULL) *nbytes_out_hi32 = 0; cannam@89: cannam@89: if ((!abandon) && bzf->lastErr == BZ_OK) { cannam@89: while (True) { cannam@89: bzf->strm.avail_out = BZ_MAX_UNUSED; cannam@89: bzf->strm.next_out = bzf->buf; cannam@89: ret = BZ2_bzCompress ( &(bzf->strm), BZ_FINISH ); cannam@89: if (ret != BZ_FINISH_OK && ret != BZ_STREAM_END) cannam@89: { BZ_SETERR(ret); return; }; cannam@89: cannam@89: if (bzf->strm.avail_out < BZ_MAX_UNUSED) { cannam@89: n = BZ_MAX_UNUSED - bzf->strm.avail_out; cannam@89: n2 = fwrite ( (void*)(bzf->buf), sizeof(UChar), cannam@89: n, bzf->handle ); cannam@89: if (n != n2 || ferror(bzf->handle)) cannam@89: { BZ_SETERR(BZ_IO_ERROR); return; }; cannam@89: } cannam@89: cannam@89: if (ret == BZ_STREAM_END) break; cannam@89: } cannam@89: } cannam@89: cannam@89: if ( !abandon && !ferror ( bzf->handle ) ) { cannam@89: fflush ( bzf->handle ); cannam@89: if (ferror(bzf->handle)) cannam@89: { BZ_SETERR(BZ_IO_ERROR); return; }; cannam@89: } cannam@89: cannam@89: if (nbytes_in_lo32 != NULL) cannam@89: *nbytes_in_lo32 = bzf->strm.total_in_lo32; cannam@89: if (nbytes_in_hi32 != NULL) cannam@89: *nbytes_in_hi32 = bzf->strm.total_in_hi32; cannam@89: if (nbytes_out_lo32 != NULL) cannam@89: *nbytes_out_lo32 = bzf->strm.total_out_lo32; cannam@89: if (nbytes_out_hi32 != NULL) cannam@89: *nbytes_out_hi32 = bzf->strm.total_out_hi32; cannam@89: cannam@89: BZ_SETERR(BZ_OK); cannam@89: BZ2_bzCompressEnd ( &(bzf->strm) ); cannam@89: free ( bzf ); cannam@89: } cannam@89: cannam@89: cannam@89: /*---------------------------------------------------*/ cannam@89: BZFILE* BZ_API(BZ2_bzReadOpen) cannam@89: ( int* bzerror, cannam@89: FILE* f, cannam@89: int verbosity, cannam@89: int small, cannam@89: void* unused, cannam@89: int nUnused ) cannam@89: { cannam@89: bzFile* bzf = NULL; cannam@89: int ret; cannam@89: cannam@89: BZ_SETERR(BZ_OK); cannam@89: cannam@89: if (f == NULL || cannam@89: (small != 0 && small != 1) || cannam@89: (verbosity < 0 || verbosity > 4) || cannam@89: (unused == NULL && nUnused != 0) || cannam@89: (unused != NULL && (nUnused < 0 || nUnused > BZ_MAX_UNUSED))) cannam@89: { BZ_SETERR(BZ_PARAM_ERROR); return NULL; }; cannam@89: cannam@89: if (ferror(f)) cannam@89: { BZ_SETERR(BZ_IO_ERROR); return NULL; }; cannam@89: cannam@89: bzf = malloc ( sizeof(bzFile) ); cannam@89: if (bzf == NULL) cannam@89: { BZ_SETERR(BZ_MEM_ERROR); return NULL; }; cannam@89: cannam@89: BZ_SETERR(BZ_OK); cannam@89: cannam@89: bzf->initialisedOk = False; cannam@89: bzf->handle = f; cannam@89: bzf->bufN = 0; cannam@89: bzf->writing = False; cannam@89: bzf->strm.bzalloc = NULL; cannam@89: bzf->strm.bzfree = NULL; cannam@89: bzf->strm.opaque = NULL; cannam@89: cannam@89: while (nUnused > 0) { cannam@89: bzf->buf[bzf->bufN] = *((UChar*)(unused)); bzf->bufN++; cannam@89: unused = ((void*)( 1 + ((UChar*)(unused)) )); cannam@89: nUnused--; cannam@89: } cannam@89: cannam@89: ret = BZ2_bzDecompressInit ( &(bzf->strm), verbosity, small ); cannam@89: if (ret != BZ_OK) cannam@89: { BZ_SETERR(ret); free(bzf); return NULL; }; cannam@89: cannam@89: bzf->strm.avail_in = bzf->bufN; cannam@89: bzf->strm.next_in = bzf->buf; cannam@89: cannam@89: bzf->initialisedOk = True; cannam@89: return bzf; cannam@89: } cannam@89: cannam@89: cannam@89: /*---------------------------------------------------*/ cannam@89: void BZ_API(BZ2_bzReadClose) ( int *bzerror, BZFILE *b ) cannam@89: { cannam@89: bzFile* bzf = (bzFile*)b; cannam@89: cannam@89: BZ_SETERR(BZ_OK); cannam@89: if (bzf == NULL) cannam@89: { BZ_SETERR(BZ_OK); return; }; cannam@89: cannam@89: if (bzf->writing) cannam@89: { BZ_SETERR(BZ_SEQUENCE_ERROR); return; }; cannam@89: cannam@89: if (bzf->initialisedOk) cannam@89: (void)BZ2_bzDecompressEnd ( &(bzf->strm) ); cannam@89: free ( bzf ); cannam@89: } cannam@89: cannam@89: cannam@89: /*---------------------------------------------------*/ cannam@89: int BZ_API(BZ2_bzRead) cannam@89: ( int* bzerror, cannam@89: BZFILE* b, cannam@89: void* buf, cannam@89: int len ) cannam@89: { cannam@89: Int32 n, ret; cannam@89: bzFile* bzf = (bzFile*)b; cannam@89: cannam@89: BZ_SETERR(BZ_OK); cannam@89: cannam@89: if (bzf == NULL || buf == NULL || len < 0) cannam@89: { BZ_SETERR(BZ_PARAM_ERROR); return 0; }; cannam@89: cannam@89: if (bzf->writing) cannam@89: { BZ_SETERR(BZ_SEQUENCE_ERROR); return 0; }; cannam@89: cannam@89: if (len == 0) cannam@89: { BZ_SETERR(BZ_OK); return 0; }; cannam@89: cannam@89: bzf->strm.avail_out = len; cannam@89: bzf->strm.next_out = buf; cannam@89: cannam@89: while (True) { cannam@89: cannam@89: if (ferror(bzf->handle)) cannam@89: { BZ_SETERR(BZ_IO_ERROR); return 0; }; cannam@89: cannam@89: if (bzf->strm.avail_in == 0 && !myfeof(bzf->handle)) { cannam@89: n = fread ( bzf->buf, sizeof(UChar), cannam@89: BZ_MAX_UNUSED, bzf->handle ); cannam@89: if (ferror(bzf->handle)) cannam@89: { BZ_SETERR(BZ_IO_ERROR); return 0; }; cannam@89: bzf->bufN = n; cannam@89: bzf->strm.avail_in = bzf->bufN; cannam@89: bzf->strm.next_in = bzf->buf; cannam@89: } cannam@89: cannam@89: ret = BZ2_bzDecompress ( &(bzf->strm) ); cannam@89: cannam@89: if (ret != BZ_OK && ret != BZ_STREAM_END) cannam@89: { BZ_SETERR(ret); return 0; }; cannam@89: cannam@89: if (ret == BZ_OK && myfeof(bzf->handle) && cannam@89: bzf->strm.avail_in == 0 && bzf->strm.avail_out > 0) cannam@89: { BZ_SETERR(BZ_UNEXPECTED_EOF); return 0; }; cannam@89: cannam@89: if (ret == BZ_STREAM_END) cannam@89: { BZ_SETERR(BZ_STREAM_END); cannam@89: return len - bzf->strm.avail_out; }; cannam@89: if (bzf->strm.avail_out == 0) cannam@89: { BZ_SETERR(BZ_OK); return len; }; cannam@89: cannam@89: } cannam@89: cannam@89: return 0; /*not reached*/ cannam@89: } cannam@89: cannam@89: cannam@89: /*---------------------------------------------------*/ cannam@89: void BZ_API(BZ2_bzReadGetUnused) cannam@89: ( int* bzerror, cannam@89: BZFILE* b, cannam@89: void** unused, cannam@89: int* nUnused ) cannam@89: { cannam@89: bzFile* bzf = (bzFile*)b; cannam@89: if (bzf == NULL) cannam@89: { BZ_SETERR(BZ_PARAM_ERROR); return; }; cannam@89: if (bzf->lastErr != BZ_STREAM_END) cannam@89: { BZ_SETERR(BZ_SEQUENCE_ERROR); return; }; cannam@89: if (unused == NULL || nUnused == NULL) cannam@89: { BZ_SETERR(BZ_PARAM_ERROR); return; }; cannam@89: cannam@89: BZ_SETERR(BZ_OK); cannam@89: *nUnused = bzf->strm.avail_in; cannam@89: *unused = bzf->strm.next_in; cannam@89: } cannam@89: #endif cannam@89: cannam@89: cannam@89: /*---------------------------------------------------*/ cannam@89: /*--- Misc convenience stuff ---*/ cannam@89: /*---------------------------------------------------*/ cannam@89: cannam@89: /*---------------------------------------------------*/ cannam@89: int BZ_API(BZ2_bzBuffToBuffCompress) cannam@89: ( char* dest, cannam@89: unsigned int* destLen, cannam@89: char* source, cannam@89: unsigned int sourceLen, cannam@89: int blockSize100k, cannam@89: int verbosity, cannam@89: int workFactor ) cannam@89: { cannam@89: bz_stream strm; cannam@89: int ret; cannam@89: cannam@89: if (dest == NULL || destLen == NULL || cannam@89: source == NULL || cannam@89: blockSize100k < 1 || blockSize100k > 9 || cannam@89: verbosity < 0 || verbosity > 4 || cannam@89: workFactor < 0 || workFactor > 250) cannam@89: return BZ_PARAM_ERROR; cannam@89: cannam@89: if (workFactor == 0) workFactor = 30; cannam@89: strm.bzalloc = NULL; cannam@89: strm.bzfree = NULL; cannam@89: strm.opaque = NULL; cannam@89: ret = BZ2_bzCompressInit ( &strm, blockSize100k, cannam@89: verbosity, workFactor ); cannam@89: if (ret != BZ_OK) return ret; cannam@89: cannam@89: strm.next_in = source; cannam@89: strm.next_out = dest; cannam@89: strm.avail_in = sourceLen; cannam@89: strm.avail_out = *destLen; cannam@89: cannam@89: ret = BZ2_bzCompress ( &strm, BZ_FINISH ); cannam@89: if (ret == BZ_FINISH_OK) goto output_overflow; cannam@89: if (ret != BZ_STREAM_END) goto errhandler; cannam@89: cannam@89: /* normal termination */ cannam@89: *destLen -= strm.avail_out; cannam@89: BZ2_bzCompressEnd ( &strm ); cannam@89: return BZ_OK; cannam@89: cannam@89: output_overflow: cannam@89: BZ2_bzCompressEnd ( &strm ); cannam@89: return BZ_OUTBUFF_FULL; cannam@89: cannam@89: errhandler: cannam@89: BZ2_bzCompressEnd ( &strm ); cannam@89: return ret; cannam@89: } cannam@89: cannam@89: cannam@89: /*---------------------------------------------------*/ cannam@89: int BZ_API(BZ2_bzBuffToBuffDecompress) cannam@89: ( char* dest, cannam@89: unsigned int* destLen, cannam@89: char* source, cannam@89: unsigned int sourceLen, cannam@89: int small, cannam@89: int verbosity ) cannam@89: { cannam@89: bz_stream strm; cannam@89: int ret; cannam@89: cannam@89: if (dest == NULL || destLen == NULL || cannam@89: source == NULL || cannam@89: (small != 0 && small != 1) || cannam@89: verbosity < 0 || verbosity > 4) cannam@89: return BZ_PARAM_ERROR; cannam@89: cannam@89: strm.bzalloc = NULL; cannam@89: strm.bzfree = NULL; cannam@89: strm.opaque = NULL; cannam@89: ret = BZ2_bzDecompressInit ( &strm, verbosity, small ); cannam@89: if (ret != BZ_OK) return ret; cannam@89: cannam@89: strm.next_in = source; cannam@89: strm.next_out = dest; cannam@89: strm.avail_in = sourceLen; cannam@89: strm.avail_out = *destLen; cannam@89: cannam@89: ret = BZ2_bzDecompress ( &strm ); cannam@89: if (ret == BZ_OK) goto output_overflow_or_eof; cannam@89: if (ret != BZ_STREAM_END) goto errhandler; cannam@89: cannam@89: /* normal termination */ cannam@89: *destLen -= strm.avail_out; cannam@89: BZ2_bzDecompressEnd ( &strm ); cannam@89: return BZ_OK; cannam@89: cannam@89: output_overflow_or_eof: cannam@89: if (strm.avail_out > 0) { cannam@89: BZ2_bzDecompressEnd ( &strm ); cannam@89: return BZ_UNEXPECTED_EOF; cannam@89: } else { cannam@89: BZ2_bzDecompressEnd ( &strm ); cannam@89: return BZ_OUTBUFF_FULL; cannam@89: }; cannam@89: cannam@89: errhandler: cannam@89: BZ2_bzDecompressEnd ( &strm ); cannam@89: return ret; cannam@89: } cannam@89: cannam@89: cannam@89: /*---------------------------------------------------*/ cannam@89: /*-- cannam@89: Code contributed by Yoshioka Tsuneo (tsuneo@rr.iij4u.or.jp) cannam@89: to support better zlib compatibility. cannam@89: This code is not _officially_ part of libbzip2 (yet); cannam@89: I haven't tested it, documented it, or considered the cannam@89: threading-safeness of it. cannam@89: If this code breaks, please contact both Yoshioka and me. cannam@89: --*/ cannam@89: /*---------------------------------------------------*/ cannam@89: cannam@89: /*---------------------------------------------------*/ cannam@89: /*-- cannam@89: return version like "0.9.5d, 4-Sept-1999". cannam@89: --*/ cannam@89: const char * BZ_API(BZ2_bzlibVersion)(void) cannam@89: { cannam@89: return BZ_VERSION; cannam@89: } cannam@89: cannam@89: cannam@89: #ifndef BZ_NO_STDIO cannam@89: /*---------------------------------------------------*/ cannam@89: cannam@89: #if defined(_WIN32) || defined(OS2) || defined(MSDOS) cannam@89: # include cannam@89: # include cannam@89: # define SET_BINARY_MODE(file) setmode(fileno(file),O_BINARY) cannam@89: #else cannam@89: # define SET_BINARY_MODE(file) cannam@89: #endif cannam@89: static cannam@89: BZFILE * bzopen_or_bzdopen cannam@89: ( const char *path, /* no use when bzdopen */ cannam@89: int fd, /* no use when bzdopen */ cannam@89: const char *mode, cannam@89: int open_mode) /* bzopen: 0, bzdopen:1 */ cannam@89: { cannam@89: int bzerr; cannam@89: char unused[BZ_MAX_UNUSED]; cannam@89: int blockSize100k = 9; cannam@89: int writing = 0; cannam@89: char mode2[10] = ""; cannam@89: FILE *fp = NULL; cannam@89: BZFILE *bzfp = NULL; cannam@89: int verbosity = 0; cannam@89: int workFactor = 30; cannam@89: int smallMode = 0; cannam@89: int nUnused = 0; cannam@89: cannam@89: if (mode == NULL) return NULL; cannam@89: while (*mode) { cannam@89: switch (*mode) { cannam@89: case 'r': cannam@89: writing = 0; break; cannam@89: case 'w': cannam@89: writing = 1; break; cannam@89: case 's': cannam@89: smallMode = 1; break; cannam@89: default: cannam@89: if (isdigit((int)(*mode))) { cannam@89: blockSize100k = *mode-BZ_HDR_0; cannam@89: } cannam@89: } cannam@89: mode++; cannam@89: } cannam@89: strcat(mode2, writing ? "w" : "r" ); cannam@89: strcat(mode2,"b"); /* binary mode */ cannam@89: cannam@89: if (open_mode==0) { cannam@89: if (path==NULL || strcmp(path,"")==0) { cannam@89: fp = (writing ? stdout : stdin); cannam@89: SET_BINARY_MODE(fp); cannam@89: } else { cannam@89: fp = fopen(path,mode2); cannam@89: } cannam@89: } else { cannam@89: #ifdef BZ_STRICT_ANSI cannam@89: fp = NULL; cannam@89: #else cannam@89: fp = fdopen(fd,mode2); cannam@89: #endif cannam@89: } cannam@89: if (fp == NULL) return NULL; cannam@89: cannam@89: if (writing) { cannam@89: /* Guard against total chaos and anarchy -- JRS */ cannam@89: if (blockSize100k < 1) blockSize100k = 1; cannam@89: if (blockSize100k > 9) blockSize100k = 9; cannam@89: bzfp = BZ2_bzWriteOpen(&bzerr,fp,blockSize100k, cannam@89: verbosity,workFactor); cannam@89: } else { cannam@89: bzfp = BZ2_bzReadOpen(&bzerr,fp,verbosity,smallMode, cannam@89: unused,nUnused); cannam@89: } cannam@89: if (bzfp == NULL) { cannam@89: if (fp != stdin && fp != stdout) fclose(fp); cannam@89: return NULL; cannam@89: } cannam@89: return bzfp; cannam@89: } cannam@89: cannam@89: cannam@89: /*---------------------------------------------------*/ cannam@89: /*-- cannam@89: open file for read or write. cannam@89: ex) bzopen("file","w9") cannam@89: case path="" or NULL => use stdin or stdout. cannam@89: --*/ cannam@89: BZFILE * BZ_API(BZ2_bzopen) cannam@89: ( const char *path, cannam@89: const char *mode ) cannam@89: { cannam@89: return bzopen_or_bzdopen(path,-1,mode,/*bzopen*/0); cannam@89: } cannam@89: cannam@89: cannam@89: /*---------------------------------------------------*/ cannam@89: BZFILE * BZ_API(BZ2_bzdopen) cannam@89: ( int fd, cannam@89: const char *mode ) cannam@89: { cannam@89: return bzopen_or_bzdopen(NULL,fd,mode,/*bzdopen*/1); cannam@89: } cannam@89: cannam@89: cannam@89: /*---------------------------------------------------*/ cannam@89: int BZ_API(BZ2_bzread) (BZFILE* b, void* buf, int len ) cannam@89: { cannam@89: int bzerr, nread; cannam@89: if (((bzFile*)b)->lastErr == BZ_STREAM_END) return 0; cannam@89: nread = BZ2_bzRead(&bzerr,b,buf,len); cannam@89: if (bzerr == BZ_OK || bzerr == BZ_STREAM_END) { cannam@89: return nread; cannam@89: } else { cannam@89: return -1; cannam@89: } cannam@89: } cannam@89: cannam@89: cannam@89: /*---------------------------------------------------*/ cannam@89: int BZ_API(BZ2_bzwrite) (BZFILE* b, void* buf, int len ) cannam@89: { cannam@89: int bzerr; cannam@89: cannam@89: BZ2_bzWrite(&bzerr,b,buf,len); cannam@89: if(bzerr == BZ_OK){ cannam@89: return len; cannam@89: }else{ cannam@89: return -1; cannam@89: } cannam@89: } cannam@89: cannam@89: cannam@89: /*---------------------------------------------------*/ cannam@89: int BZ_API(BZ2_bzflush) (BZFILE *b) cannam@89: { cannam@89: /* do nothing now... */ cannam@89: return 0; cannam@89: } cannam@89: cannam@89: cannam@89: /*---------------------------------------------------*/ cannam@89: void BZ_API(BZ2_bzclose) (BZFILE* b) cannam@89: { cannam@89: int bzerr; cannam@89: FILE *fp; cannam@89: cannam@89: if (b==NULL) {return;} cannam@89: fp = ((bzFile *)b)->handle; cannam@89: if(((bzFile*)b)->writing){ cannam@89: BZ2_bzWriteClose(&bzerr,b,0,NULL,NULL); cannam@89: if(bzerr != BZ_OK){ cannam@89: BZ2_bzWriteClose(NULL,b,1,NULL,NULL); cannam@89: } cannam@89: }else{ cannam@89: BZ2_bzReadClose(&bzerr,b); cannam@89: } cannam@89: if(fp!=stdin && fp!=stdout){ cannam@89: fclose(fp); cannam@89: } cannam@89: } cannam@89: cannam@89: cannam@89: /*---------------------------------------------------*/ cannam@89: /*-- cannam@89: return last error code cannam@89: --*/ cannam@89: static const char *bzerrorstrings[] = { cannam@89: "OK" cannam@89: ,"SEQUENCE_ERROR" cannam@89: ,"PARAM_ERROR" cannam@89: ,"MEM_ERROR" cannam@89: ,"DATA_ERROR" cannam@89: ,"DATA_ERROR_MAGIC" cannam@89: ,"IO_ERROR" cannam@89: ,"UNEXPECTED_EOF" cannam@89: ,"OUTBUFF_FULL" cannam@89: ,"CONFIG_ERROR" cannam@89: ,"???" /* for future */ cannam@89: ,"???" /* for future */ cannam@89: ,"???" /* for future */ cannam@89: ,"???" /* for future */ cannam@89: ,"???" /* for future */ cannam@89: ,"???" /* for future */ cannam@89: }; cannam@89: cannam@89: cannam@89: const char * BZ_API(BZ2_bzerror) (BZFILE *b, int *errnum) cannam@89: { cannam@89: int err = ((bzFile *)b)->lastErr; cannam@89: cannam@89: if(err>0) err = 0; cannam@89: *errnum = err; cannam@89: return bzerrorstrings[err*-1]; cannam@89: } cannam@89: #endif cannam@89: cannam@89: cannam@89: /*-------------------------------------------------------------*/ cannam@89: /*--- end bzlib.c ---*/ cannam@89: /*-------------------------------------------------------------*/