Back to index

avfs  1.0.1
bzlib.c
Go to the documentation of this file.
00001 /* IMPORTANT NOTE: This is not the original bzip2 distribution.
00002 
00003    The modifications are copyright (C) 2001 Miklos Szeredi
00004    <miklos@szeredi.hu>
00005 
00006    The modified software can be distributed under the same licence as
00007    the original software (see bellow).
00008 */
00009 
00010 /*-------------------------------------------------------------*/
00011 /*--- Library top-level functions.                          ---*/
00012 /*---                                               bzlib.c ---*/
00013 /*-------------------------------------------------------------*/
00014 
00015 /* ------------------------------------------------------------------
00016    This file is part of bzip2/libbzip2, a program and library for
00017    lossless, block-sorting data compression.
00018 
00019    bzip2/libbzip2 version 1.0.6 of 6 September 2010
00020    Copyright (C) 1996-2010 Julian Seward <jseward@bzip.org>
00021 
00022    Please read the WARNING, DISCLAIMER and PATENTS sections in the 
00023    README file.
00024 
00025    This program is released under the terms of the license contained
00026    in the file LICENSE.
00027    ------------------------------------------------------------------ */
00028 
00029 /* CHANGES
00030    0.9.0    -- original version.
00031    0.9.0a/b -- no changes in this file.
00032    0.9.0c   -- made zero-length BZ_FLUSH work correctly in bzCompress().
00033      fixed bzWrite/bzRead to ignore zero-length requests.
00034      fixed bzread to correctly handle read requests after EOF.
00035      wrong parameter order in call to bzDecompressInit in
00036      bzBuffToBuffDecompress.  Fixed.
00037 */
00038 
00039 #include "bzlib_private.h"
00040 
00041 
00042 /*---------------------------------------------------*/
00043 /*--- Compression stuff                           ---*/
00044 /*---------------------------------------------------*/
00045 
00046 
00047 /*---------------------------------------------------*/
00048 #ifndef BZ_NO_STDIO
00049 void BZ2_bz__AssertH__fail ( int errcode )
00050 {
00051    fprintf(stderr, 
00052       "\n\nbzip2/libbzip2: internal error number %d.\n"
00053       "This is a bug in bzip2/libbzip2, %s.\n"
00054       "Please report it to me at: jseward@bzip.org.  If this happened\n"
00055       "when you were using some program which uses libbzip2 as a\n"
00056       "component, you should also report this bug to the author(s)\n"
00057       "of that program.  Please make an effort to report this bug;\n"
00058       "timely and accurate bug reports eventually lead to higher\n"
00059       "quality software.  Thanks.  Julian Seward, 10 December 2007.\n\n",
00060       errcode,
00061       BZ2_bzlibVersion()
00062    );
00063 
00064    if (errcode == 1007) {
00065    fprintf(stderr,
00066       "\n*** A special note about internal error number 1007 ***\n"
00067       "\n"
00068       "Experience suggests that a common cause of i.e. 1007\n"
00069       "is unreliable memory or other hardware.  The 1007 assertion\n"
00070       "just happens to cross-check the results of huge numbers of\n"
00071       "memory reads/writes, and so acts (unintendedly) as a stress\n"
00072       "test of your memory system.\n"
00073       "\n"
00074       "I suggest the following: try compressing the file again,\n"
00075       "possibly monitoring progress in detail with the -vv flag.\n"
00076       "\n"
00077       "* If the error cannot be reproduced, and/or happens at different\n"
00078       "  points in compression, you may have a flaky memory system.\n"
00079       "  Try a memory-test program.  I have used Memtest86\n"
00080       "  (www.memtest86.com).  At the time of writing it is free (GPLd).\n"
00081       "  Memtest86 tests memory much more thorougly than your BIOSs\n"
00082       "  power-on test, and may find failures that the BIOS doesn't.\n"
00083       "\n"
00084       "* If the error can be repeatably reproduced, this is a bug in\n"
00085       "  bzip2, and I would very much like to hear about it.  Please\n"
00086       "  let me know, and, ideally, save a copy of the file causing the\n"
00087       "  problem -- without which I will be unable to investigate it.\n"
00088       "\n"
00089    );
00090    }
00091 
00092    exit(3);
00093 }
00094 #endif
00095 
00096 
00097 /*---------------------------------------------------*/
00098 static
00099 int bz_config_ok ( void )
00100 {
00101    if (sizeof(int)   != 4) return 0;
00102    if (sizeof(short) != 2) return 0;
00103    if (sizeof(char)  != 1) return 0;
00104    return 1;
00105 }
00106 
00107 
00108 /*---------------------------------------------------*/
00109 static
00110 void* default_bzalloc ( void* opaque, Int32 items, Int32 size )
00111 {
00112    void* v = malloc ( items * size );
00113    return v;
00114 }
00115 
00116 static
00117 void default_bzfree ( void* opaque, void* addr )
00118 {
00119    if (addr != NULL) free ( addr );
00120 }
00121 
00122 
00123 /*---------------------------------------------------*/
00124 static
00125 void prepare_new_block ( EState* s )
00126 {
00127    Int32 i;
00128    s->nblock = 0;
00129    s->numZ = 0;
00130    s->state_out_pos = 0;
00131    BZ_INITIALISE_CRC ( s->blockCRC );
00132    for (i = 0; i < 256; i++) s->inUse[i] = False;
00133    s->blockNo++;
00134 }
00135 
00136 
00137 /*---------------------------------------------------*/
00138 static
00139 void init_RL ( EState* s )
00140 {
00141    s->state_in_ch  = 256;
00142    s->state_in_len = 0;
00143 }
00144 
00145 
00146 static
00147 Bool isempty_RL ( EState* s )
00148 {
00149    if (s->state_in_ch < 256 && s->state_in_len > 0)
00150       return False; else
00151       return True;
00152 }
00153 
00154 
00155 /*---------------------------------------------------*/
00156 int BZ_API(BZ2_bzCompressInit) 
00157                     ( bz_stream* strm, 
00158                      int        blockSize100k,
00159                      int        verbosity,
00160                      int        workFactor )
00161 {
00162    Int32   n;
00163    EState* s;
00164 
00165    if (!bz_config_ok()) return BZ_CONFIG_ERROR;
00166 
00167    if (strm == NULL || 
00168        blockSize100k < 1 || blockSize100k > 9 ||
00169        workFactor < 0 || workFactor > 250)
00170      return BZ_PARAM_ERROR;
00171 
00172    if (workFactor == 0) workFactor = 30;
00173    if (strm->bzalloc == NULL) strm->bzalloc = default_bzalloc;
00174    if (strm->bzfree == NULL) strm->bzfree = default_bzfree;
00175 
00176    s = BZALLOC( sizeof(EState) );
00177    if (s == NULL) return BZ_MEM_ERROR;
00178    s->strm = strm;
00179 
00180    s->arr1 = NULL;
00181    s->arr2 = NULL;
00182    s->ftab = NULL;
00183 
00184    n       = 100000 * blockSize100k;
00185    s->arr1 = BZALLOC( n                  * sizeof(UInt32) );
00186    s->arr2 = BZALLOC( (n+BZ_N_OVERSHOOT) * sizeof(UInt32) );
00187    s->ftab = BZALLOC( 65537              * sizeof(UInt32) );
00188 
00189    if (s->arr1 == NULL || s->arr2 == NULL || s->ftab == NULL) {
00190       if (s->arr1 != NULL) BZFREE(s->arr1);
00191       if (s->arr2 != NULL) BZFREE(s->arr2);
00192       if (s->ftab != NULL) BZFREE(s->ftab);
00193       if (s       != NULL) BZFREE(s);
00194       return BZ_MEM_ERROR;
00195    }
00196 
00197    s->blockNo           = 0;
00198    s->state             = BZ_S_INPUT;
00199    s->mode              = BZ_M_RUNNING;
00200    s->combinedCRC       = 0;
00201    s->blockSize100k     = blockSize100k;
00202    s->nblockMAX         = 100000 * blockSize100k - 19;
00203    s->verbosity         = verbosity;
00204    s->workFactor        = workFactor;
00205 
00206    s->block             = (UChar*)s->arr2;
00207    s->mtfv              = (UInt16*)s->arr1;
00208    s->zbits             = NULL;
00209    s->ptr               = (UInt32*)s->arr1;
00210 
00211    strm->state          = s;
00212    strm->total_in_lo32  = 0;
00213    strm->total_in_hi32  = 0;
00214    strm->total_out_lo32 = 0;
00215    strm->total_out_hi32 = 0;
00216    init_RL ( s );
00217    prepare_new_block ( s );
00218    return BZ_OK;
00219 }
00220 
00221 
00222 /*---------------------------------------------------*/
00223 static
00224 void add_pair_to_block ( EState* s )
00225 {
00226    Int32 i;
00227    UChar ch = (UChar)(s->state_in_ch);
00228    for (i = 0; i < s->state_in_len; i++) {
00229       BZ_UPDATE_CRC( s->blockCRC, ch );
00230    }
00231    s->inUse[s->state_in_ch] = True;
00232    switch (s->state_in_len) {
00233       case 1:
00234          s->block[s->nblock] = (UChar)ch; s->nblock++;
00235          break;
00236       case 2:
00237          s->block[s->nblock] = (UChar)ch; s->nblock++;
00238          s->block[s->nblock] = (UChar)ch; s->nblock++;
00239          break;
00240       case 3:
00241          s->block[s->nblock] = (UChar)ch; s->nblock++;
00242          s->block[s->nblock] = (UChar)ch; s->nblock++;
00243          s->block[s->nblock] = (UChar)ch; s->nblock++;
00244          break;
00245       default:
00246          s->inUse[s->state_in_len-4] = True;
00247          s->block[s->nblock] = (UChar)ch; s->nblock++;
00248          s->block[s->nblock] = (UChar)ch; s->nblock++;
00249          s->block[s->nblock] = (UChar)ch; s->nblock++;
00250          s->block[s->nblock] = (UChar)ch; s->nblock++;
00251          s->block[s->nblock] = ((UChar)(s->state_in_len-4));
00252          s->nblock++;
00253          break;
00254    }
00255 }
00256 
00257 
00258 /*---------------------------------------------------*/
00259 static
00260 void flush_RL ( EState* s )
00261 {
00262    if (s->state_in_ch < 256) add_pair_to_block ( s );
00263    init_RL ( s );
00264 }
00265 
00266 
00267 /*---------------------------------------------------*/
00268 #define ADD_CHAR_TO_BLOCK(zs,zchh0)               \
00269 {                                                 \
00270    UInt32 zchh = (UInt32)(zchh0);                 \
00271    /*-- fast track the common case --*/           \
00272    if (zchh != zs->state_in_ch &&                 \
00273        zs->state_in_len == 1) {                   \
00274       UChar ch = (UChar)(zs->state_in_ch);        \
00275       BZ_UPDATE_CRC( zs->blockCRC, ch );          \
00276       zs->inUse[zs->state_in_ch] = True;          \
00277       zs->block[zs->nblock] = (UChar)ch;          \
00278       zs->nblock++;                               \
00279       zs->state_in_ch = zchh;                     \
00280    }                                              \
00281    else                                           \
00282    /*-- general, uncommon cases --*/              \
00283    if (zchh != zs->state_in_ch ||                 \
00284       zs->state_in_len == 255) {                  \
00285       if (zs->state_in_ch < 256)                  \
00286          add_pair_to_block ( zs );                \
00287       zs->state_in_ch = zchh;                     \
00288       zs->state_in_len = 1;                       \
00289    } else {                                       \
00290       zs->state_in_len++;                         \
00291    }                                              \
00292 }
00293 
00294 
00295 /*---------------------------------------------------*/
00296 static
00297 Bool copy_input_until_stop ( EState* s )
00298 {
00299    Bool progress_in = False;
00300 
00301    if (s->mode == BZ_M_RUNNING) {
00302 
00303       /*-- fast track the common case --*/
00304       while (True) {
00305          /*-- block full? --*/
00306          if (s->nblock >= s->nblockMAX) break;
00307          /*-- no input? --*/
00308          if (s->strm->avail_in == 0) break;
00309          progress_in = True;
00310          ADD_CHAR_TO_BLOCK ( s, (UInt32)(*((UChar*)(s->strm->next_in))) ); 
00311          s->strm->next_in++;
00312          s->strm->avail_in--;
00313          s->strm->total_in_lo32++;
00314          if (s->strm->total_in_lo32 == 0) s->strm->total_in_hi32++;
00315       }
00316 
00317    } else {
00318 
00319       /*-- general, uncommon case --*/
00320       while (True) {
00321          /*-- block full? --*/
00322          if (s->nblock >= s->nblockMAX) break;
00323          /*-- no input? --*/
00324          if (s->strm->avail_in == 0) break;
00325          /*-- flush/finish end? --*/
00326          if (s->avail_in_expect == 0) break;
00327          progress_in = True;
00328          ADD_CHAR_TO_BLOCK ( s, (UInt32)(*((UChar*)(s->strm->next_in))) ); 
00329          s->strm->next_in++;
00330          s->strm->avail_in--;
00331          s->strm->total_in_lo32++;
00332          if (s->strm->total_in_lo32 == 0) s->strm->total_in_hi32++;
00333          s->avail_in_expect--;
00334       }
00335    }
00336    return progress_in;
00337 }
00338 
00339 
00340 /*---------------------------------------------------*/
00341 static
00342 Bool copy_output_until_stop ( EState* s )
00343 {
00344    Bool progress_out = False;
00345 
00346    while (True) {
00347 
00348       /*-- no output space? --*/
00349       if (s->strm->avail_out == 0) break;
00350 
00351       /*-- block done? --*/
00352       if (s->state_out_pos >= s->numZ) break;
00353 
00354       progress_out = True;
00355       *(s->strm->next_out) = s->zbits[s->state_out_pos];
00356       s->state_out_pos++;
00357       s->strm->avail_out--;
00358       s->strm->next_out++;
00359       s->strm->total_out_lo32++;
00360       if (s->strm->total_out_lo32 == 0) s->strm->total_out_hi32++;
00361    }
00362 
00363    return progress_out;
00364 }
00365 
00366 
00367 /*---------------------------------------------------*/
00368 static
00369 Bool handle_compress ( bz_stream* strm )
00370 {
00371    Bool progress_in  = False;
00372    Bool progress_out = False;
00373    EState* s = strm->state;
00374    
00375    while (True) {
00376 
00377       if (s->state == BZ_S_OUTPUT) {
00378          progress_out |= copy_output_until_stop ( s );
00379          if (s->state_out_pos < s->numZ) break;
00380          if (s->mode == BZ_M_FINISHING && 
00381              s->avail_in_expect == 0 &&
00382              isempty_RL(s)) break;
00383          prepare_new_block ( s );
00384          s->state = BZ_S_INPUT;
00385          if (s->mode == BZ_M_FLUSHING && 
00386              s->avail_in_expect == 0 &&
00387              isempty_RL(s)) break;
00388       }
00389 
00390       if (s->state == BZ_S_INPUT) {
00391          progress_in |= copy_input_until_stop ( s );
00392          if (s->mode != BZ_M_RUNNING && s->avail_in_expect == 0) {
00393             flush_RL ( s );
00394             BZ2_compressBlock ( s, (Bool)(s->mode == BZ_M_FINISHING) );
00395             s->state = BZ_S_OUTPUT;
00396          }
00397          else
00398          if (s->nblock >= s->nblockMAX) {
00399             BZ2_compressBlock ( s, False );
00400             s->state = BZ_S_OUTPUT;
00401          }
00402          else
00403          if (s->strm->avail_in == 0) {
00404             break;
00405          }
00406       }
00407 
00408    }
00409 
00410    return progress_in || progress_out;
00411 }
00412 
00413 
00414 /*---------------------------------------------------*/
00415 int BZ_API(BZ2_bzCompress) ( bz_stream *strm, int action )
00416 {
00417    Bool progress;
00418    EState* s;
00419    if (strm == NULL) return BZ_PARAM_ERROR;
00420    s = strm->state;
00421    if (s == NULL) return BZ_PARAM_ERROR;
00422    if (s->strm != strm) return BZ_PARAM_ERROR;
00423 
00424    preswitch:
00425    switch (s->mode) {
00426 
00427       case BZ_M_IDLE:
00428          return BZ_SEQUENCE_ERROR;
00429 
00430       case BZ_M_RUNNING:
00431          if (action == BZ_RUN) {
00432             progress = handle_compress ( strm );
00433             return progress ? BZ_RUN_OK : BZ_PARAM_ERROR;
00434          } 
00435          else
00436         if (action == BZ_FLUSH) {
00437             s->avail_in_expect = strm->avail_in;
00438             s->mode = BZ_M_FLUSHING;
00439             goto preswitch;
00440          }
00441          else
00442          if (action == BZ_FINISH) {
00443             s->avail_in_expect = strm->avail_in;
00444             s->mode = BZ_M_FINISHING;
00445             goto preswitch;
00446          }
00447          else 
00448             return BZ_PARAM_ERROR;
00449 
00450       case BZ_M_FLUSHING:
00451          if (action != BZ_FLUSH) return BZ_SEQUENCE_ERROR;
00452          if (s->avail_in_expect != s->strm->avail_in) 
00453             return BZ_SEQUENCE_ERROR;
00454          progress = handle_compress ( strm );
00455          if (s->avail_in_expect > 0 || !isempty_RL(s) ||
00456              s->state_out_pos < s->numZ) return BZ_FLUSH_OK;
00457          s->mode = BZ_M_RUNNING;
00458          return BZ_RUN_OK;
00459 
00460       case BZ_M_FINISHING:
00461          if (action != BZ_FINISH) return BZ_SEQUENCE_ERROR;
00462          if (s->avail_in_expect != s->strm->avail_in) 
00463             return BZ_SEQUENCE_ERROR;
00464          progress = handle_compress ( strm );
00465          if (!progress) return BZ_SEQUENCE_ERROR;
00466          if (s->avail_in_expect > 0 || !isempty_RL(s) ||
00467              s->state_out_pos < s->numZ) return BZ_FINISH_OK;
00468          s->mode = BZ_M_IDLE;
00469          return BZ_STREAM_END;
00470    }
00471    return BZ_OK; /*--not reached--*/
00472 }
00473 
00474 
00475 /*---------------------------------------------------*/
00476 int BZ_API(BZ2_bzCompressEnd)  ( bz_stream *strm )
00477 {
00478    EState* s;
00479    if (strm == NULL) return BZ_PARAM_ERROR;
00480    s = strm->state;
00481    if (s == NULL) return BZ_PARAM_ERROR;
00482    if (s->strm != strm) return BZ_PARAM_ERROR;
00483 
00484    if (s->arr1 != NULL) BZFREE(s->arr1);
00485    if (s->arr2 != NULL) BZFREE(s->arr2);
00486    if (s->ftab != NULL) BZFREE(s->ftab);
00487    BZFREE(strm->state);
00488 
00489    strm->state = NULL;   
00490 
00491    return BZ_OK;
00492 }
00493 
00494 
00495 /*---------------------------------------------------*/
00496 /*--- Decompression stuff                         ---*/
00497 /*---------------------------------------------------*/
00498 
00499 /*---------------------------------------------------*/
00500 int BZ_API(BZ2_bzDecompressInit) 
00501                      ( bz_stream* strm, 
00502                        int        verbosity,
00503                        int        small )
00504 {
00505    DState* s;
00506 
00507    if (!bz_config_ok()) return BZ_CONFIG_ERROR;
00508 
00509    if (strm == NULL) return BZ_PARAM_ERROR;
00510    if (small != 0 && small != 1) return BZ_PARAM_ERROR;
00511    if (verbosity < 0 || verbosity > 4) return BZ_PARAM_ERROR;
00512 
00513    if (strm->bzalloc == NULL) strm->bzalloc = default_bzalloc;
00514    if (strm->bzfree == NULL) strm->bzfree = default_bzfree;
00515 
00516    s = BZALLOC( sizeof(DState) );
00517    if (s == NULL) return BZ_MEM_ERROR;
00518    s->strm                  = strm;
00519    strm->state              = s;
00520    s->state                 = BZ_X_MAGIC_1;
00521    s->bsLive                = 0;
00522    s->bsBuff                = 0;
00523    s->calculatedCombinedCRC = 0;
00524    strm->total_in_lo32      = 0;
00525    strm->total_in_hi32      = 0;
00526    strm->total_out_lo32     = 0;
00527    strm->total_out_hi32     = 0;
00528    s->smallDecompress       = (Bool)small;
00529    s->ll4                   = NULL;
00530    s->ll16                  = NULL;
00531    s->tt                    = NULL;
00532    s->currBlockNo           = 0;
00533    s->verbosity             = verbosity;
00534    s->blockEndHandler       = NULL;
00535    s->blockEndHandlerData   = NULL;
00536 
00537    return BZ_OK;
00538 }
00539 
00540 void BZ_API(BZ2_bzSetBlockEndHandler) 
00541     (
00542         bz_stream *strm,
00543         void (*func) (void *data, bz_stream *strm, unsigned int bitsrem,
00544                       unsigned int bits, unsigned int crc,
00545                       unsigned int blocksize),
00546         void *data
00547         )
00548 {
00549     DState* s;
00550 
00551     s = strm->state;
00552     s->blockEndHandler = func;
00553     s->blockEndHandlerData = data;
00554 }
00555 
00556 void BZ_API(BZ2_bzRestoreBlockEnd) 
00557     (
00558         bz_stream *strm,
00559         unsigned int bitsrem,
00560         unsigned int crc )
00561 {
00562     DState* s;
00563 
00564     AssertH((bitsrem >= 0 && bitsrem < 8), 2828);
00565     s = strm->state;
00566     s->bsBuff = 'B' >> (8 - bitsrem);
00567     s->bsLive = bitsrem;
00568     s->calculatedCombinedCRC = crc;
00569 }
00570 
00571 
00572 
00573 /*---------------------------------------------------*/
00574 /* Return  True iff data corruption is discovered.
00575    Returns False if there is no problem.
00576 */
00577 static
00578 Bool unRLE_obuf_to_output_FAST ( DState* s )
00579 {
00580    UChar k1;
00581 
00582    if (s->blockRandomised) {
00583 
00584       while (True) {
00585          /* try to finish existing run */
00586          while (True) {
00587             if (s->strm->avail_out == 0) return False;
00588             if (s->state_out_len == 0) break;
00589             *( (UChar*)(s->strm->next_out) ) = s->state_out_ch;
00590             BZ_UPDATE_CRC ( s->calculatedBlockCRC, s->state_out_ch );
00591             s->state_out_len--;
00592             s->strm->next_out++;
00593             s->strm->avail_out--;
00594             s->strm->total_out_lo32++;
00595             if (s->strm->total_out_lo32 == 0) s->strm->total_out_hi32++;
00596          }
00597 
00598          /* can a new run be started? */
00599          if (s->nblock_used == s->save_nblock+1) return False;
00600                
00601          /* Only caused by corrupt data stream? */
00602          if (s->nblock_used > s->save_nblock+1)
00603             return True;
00604    
00605          s->state_out_len = 1;
00606          s->state_out_ch = s->k0;
00607          BZ_GET_FAST(k1); BZ_RAND_UPD_MASK; 
00608          k1 ^= BZ_RAND_MASK; s->nblock_used++;
00609          if (s->nblock_used == s->save_nblock+1) continue;
00610          if (k1 != s->k0) { s->k0 = k1; continue; };
00611    
00612          s->state_out_len = 2;
00613          BZ_GET_FAST(k1); BZ_RAND_UPD_MASK; 
00614          k1 ^= BZ_RAND_MASK; s->nblock_used++;
00615          if (s->nblock_used == s->save_nblock+1) continue;
00616          if (k1 != s->k0) { s->k0 = k1; continue; };
00617    
00618          s->state_out_len = 3;
00619          BZ_GET_FAST(k1); BZ_RAND_UPD_MASK; 
00620          k1 ^= BZ_RAND_MASK; s->nblock_used++;
00621          if (s->nblock_used == s->save_nblock+1) continue;
00622          if (k1 != s->k0) { s->k0 = k1; continue; };
00623    
00624          BZ_GET_FAST(k1); BZ_RAND_UPD_MASK; 
00625          k1 ^= BZ_RAND_MASK; s->nblock_used++;
00626          s->state_out_len = ((Int32)k1) + 4;
00627          BZ_GET_FAST(s->k0); BZ_RAND_UPD_MASK; 
00628          s->k0 ^= BZ_RAND_MASK; s->nblock_used++;
00629       }
00630 
00631    } else {
00632 
00633       /* restore */
00634       UInt32        c_calculatedBlockCRC = s->calculatedBlockCRC;
00635       UChar         c_state_out_ch       = s->state_out_ch;
00636       Int32         c_state_out_len      = s->state_out_len;
00637       Int32         c_nblock_used        = s->nblock_used;
00638       Int32         c_k0                 = s->k0;
00639       UInt32*       c_tt                 = s->tt;
00640       UInt32        c_tPos               = s->tPos;
00641       char*         cs_next_out          = s->strm->next_out;
00642       unsigned int  cs_avail_out         = s->strm->avail_out;
00643       Int32         ro_blockSize100k     = s->blockSize100k;
00644       /* end restore */
00645 
00646       UInt32       avail_out_INIT = cs_avail_out;
00647       Int32        s_save_nblockPP = s->save_nblock+1;
00648       unsigned int total_out_lo32_old;
00649 
00650       while (True) {
00651 
00652          /* try to finish existing run */
00653          if (c_state_out_len > 0) {
00654             while (True) {
00655                if (cs_avail_out == 0) goto return_notr;
00656                if (c_state_out_len == 1) break;
00657                *( (UChar*)(cs_next_out) ) = c_state_out_ch;
00658                BZ_UPDATE_CRC ( c_calculatedBlockCRC, c_state_out_ch );
00659                c_state_out_len--;
00660                cs_next_out++;
00661                cs_avail_out--;
00662             }
00663             s_state_out_len_eq_one:
00664             {
00665                if (cs_avail_out == 0) { 
00666                   c_state_out_len = 1; goto return_notr;
00667                };
00668                *( (UChar*)(cs_next_out) ) = c_state_out_ch;
00669                BZ_UPDATE_CRC ( c_calculatedBlockCRC, c_state_out_ch );
00670                cs_next_out++;
00671                cs_avail_out--;
00672             }
00673          }   
00674          /* Only caused by corrupt data stream? */
00675          if (c_nblock_used > s_save_nblockPP)
00676             return True;
00677 
00678          /* can a new run be started? */
00679          if (c_nblock_used == s_save_nblockPP) {
00680             c_state_out_len = 0; goto return_notr;
00681          };   
00682          c_state_out_ch = c_k0;
00683          BZ_GET_FAST_C(k1); c_nblock_used++;
00684          if (k1 != c_k0) { 
00685             c_k0 = k1; goto s_state_out_len_eq_one; 
00686          };
00687          if (c_nblock_used == s_save_nblockPP) 
00688             goto s_state_out_len_eq_one;
00689    
00690          c_state_out_len = 2;
00691          BZ_GET_FAST_C(k1); c_nblock_used++;
00692          if (c_nblock_used == s_save_nblockPP) continue;
00693          if (k1 != c_k0) { c_k0 = k1; continue; };
00694    
00695          c_state_out_len = 3;
00696          BZ_GET_FAST_C(k1); c_nblock_used++;
00697          if (c_nblock_used == s_save_nblockPP) continue;
00698          if (k1 != c_k0) { c_k0 = k1; continue; };
00699    
00700          BZ_GET_FAST_C(k1); c_nblock_used++;
00701          c_state_out_len = ((Int32)k1) + 4;
00702          BZ_GET_FAST_C(c_k0); c_nblock_used++;
00703       }
00704 
00705       return_notr:
00706       total_out_lo32_old = s->strm->total_out_lo32;
00707       s->strm->total_out_lo32 += (avail_out_INIT - cs_avail_out);
00708       if (s->strm->total_out_lo32 < total_out_lo32_old)
00709          s->strm->total_out_hi32++;
00710 
00711       /* save */
00712       s->calculatedBlockCRC = c_calculatedBlockCRC;
00713       s->state_out_ch       = c_state_out_ch;
00714       s->state_out_len      = c_state_out_len;
00715       s->nblock_used        = c_nblock_used;
00716       s->k0                 = c_k0;
00717       s->tt                 = c_tt;
00718       s->tPos               = c_tPos;
00719       s->strm->next_out     = cs_next_out;
00720       s->strm->avail_out    = cs_avail_out;
00721       /* end save */
00722    }
00723    return False;
00724 }
00725 
00726 
00727 
00728 /*---------------------------------------------------*/
00729 __inline__ Int32 BZ2_indexIntoF ( Int32 indx, Int32 *cftab )
00730 {
00731    Int32 nb, na, mid;
00732    nb = 0;
00733    na = 256;
00734    do {
00735       mid = (nb + na) >> 1;
00736       if (indx >= cftab[mid]) nb = mid; else na = mid;
00737    }
00738    while (na - nb != 1);
00739    return nb;
00740 }
00741 
00742 
00743 /*---------------------------------------------------*/
00744 /* Return  True iff data corruption is discovered.
00745    Returns False if there is no problem.
00746 */
00747 static
00748 Bool unRLE_obuf_to_output_SMALL ( DState* s )
00749 {
00750    UChar k1;
00751 
00752    if (s->blockRandomised) {
00753 
00754       while (True) {
00755          /* try to finish existing run */
00756          while (True) {
00757             if (s->strm->avail_out == 0) return False;
00758             if (s->state_out_len == 0) break;
00759             *( (UChar*)(s->strm->next_out) ) = s->state_out_ch;
00760             BZ_UPDATE_CRC ( s->calculatedBlockCRC, s->state_out_ch );
00761             s->state_out_len--;
00762             s->strm->next_out++;
00763             s->strm->avail_out--;
00764             s->strm->total_out_lo32++;
00765             if (s->strm->total_out_lo32 == 0) s->strm->total_out_hi32++;
00766          }
00767    
00768          /* can a new run be started? */
00769          if (s->nblock_used == s->save_nblock+1) return False;
00770 
00771          /* Only caused by corrupt data stream? */
00772          if (s->nblock_used > s->save_nblock+1)
00773             return True;
00774    
00775          s->state_out_len = 1;
00776          s->state_out_ch = s->k0;
00777          BZ_GET_SMALL(k1); BZ_RAND_UPD_MASK; 
00778          k1 ^= BZ_RAND_MASK; s->nblock_used++;
00779          if (s->nblock_used == s->save_nblock+1) continue;
00780          if (k1 != s->k0) { s->k0 = k1; continue; };
00781    
00782          s->state_out_len = 2;
00783          BZ_GET_SMALL(k1); BZ_RAND_UPD_MASK; 
00784          k1 ^= BZ_RAND_MASK; s->nblock_used++;
00785          if (s->nblock_used == s->save_nblock+1) continue;
00786          if (k1 != s->k0) { s->k0 = k1; continue; };
00787    
00788          s->state_out_len = 3;
00789          BZ_GET_SMALL(k1); BZ_RAND_UPD_MASK; 
00790          k1 ^= BZ_RAND_MASK; s->nblock_used++;
00791          if (s->nblock_used == s->save_nblock+1) continue;
00792          if (k1 != s->k0) { s->k0 = k1; continue; };
00793    
00794          BZ_GET_SMALL(k1); BZ_RAND_UPD_MASK; 
00795          k1 ^= BZ_RAND_MASK; s->nblock_used++;
00796          s->state_out_len = ((Int32)k1) + 4;
00797          BZ_GET_SMALL(s->k0); BZ_RAND_UPD_MASK; 
00798          s->k0 ^= BZ_RAND_MASK; s->nblock_used++;
00799       }
00800 
00801    } else {
00802 
00803       while (True) {
00804          /* try to finish existing run */
00805          while (True) {
00806             if (s->strm->avail_out == 0) return False;
00807             if (s->state_out_len == 0) break;
00808             *( (UChar*)(s->strm->next_out) ) = s->state_out_ch;
00809             BZ_UPDATE_CRC ( s->calculatedBlockCRC, s->state_out_ch );
00810             s->state_out_len--;
00811             s->strm->next_out++;
00812             s->strm->avail_out--;
00813             s->strm->total_out_lo32++;
00814             if (s->strm->total_out_lo32 == 0) s->strm->total_out_hi32++;
00815          }
00816    
00817          /* can a new run be started? */
00818          if (s->nblock_used == s->save_nblock+1) return False;
00819 
00820          /* Only caused by corrupt data stream? */
00821          if (s->nblock_used > s->save_nblock+1)
00822             return True;
00823    
00824          s->state_out_len = 1;
00825          s->state_out_ch = s->k0;
00826          BZ_GET_SMALL(k1); s->nblock_used++;
00827          if (s->nblock_used == s->save_nblock+1) continue;
00828          if (k1 != s->k0) { s->k0 = k1; continue; };
00829    
00830          s->state_out_len = 2;
00831          BZ_GET_SMALL(k1); s->nblock_used++;
00832          if (s->nblock_used == s->save_nblock+1) continue;
00833          if (k1 != s->k0) { s->k0 = k1; continue; };
00834    
00835          s->state_out_len = 3;
00836          BZ_GET_SMALL(k1); s->nblock_used++;
00837          if (s->nblock_used == s->save_nblock+1) continue;
00838          if (k1 != s->k0) { s->k0 = k1; continue; };
00839    
00840          BZ_GET_SMALL(k1); s->nblock_used++;
00841          s->state_out_len = ((Int32)k1) + 4;
00842          BZ_GET_SMALL(s->k0); s->nblock_used++;
00843       }
00844 
00845    }
00846 }
00847 
00848 
00849 /*---------------------------------------------------*/
00850 int BZ_API(BZ2_bzDecompress) ( bz_stream *strm )
00851 {
00852    Bool    corrupt;
00853    DState* s;
00854    if (strm == NULL) return BZ_PARAM_ERROR;
00855    s = strm->state;
00856    if (s == NULL) return BZ_PARAM_ERROR;
00857    if (s->strm != strm) return BZ_PARAM_ERROR;
00858 
00859    while (True) {
00860       if (s->state == BZ_X_IDLE) return BZ_SEQUENCE_ERROR;
00861       if (s->state == BZ_X_OUTPUT) {
00862          if (s->smallDecompress)
00863             corrupt = unRLE_obuf_to_output_SMALL ( s ); else
00864             corrupt = unRLE_obuf_to_output_FAST  ( s );
00865          if (corrupt) return BZ_DATA_ERROR;
00866          if (s->nblock_used == s->save_nblock+1 && s->state_out_len == 0) {
00867             BZ_FINALISE_CRC ( s->calculatedBlockCRC );
00868             if (s->verbosity >= 3) {
00869                VPrintf2 ( " {0x%08x, 0x%08x}", s->storedBlockCRC, 
00870                           s->calculatedBlockCRC );
00871             }
00872             if (s->verbosity >= 2) VPrintf0 ( "]" );
00873             if (s->calculatedBlockCRC != s->storedBlockCRC)
00874                return BZ_DATA_ERROR;
00875             s->calculatedCombinedCRC 
00876                = (s->calculatedCombinedCRC << 1) | 
00877                     (s->calculatedCombinedCRC >> 31);
00878             s->calculatedCombinedCRC ^= s->calculatedBlockCRC;
00879             if(s->blockEndHandler != NULL)
00880                 s->blockEndHandler(s->blockEndHandlerData, strm, s->bsLive,
00881                                    s->bsBuff, s->calculatedCombinedCRC,
00882                                    s->blockSize100k);
00883             s->state = BZ_X_BLKHDR_1;
00884          } else {
00885             return BZ_OK;
00886          }
00887       }
00888       if (s->state >= BZ_X_MAGIC_1) {
00889          Int32 r = BZ2_decompress ( s );
00890          if (r == BZ_STREAM_END) {
00891             if (s->verbosity >= 3)
00892                VPrintf2 ( "\n    combined CRCs: stored = 0x%08x, computed = 0x%08x", 
00893                           s->storedCombinedCRC, s->calculatedCombinedCRC );
00894             if (s->calculatedCombinedCRC != s->storedCombinedCRC)
00895                return BZ_DATA_ERROR;
00896             return r;
00897          }
00898          if (s->state != BZ_X_OUTPUT) return r;
00899       }
00900    }
00901 
00902    AssertH ( 0, 6001 );
00903 
00904    return 0;  /*NOTREACHED*/
00905 }
00906 
00907 
00908 /*---------------------------------------------------*/
00909 int BZ_API(BZ2_bzDecompressEnd)  ( bz_stream *strm )
00910 {
00911    DState* s;
00912    if (strm == NULL) return BZ_PARAM_ERROR;
00913    s = strm->state;
00914    if (s == NULL) return BZ_PARAM_ERROR;
00915    if (s->strm != strm) return BZ_PARAM_ERROR;
00916 
00917    if (s->tt   != NULL) BZFREE(s->tt);
00918    if (s->ll16 != NULL) BZFREE(s->ll16);
00919    if (s->ll4  != NULL) BZFREE(s->ll4);
00920 
00921    BZFREE(strm->state);
00922    strm->state = NULL;
00923 
00924    return BZ_OK;
00925 }
00926 
00927 
00928 #ifndef BZ_NO_STDIO
00929 /*---------------------------------------------------*/
00930 /*--- File I/O stuff                              ---*/
00931 /*---------------------------------------------------*/
00932 
00933 #define BZ_SETERR(eee)                    \
00934 {                                         \
00935    if (bzerror != NULL) *bzerror = eee;   \
00936    if (bzf != NULL) bzf->lastErr = eee;   \
00937 }
00938 
00939 typedef 
00940    struct {
00941       FILE*     handle;
00942       Char      buf[BZ_MAX_UNUSED];
00943       Int32     bufN;
00944       Bool      writing;
00945       bz_stream strm;
00946       Int32     lastErr;
00947       Bool      initialisedOk;
00948    }
00949    bzFile;
00950 
00951 
00952 /*---------------------------------------------*/
00953 static Bool myfeof ( FILE* f )
00954 {
00955    Int32 c = fgetc ( f );
00956    if (c == EOF) return True;
00957    ungetc ( c, f );
00958    return False;
00959 }
00960 
00961 
00962 /*---------------------------------------------------*/
00963 BZFILE* BZ_API(BZ2_bzWriteOpen) 
00964                     ( int*  bzerror,      
00965                       FILE* f, 
00966                       int   blockSize100k, 
00967                       int   verbosity,
00968                       int   workFactor )
00969 {
00970    Int32   ret;
00971    bzFile* bzf = NULL;
00972 
00973    BZ_SETERR(BZ_OK);
00974 
00975    if (f == NULL ||
00976        (blockSize100k < 1 || blockSize100k > 9) ||
00977        (workFactor < 0 || workFactor > 250) ||
00978        (verbosity < 0 || verbosity > 4))
00979       { BZ_SETERR(BZ_PARAM_ERROR); return NULL; };
00980 
00981    if (ferror(f))
00982       { BZ_SETERR(BZ_IO_ERROR); return NULL; };
00983 
00984    bzf = malloc ( sizeof(bzFile) );
00985    if (bzf == NULL)
00986       { BZ_SETERR(BZ_MEM_ERROR); return NULL; };
00987 
00988    BZ_SETERR(BZ_OK);
00989    bzf->initialisedOk = False;
00990    bzf->bufN          = 0;
00991    bzf->handle        = f;
00992    bzf->writing       = True;
00993    bzf->strm.bzalloc  = NULL;
00994    bzf->strm.bzfree   = NULL;
00995    bzf->strm.opaque   = NULL;
00996 
00997    if (workFactor == 0) workFactor = 30;
00998    ret = BZ2_bzCompressInit ( &(bzf->strm), blockSize100k, 
00999                               verbosity, workFactor );
01000    if (ret != BZ_OK)
01001       { BZ_SETERR(ret); free(bzf); return NULL; };
01002 
01003    bzf->strm.avail_in = 0;
01004    bzf->initialisedOk = True;
01005    return bzf;   
01006 }
01007 
01008 
01009 
01010 /*---------------------------------------------------*/
01011 void BZ_API(BZ2_bzWrite)
01012              ( int*    bzerror, 
01013                BZFILE* b, 
01014                void*   buf, 
01015                int     len )
01016 {
01017    Int32 n, n2, ret;
01018    bzFile* bzf = (bzFile*)b;
01019 
01020    BZ_SETERR(BZ_OK);
01021    if (bzf == NULL || buf == NULL || len < 0)
01022       { BZ_SETERR(BZ_PARAM_ERROR); return; };
01023    if (!(bzf->writing))
01024       { BZ_SETERR(BZ_SEQUENCE_ERROR); return; };
01025    if (ferror(bzf->handle))
01026       { BZ_SETERR(BZ_IO_ERROR); return; };
01027 
01028    if (len == 0)
01029       { BZ_SETERR(BZ_OK); return; };
01030 
01031    bzf->strm.avail_in = len;
01032    bzf->strm.next_in  = buf;
01033 
01034    while (True) {
01035       bzf->strm.avail_out = BZ_MAX_UNUSED;
01036       bzf->strm.next_out = bzf->buf;
01037       ret = BZ2_bzCompress ( &(bzf->strm), BZ_RUN );
01038       if (ret != BZ_RUN_OK)
01039          { BZ_SETERR(ret); return; };
01040 
01041       if (bzf->strm.avail_out < BZ_MAX_UNUSED) {
01042          n = BZ_MAX_UNUSED - bzf->strm.avail_out;
01043          n2 = fwrite ( (void*)(bzf->buf), sizeof(UChar), 
01044                        n, bzf->handle );
01045          if (n != n2 || ferror(bzf->handle))
01046             { BZ_SETERR(BZ_IO_ERROR); return; };
01047       }
01048 
01049       if (bzf->strm.avail_in == 0)
01050          { BZ_SETERR(BZ_OK); return; };
01051    }
01052 }
01053 
01054 
01055 /*---------------------------------------------------*/
01056 void BZ_API(BZ2_bzWriteClose)
01057                   ( int*          bzerror, 
01058                     BZFILE*       b, 
01059                     int           abandon,
01060                     unsigned int* nbytes_in,
01061                     unsigned int* nbytes_out )
01062 {
01063    BZ2_bzWriteClose64 ( bzerror, b, abandon, 
01064                         nbytes_in, NULL, nbytes_out, NULL );
01065 }
01066 
01067 
01068 void BZ_API(BZ2_bzWriteClose64)
01069                   ( int*          bzerror, 
01070                     BZFILE*       b, 
01071                     int           abandon,
01072                     unsigned int* nbytes_in_lo32,
01073                     unsigned int* nbytes_in_hi32,
01074                     unsigned int* nbytes_out_lo32,
01075                     unsigned int* nbytes_out_hi32 )
01076 {
01077    Int32   n, n2, ret;
01078    bzFile* bzf = (bzFile*)b;
01079 
01080    if (bzf == NULL)
01081       { BZ_SETERR(BZ_OK); return; };
01082    if (!(bzf->writing))
01083       { BZ_SETERR(BZ_SEQUENCE_ERROR); return; };
01084    if (ferror(bzf->handle))
01085       { BZ_SETERR(BZ_IO_ERROR); return; };
01086 
01087    if (nbytes_in_lo32 != NULL) *nbytes_in_lo32 = 0;
01088    if (nbytes_in_hi32 != NULL) *nbytes_in_hi32 = 0;
01089    if (nbytes_out_lo32 != NULL) *nbytes_out_lo32 = 0;
01090    if (nbytes_out_hi32 != NULL) *nbytes_out_hi32 = 0;
01091 
01092    if ((!abandon) && bzf->lastErr == BZ_OK) {
01093       while (True) {
01094          bzf->strm.avail_out = BZ_MAX_UNUSED;
01095          bzf->strm.next_out = bzf->buf;
01096          ret = BZ2_bzCompress ( &(bzf->strm), BZ_FINISH );
01097          if (ret != BZ_FINISH_OK && ret != BZ_STREAM_END)
01098             { BZ_SETERR(ret); return; };
01099 
01100          if (bzf->strm.avail_out < BZ_MAX_UNUSED) {
01101             n = BZ_MAX_UNUSED - bzf->strm.avail_out;
01102             n2 = fwrite ( (void*)(bzf->buf), sizeof(UChar), 
01103                           n, bzf->handle );
01104             if (n != n2 || ferror(bzf->handle))
01105                { BZ_SETERR(BZ_IO_ERROR); return; };
01106          }
01107 
01108          if (ret == BZ_STREAM_END) break;
01109       }
01110    }
01111 
01112    if ( !abandon && !ferror ( bzf->handle ) ) {
01113       fflush ( bzf->handle );
01114       if (ferror(bzf->handle))
01115          { BZ_SETERR(BZ_IO_ERROR); return; };
01116    }
01117 
01118    if (nbytes_in_lo32 != NULL)
01119       *nbytes_in_lo32 = bzf->strm.total_in_lo32;
01120    if (nbytes_in_hi32 != NULL)
01121       *nbytes_in_hi32 = bzf->strm.total_in_hi32;
01122    if (nbytes_out_lo32 != NULL)
01123       *nbytes_out_lo32 = bzf->strm.total_out_lo32;
01124    if (nbytes_out_hi32 != NULL)
01125       *nbytes_out_hi32 = bzf->strm.total_out_hi32;
01126 
01127    BZ_SETERR(BZ_OK);
01128    BZ2_bzCompressEnd ( &(bzf->strm) );
01129    free ( bzf );
01130 }
01131 
01132 
01133 /*---------------------------------------------------*/
01134 BZFILE* BZ_API(BZ2_bzReadOpen) 
01135                    ( int*  bzerror, 
01136                      FILE* f, 
01137                      int   verbosity,
01138                      int   small,
01139                      void* unused,
01140                      int   nUnused )
01141 {
01142    bzFile* bzf = NULL;
01143    int     ret;
01144 
01145    BZ_SETERR(BZ_OK);
01146 
01147    if (f == NULL || 
01148        (small != 0 && small != 1) ||
01149        (verbosity < 0 || verbosity > 4) ||
01150        (unused == NULL && nUnused != 0) ||
01151        (unused != NULL && (nUnused < 0 || nUnused > BZ_MAX_UNUSED)))
01152       { BZ_SETERR(BZ_PARAM_ERROR); return NULL; };
01153 
01154    if (ferror(f))
01155       { BZ_SETERR(BZ_IO_ERROR); return NULL; };
01156 
01157    bzf = malloc ( sizeof(bzFile) );
01158    if (bzf == NULL) 
01159       { BZ_SETERR(BZ_MEM_ERROR); return NULL; };
01160 
01161    BZ_SETERR(BZ_OK);
01162 
01163    bzf->initialisedOk = False;
01164    bzf->handle        = f;
01165    bzf->bufN          = 0;
01166    bzf->writing       = False;
01167    bzf->strm.bzalloc  = NULL;
01168    bzf->strm.bzfree   = NULL;
01169    bzf->strm.opaque   = NULL;
01170    
01171    while (nUnused > 0) {
01172       bzf->buf[bzf->bufN] = *((UChar*)(unused)); bzf->bufN++;
01173       unused = ((void*)( 1 + ((UChar*)(unused))  ));
01174       nUnused--;
01175    }
01176 
01177    ret = BZ2_bzDecompressInit ( &(bzf->strm), verbosity, small );
01178    if (ret != BZ_OK)
01179       { BZ_SETERR(ret); free(bzf); return NULL; };
01180 
01181    bzf->strm.avail_in = bzf->bufN;
01182    bzf->strm.next_in  = bzf->buf;
01183 
01184    bzf->initialisedOk = True;
01185    return bzf;   
01186 }
01187 
01188 
01189 /*---------------------------------------------------*/
01190 void BZ_API(BZ2_bzReadClose) ( int *bzerror, BZFILE *b )
01191 {
01192    bzFile* bzf = (bzFile*)b;
01193 
01194    BZ_SETERR(BZ_OK);
01195    if (bzf == NULL)
01196       { BZ_SETERR(BZ_OK); return; };
01197 
01198    if (bzf->writing)
01199       { BZ_SETERR(BZ_SEQUENCE_ERROR); return; };
01200 
01201    if (bzf->initialisedOk)
01202       (void)BZ2_bzDecompressEnd ( &(bzf->strm) );
01203    free ( bzf );
01204 }
01205 
01206 
01207 /*---------------------------------------------------*/
01208 int BZ_API(BZ2_bzRead) 
01209            ( int*    bzerror, 
01210              BZFILE* b, 
01211              void*   buf, 
01212              int     len )
01213 {
01214    Int32   n, ret;
01215    bzFile* bzf = (bzFile*)b;
01216 
01217    BZ_SETERR(BZ_OK);
01218 
01219    if (bzf == NULL || buf == NULL || len < 0)
01220       { BZ_SETERR(BZ_PARAM_ERROR); return 0; };
01221 
01222    if (bzf->writing)
01223       { BZ_SETERR(BZ_SEQUENCE_ERROR); return 0; };
01224 
01225    if (len == 0)
01226       { BZ_SETERR(BZ_OK); return 0; };
01227 
01228    bzf->strm.avail_out = len;
01229    bzf->strm.next_out = buf;
01230 
01231    while (True) {
01232 
01233       if (ferror(bzf->handle)) 
01234          { BZ_SETERR(BZ_IO_ERROR); return 0; };
01235 
01236       if (bzf->strm.avail_in == 0 && !myfeof(bzf->handle)) {
01237          n = fread ( bzf->buf, sizeof(UChar), 
01238                      BZ_MAX_UNUSED, bzf->handle );
01239          if (ferror(bzf->handle))
01240             { BZ_SETERR(BZ_IO_ERROR); return 0; };
01241          bzf->bufN = n;
01242          bzf->strm.avail_in = bzf->bufN;
01243          bzf->strm.next_in = bzf->buf;
01244       }
01245 
01246       ret = BZ2_bzDecompress ( &(bzf->strm) );
01247 
01248       if (ret != BZ_OK && ret != BZ_STREAM_END)
01249          { BZ_SETERR(ret); return 0; };
01250 
01251       if (ret == BZ_OK && myfeof(bzf->handle) && 
01252           bzf->strm.avail_in == 0 && bzf->strm.avail_out > 0)
01253          { BZ_SETERR(BZ_UNEXPECTED_EOF); return 0; };
01254 
01255       if (ret == BZ_STREAM_END)
01256          { BZ_SETERR(BZ_STREAM_END);
01257            return len - bzf->strm.avail_out; };
01258       if (bzf->strm.avail_out == 0)
01259          { BZ_SETERR(BZ_OK); return len; };
01260       
01261    }
01262 
01263    return 0; /*not reached*/
01264 }
01265 
01266 
01267 /*---------------------------------------------------*/
01268 void BZ_API(BZ2_bzReadGetUnused) 
01269                      ( int*    bzerror, 
01270                        BZFILE* b, 
01271                        void**  unused, 
01272                        int*    nUnused )
01273 {
01274    bzFile* bzf = (bzFile*)b;
01275    if (bzf == NULL)
01276       { BZ_SETERR(BZ_PARAM_ERROR); return; };
01277    if (bzf->lastErr != BZ_STREAM_END)
01278       { BZ_SETERR(BZ_SEQUENCE_ERROR); return; };
01279    if (unused == NULL || nUnused == NULL)
01280       { BZ_SETERR(BZ_PARAM_ERROR); return; };
01281 
01282    BZ_SETERR(BZ_OK);
01283    *nUnused = bzf->strm.avail_in;
01284    *unused = bzf->strm.next_in;
01285 }
01286 #endif
01287 
01288 
01289 /*---------------------------------------------------*/
01290 /*--- Misc convenience stuff                      ---*/
01291 /*---------------------------------------------------*/
01292 
01293 /*---------------------------------------------------*/
01294 int BZ_API(BZ2_bzBuffToBuffCompress) 
01295                          ( char*         dest, 
01296                            unsigned int* destLen,
01297                            char*         source, 
01298                            unsigned int  sourceLen,
01299                            int           blockSize100k, 
01300                            int           verbosity, 
01301                            int           workFactor )
01302 {
01303    bz_stream strm;
01304    int ret;
01305 
01306    if (dest == NULL || destLen == NULL || 
01307        source == NULL ||
01308        blockSize100k < 1 || blockSize100k > 9 ||
01309        verbosity < 0 || verbosity > 4 ||
01310        workFactor < 0 || workFactor > 250) 
01311       return BZ_PARAM_ERROR;
01312 
01313    if (workFactor == 0) workFactor = 30;
01314    strm.bzalloc = NULL;
01315    strm.bzfree = NULL;
01316    strm.opaque = NULL;
01317    ret = BZ2_bzCompressInit ( &strm, blockSize100k, 
01318                               verbosity, workFactor );
01319    if (ret != BZ_OK) return ret;
01320 
01321    strm.next_in = source;
01322    strm.next_out = dest;
01323    strm.avail_in = sourceLen;
01324    strm.avail_out = *destLen;
01325 
01326    ret = BZ2_bzCompress ( &strm, BZ_FINISH );
01327    if (ret == BZ_FINISH_OK) goto output_overflow;
01328    if (ret != BZ_STREAM_END) goto errhandler;
01329 
01330    /* normal termination */
01331    *destLen -= strm.avail_out;   
01332    BZ2_bzCompressEnd ( &strm );
01333    return BZ_OK;
01334 
01335    output_overflow:
01336    BZ2_bzCompressEnd ( &strm );
01337    return BZ_OUTBUFF_FULL;
01338 
01339    errhandler:
01340    BZ2_bzCompressEnd ( &strm );
01341    return ret;
01342 }
01343 
01344 
01345 /*---------------------------------------------------*/
01346 int BZ_API(BZ2_bzBuffToBuffDecompress) 
01347                            ( char*         dest, 
01348                              unsigned int* destLen,
01349                              char*         source, 
01350                              unsigned int  sourceLen,
01351                              int           small,
01352                              int           verbosity )
01353 {
01354    bz_stream strm;
01355    int ret;
01356 
01357    if (dest == NULL || destLen == NULL || 
01358        source == NULL ||
01359        (small != 0 && small != 1) ||
01360        verbosity < 0 || verbosity > 4) 
01361           return BZ_PARAM_ERROR;
01362 
01363    strm.bzalloc = NULL;
01364    strm.bzfree = NULL;
01365    strm.opaque = NULL;
01366    ret = BZ2_bzDecompressInit ( &strm, verbosity, small );
01367    if (ret != BZ_OK) return ret;
01368 
01369    strm.next_in = source;
01370    strm.next_out = dest;
01371    strm.avail_in = sourceLen;
01372    strm.avail_out = *destLen;
01373 
01374    ret = BZ2_bzDecompress ( &strm );
01375    if (ret == BZ_OK) goto output_overflow_or_eof;
01376    if (ret != BZ_STREAM_END) goto errhandler;
01377 
01378    /* normal termination */
01379    *destLen -= strm.avail_out;
01380    BZ2_bzDecompressEnd ( &strm );
01381    return BZ_OK;
01382 
01383    output_overflow_or_eof:
01384    if (strm.avail_out > 0) {
01385       BZ2_bzDecompressEnd ( &strm );
01386       return BZ_UNEXPECTED_EOF;
01387    } else {
01388       BZ2_bzDecompressEnd ( &strm );
01389       return BZ_OUTBUFF_FULL;
01390    };      
01391 
01392    errhandler:
01393    BZ2_bzDecompressEnd ( &strm );
01394    return ret; 
01395 }
01396 
01397 
01398 /*---------------------------------------------------*/
01399 /*--
01400    Code contributed by Yoshioka Tsuneo (tsuneo@rr.iij4u.or.jp)
01401    to support better zlib compatibility.
01402    This code is not _officially_ part of libbzip2 (yet);
01403    I haven't tested it, documented it, or considered the
01404    threading-safeness of it.
01405    If this code breaks, please contact both Yoshioka and me.
01406 --*/
01407 /*---------------------------------------------------*/
01408 
01409 /*---------------------------------------------------*/
01410 /*--
01411    return version like "0.9.5d, 4-Sept-1999".
01412 --*/
01413 const char * BZ_API(BZ2_bzlibVersion)(void)
01414 {
01415    return BZ_VERSION;
01416 }
01417 
01418 
01419 #ifndef BZ_NO_STDIO
01420 /*---------------------------------------------------*/
01421 
01422 #if defined(_WIN32) || defined(OS2) || defined(MSDOS)
01423 #   include <fcntl.h>
01424 #   include <io.h>
01425 #   define SET_BINARY_MODE(file) setmode(fileno(file),O_BINARY)
01426 #else
01427 #   define SET_BINARY_MODE(file)
01428 #endif
01429 static
01430 BZFILE * bzopen_or_bzdopen
01431                ( const char *path,   /* no use when bzdopen */
01432                  int fd,             /* no use when bzdopen */
01433                  const char *mode,
01434                  int open_mode)      /* bzopen: 0, bzdopen:1 */
01435 {
01436    int    bzerr;
01437    char   unused[BZ_MAX_UNUSED];
01438    int    blockSize100k = 9;
01439    int    writing       = 0;
01440    char   mode2[10]     = "";
01441    FILE   *fp           = NULL;
01442    BZFILE *bzfp         = NULL;
01443    int    verbosity     = 0;
01444    int    workFactor    = 30;
01445    int    smallMode     = 0;
01446    int    nUnused       = 0; 
01447 
01448    if (mode == NULL) return NULL;
01449    while (*mode) {
01450       switch (*mode) {
01451       case 'r':
01452          writing = 0; break;
01453       case 'w':
01454          writing = 1; break;
01455       case 's':
01456          smallMode = 1; break;
01457       default:
01458          if (isdigit((int)(*mode))) {
01459             blockSize100k = *mode-BZ_HDR_0;
01460          }
01461       }
01462       mode++;
01463    }
01464    strcat(mode2, writing ? "w" : "r" );
01465    strcat(mode2,"b");   /* binary mode */
01466 
01467    if (open_mode==0) {
01468       if (path==NULL || strcmp(path,"")==0) {
01469         fp = (writing ? stdout : stdin);
01470         SET_BINARY_MODE(fp);
01471       } else {
01472         fp = fopen(path,mode2);
01473       }
01474    } else {
01475 #ifdef BZ_STRICT_ANSI
01476       fp = NULL;
01477 #else
01478       fp = fdopen(fd,mode2);
01479 #endif
01480    }
01481    if (fp == NULL) return NULL;
01482 
01483    if (writing) {
01484       /* Guard against total chaos and anarchy -- JRS */
01485       if (blockSize100k < 1) blockSize100k = 1;
01486       if (blockSize100k > 9) blockSize100k = 9; 
01487       bzfp = BZ2_bzWriteOpen(&bzerr,fp,blockSize100k,
01488                              verbosity,workFactor);
01489    } else {
01490       bzfp = BZ2_bzReadOpen(&bzerr,fp,verbosity,smallMode,
01491                             unused,nUnused);
01492    }
01493    if (bzfp == NULL) {
01494       if (fp != stdin && fp != stdout) fclose(fp);
01495       return NULL;
01496    }
01497    return bzfp;
01498 }
01499 
01500 
01501 /*---------------------------------------------------*/
01502 /*--
01503    open file for read or write.
01504       ex) bzopen("file","w9")
01505       case path="" or NULL => use stdin or stdout.
01506 --*/
01507 BZFILE * BZ_API(BZ2_bzopen)
01508                ( const char *path,
01509                  const char *mode )
01510 {
01511    return bzopen_or_bzdopen(path,-1,mode,/*bzopen*/0);
01512 }
01513 
01514 
01515 /*---------------------------------------------------*/
01516 BZFILE * BZ_API(BZ2_bzdopen)
01517                ( int fd,
01518                  const char *mode )
01519 {
01520    return bzopen_or_bzdopen(NULL,fd,mode,/*bzdopen*/1);
01521 }
01522 
01523 
01524 /*---------------------------------------------------*/
01525 int BZ_API(BZ2_bzread) (BZFILE* b, void* buf, int len )
01526 {
01527    int bzerr, nread;
01528    if (((bzFile*)b)->lastErr == BZ_STREAM_END) return 0;
01529    nread = BZ2_bzRead(&bzerr,b,buf,len);
01530    if (bzerr == BZ_OK || bzerr == BZ_STREAM_END) {
01531       return nread;
01532    } else {
01533       return -1;
01534    }
01535 }
01536 
01537 
01538 /*---------------------------------------------------*/
01539 int BZ_API(BZ2_bzwrite) (BZFILE* b, void* buf, int len )
01540 {
01541    int bzerr;
01542 
01543    BZ2_bzWrite(&bzerr,b,buf,len);
01544    if(bzerr == BZ_OK){
01545       return len;
01546    }else{
01547       return -1;
01548    }
01549 }
01550 
01551 
01552 /*---------------------------------------------------*/
01553 int BZ_API(BZ2_bzflush) (BZFILE *b)
01554 {
01555    /* do nothing now... */
01556    return 0;
01557 }
01558 
01559 
01560 /*---------------------------------------------------*/
01561 void BZ_API(BZ2_bzclose) (BZFILE* b)
01562 {
01563    int bzerr;
01564    FILE *fp;
01565    
01566    if (b==NULL) {return;}
01567    fp = ((bzFile *)b)->handle;
01568    if(((bzFile*)b)->writing){
01569       BZ2_bzWriteClose(&bzerr,b,0,NULL,NULL);
01570       if(bzerr != BZ_OK){
01571          BZ2_bzWriteClose(NULL,b,1,NULL,NULL);
01572       }
01573    }else{
01574       BZ2_bzReadClose(&bzerr,b);
01575    }
01576    if(fp!=stdin && fp!=stdout){
01577       fclose(fp);
01578    }
01579 }
01580 
01581 
01582 /*---------------------------------------------------*/
01583 /*--
01584    return last error code 
01585 --*/
01586 static const char *bzerrorstrings[] = {
01587        "OK"
01588       ,"SEQUENCE_ERROR"
01589       ,"PARAM_ERROR"
01590       ,"MEM_ERROR"
01591       ,"DATA_ERROR"
01592       ,"DATA_ERROR_MAGIC"
01593       ,"IO_ERROR"
01594       ,"UNEXPECTED_EOF"
01595       ,"OUTBUFF_FULL"
01596       ,"CONFIG_ERROR"
01597       ,"???"   /* for future */
01598       ,"???"   /* for future */
01599       ,"???"   /* for future */
01600       ,"???"   /* for future */
01601       ,"???"   /* for future */
01602       ,"???"   /* for future */
01603 };
01604 
01605 
01606 const char * BZ_API(BZ2_bzerror) (BZFILE *b, int *errnum)
01607 {
01608    int err = ((bzFile *)b)->lastErr;
01609 
01610    if(err>0) err = 0;
01611    *errnum = err;
01612    return bzerrorstrings[err*-1];
01613 }
01614 #endif
01615 
01616 
01617 /*-------------------------------------------------------------*/
01618 /*--- end                                           bzlib.c ---*/
01619 /*-------------------------------------------------------------*/