Back to index

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