Home | History | Annotate | Line # | Download | only in dist
bzlib.c revision 1.1.1.1
      1 /*	$NetBSD: bzlib.c,v 1.1.1.1 2012/05/07 00:21:46 wiz Exp $	*/
      2 
      3 
      4 /*-------------------------------------------------------------*/
      5 /*--- Library top-level functions.                          ---*/
      6 /*---                                               bzlib.c ---*/
      7 /*-------------------------------------------------------------*/
      8 
      9 /* ------------------------------------------------------------------
     10    This file is part of bzip2/libbzip2, a program and library for
     11    lossless, block-sorting data compression.
     12 
     13    bzip2/libbzip2 version 1.0.5 of 10 December 2007
     14    Copyright (C) 1996-2007 Julian Seward <jseward (at) bzip.org>
     15 
     16    Please read the WARNING, DISCLAIMER and PATENTS sections in the
     17    README file.
     18 
     19    This program is released under the terms of the license contained
     20    in the file LICENSE.
     21    ------------------------------------------------------------------ */
     22 
     23 /* CHANGES
     24    0.9.0    -- original version.
     25    0.9.0a/b -- no changes in this file.
     26    0.9.0c   -- made zero-length BZ_FLUSH work correctly in bzCompress().
     27      fixed bzWrite/bzRead to ignore zero-length requests.
     28      fixed bzread to correctly handle read requests after EOF.
     29      wrong parameter order in call to bzDecompressInit in
     30      bzBuffToBuffDecompress.  Fixed.
     31 */
     32 
     33 #include "bzlib_private.h"
     34 
     35 
     36 /*---------------------------------------------------*/
     37 /*--- Compression stuff                           ---*/
     38 /*---------------------------------------------------*/
     39 
     40 
     41 /*---------------------------------------------------*/
     42 #ifndef BZ_NO_STDIO
     43 void BZ2_bz__AssertH__fail ( int errcode )
     44 {
     45    fprintf(stderr,
     46       "\n\nbzip2/libbzip2: internal error number %d.\n"
     47       "This is a bug in bzip2/libbzip2, %s.\n"
     48       "Please report it to me at: jseward (at) bzip.org.  If this happened\n"
     49       "when you were using some program which uses libbzip2 as a\n"
     50       "component, you should also report this bug to the author(s)\n"
     51       "of that program.  Please make an effort to report this bug;\n"
     52       "timely and accurate bug reports eventually lead to higher\n"
     53       "quality software.  Thanks.  Julian Seward, 10 December 2007.\n\n",
     54       errcode,
     55       BZ2_bzlibVersion()
     56    );
     57 
     58    if (errcode == 1007) {
     59    fprintf(stderr,
     60       "\n*** A special note about internal error number 1007 ***\n"
     61       "\n"
     62       "Experience suggests that a common cause of i.e. 1007\n"
     63       "is unreliable memory or other hardware.  The 1007 assertion\n"
     64       "just happens to cross-check the results of huge numbers of\n"
     65       "memory reads/writes, and so acts (unintendedly) as a stress\n"
     66       "test of your memory system.\n"
     67       "\n"
     68       "I suggest the following: try compressing the file again,\n"
     69       "possibly monitoring progress in detail with the -vv flag.\n"
     70       "\n"
     71       "* If the error cannot be reproduced, and/or happens at different\n"
     72       "  points in compression, you may have a flaky memory system.\n"
     73       "  Try a memory-test program.  I have used Memtest86\n"
     74       "  (www.memtest86.com).  At the time of writing it is free (GPLd).\n"
     75       "  Memtest86 tests memory much more thorougly than your BIOSs\n"
     76       "  power-on test, and may find failures that the BIOS doesn't.\n"
     77       "\n"
     78       "* If the error can be repeatably reproduced, this is a bug in\n"
     79       "  bzip2, and I would very much like to hear about it.  Please\n"
     80       "  let me know, and, ideally, save a copy of the file causing the\n"
     81       "  problem -- without which I will be unable to investigate it.\n"
     82       "\n"
     83    );
     84    }
     85 
     86    exit(3);
     87 }
     88 #endif
     89 
     90 
     91 /*---------------------------------------------------*/
     92 static
     93 int bz_config_ok ( void )
     94 {
     95    if (sizeof(int)   != 4) return 0;
     96    if (sizeof(short) != 2) return 0;
     97    if (sizeof(char)  != 1) return 0;
     98    return 1;
     99 }
    100 
    101 
    102 /*---------------------------------------------------*/
    103 static
    104 void* default_bzalloc ( void* opaque, Int32 items, Int32 size )
    105 {
    106    void* v = malloc ( items * size );
    107    return v;
    108 }
    109 
    110 static
    111 void default_bzfree ( void* opaque, void* addr )
    112 {
    113    if (addr != NULL) free ( addr );
    114 }
    115 
    116 
    117 /*---------------------------------------------------*/
    118 static
    119 void prepare_new_block ( EState* s )
    120 {
    121    Int32 i;
    122    s->nblock = 0;
    123    s->numZ = 0;
    124    s->state_out_pos = 0;
    125    BZ_INITIALISE_CRC ( s->blockCRC );
    126    for (i = 0; i < 256; i++) s->inUse[i] = False;
    127    s->blockNo++;
    128 }
    129 
    130 
    131 /*---------------------------------------------------*/
    132 static
    133 void init_RL ( EState* s )
    134 {
    135    s->state_in_ch  = 256;
    136    s->state_in_len = 0;
    137 }
    138 
    139 
    140 static
    141 Bool isempty_RL ( EState* s )
    142 {
    143    if (s->state_in_ch < 256 && s->state_in_len > 0)
    144       return False; else
    145       return True;
    146 }
    147 
    148 
    149 /*---------------------------------------------------*/
    150 int BZ_API(BZ2_bzCompressInit)
    151                     ( bz_stream* strm,
    152                      int        blockSize100k,
    153                      int        verbosity,
    154                      int        workFactor )
    155 {
    156    Int32   n;
    157    EState* s;
    158 
    159    if (!bz_config_ok()) return BZ_CONFIG_ERROR;
    160 
    161    if (strm == NULL ||
    162        blockSize100k < 1 || blockSize100k > 9 ||
    163        workFactor < 0 || workFactor > 250)
    164      return BZ_PARAM_ERROR;
    165 
    166    if (workFactor == 0) workFactor = 30;
    167    if (strm->bzalloc == NULL) strm->bzalloc = default_bzalloc;
    168    if (strm->bzfree == NULL) strm->bzfree = default_bzfree;
    169 
    170    s = BZALLOC( sizeof(EState) );
    171    if (s == NULL) return BZ_MEM_ERROR;
    172    s->strm = strm;
    173 
    174    s->arr1 = NULL;
    175    s->arr2 = NULL;
    176    s->ftab = NULL;
    177 
    178    n       = 100000 * blockSize100k;
    179    s->arr1 = BZALLOC( n                  * sizeof(UInt32) );
    180    s->arr2 = BZALLOC( (n+BZ_N_OVERSHOOT) * sizeof(UInt32) );
    181    s->ftab = BZALLOC( 65537              * sizeof(UInt32) );
    182 
    183    if (s->arr1 == NULL || s->arr2 == NULL || s->ftab == NULL) {
    184       if (s->arr1 != NULL) BZFREE(s->arr1);
    185       if (s->arr2 != NULL) BZFREE(s->arr2);
    186       if (s->ftab != NULL) BZFREE(s->ftab);
    187       if (s       != NULL) BZFREE(s);
    188       return BZ_MEM_ERROR;
    189    }
    190 
    191    s->blockNo           = 0;
    192    s->state             = BZ_S_INPUT;
    193    s->mode              = BZ_M_RUNNING;
    194    s->combinedCRC       = 0;
    195    s->blockSize100k     = blockSize100k;
    196    s->nblockMAX         = 100000 * blockSize100k - 19;
    197    s->verbosity         = verbosity;
    198    s->workFactor        = workFactor;
    199 
    200    s->block             = (UChar*)s->arr2;
    201    s->mtfv              = (UInt16*)s->arr1;
    202    s->zbits             = NULL;
    203    s->ptr               = (UInt32*)s->arr1;
    204 
    205    strm->state          = s;
    206    strm->total_in_lo32  = 0;
    207    strm->total_in_hi32  = 0;
    208    strm->total_out_lo32 = 0;
    209    strm->total_out_hi32 = 0;
    210    init_RL ( s );
    211    prepare_new_block ( s );
    212    return BZ_OK;
    213 }
    214 
    215 
    216 /*---------------------------------------------------*/
    217 static
    218 void add_pair_to_block ( EState* s )
    219 {
    220    Int32 i;
    221    UChar ch = (UChar)(s->state_in_ch);
    222    for (i = 0; i < s->state_in_len; i++) {
    223       BZ_UPDATE_CRC( s->blockCRC, ch );
    224    }
    225    s->inUse[s->state_in_ch] = True;
    226    switch (s->state_in_len) {
    227       case 1:
    228          s->block[s->nblock] = (UChar)ch; s->nblock++;
    229          break;
    230       case 2:
    231          s->block[s->nblock] = (UChar)ch; s->nblock++;
    232          s->block[s->nblock] = (UChar)ch; s->nblock++;
    233          break;
    234       case 3:
    235          s->block[s->nblock] = (UChar)ch; s->nblock++;
    236          s->block[s->nblock] = (UChar)ch; s->nblock++;
    237          s->block[s->nblock] = (UChar)ch; s->nblock++;
    238          break;
    239       default:
    240          s->inUse[s->state_in_len-4] = True;
    241          s->block[s->nblock] = (UChar)ch; s->nblock++;
    242          s->block[s->nblock] = (UChar)ch; s->nblock++;
    243          s->block[s->nblock] = (UChar)ch; s->nblock++;
    244          s->block[s->nblock] = (UChar)ch; s->nblock++;
    245          s->block[s->nblock] = ((UChar)(s->state_in_len-4));
    246          s->nblock++;
    247          break;
    248    }
    249 }
    250 
    251 
    252 /*---------------------------------------------------*/
    253 static
    254 void flush_RL ( EState* s )
    255 {
    256    if (s->state_in_ch < 256) add_pair_to_block ( s );
    257    init_RL ( s );
    258 }
    259 
    260 
    261 /*---------------------------------------------------*/
    262 #define ADD_CHAR_TO_BLOCK(zs,zchh0)               \
    263 {                                                 \
    264    UInt32 zchh = (UInt32)(zchh0);                 \
    265    /*-- fast track the common case --*/           \
    266    if (zchh != zs->state_in_ch &&                 \
    267        zs->state_in_len == 1) {                   \
    268       UChar ch = (UChar)(zs->state_in_ch);        \
    269       BZ_UPDATE_CRC( zs->blockCRC, ch );          \
    270       zs->inUse[zs->state_in_ch] = True;          \
    271       zs->block[zs->nblock] = (UChar)ch;          \
    272       zs->nblock++;                               \
    273       zs->state_in_ch = zchh;                     \
    274    }                                              \
    275    else                                           \
    276    /*-- general, uncommon cases --*/              \
    277    if (zchh != zs->state_in_ch ||                 \
    278       zs->state_in_len == 255) {                  \
    279       if (zs->state_in_ch < 256)                  \
    280          add_pair_to_block ( zs );                \
    281       zs->state_in_ch = zchh;                     \
    282       zs->state_in_len = 1;                       \
    283    } else {                                       \
    284       zs->state_in_len++;                         \
    285    }                                              \
    286 }
    287 
    288 
    289 /*---------------------------------------------------*/
    290 static
    291 Bool copy_input_until_stop ( EState* s )
    292 {
    293    Bool progress_in = False;
    294 
    295    if (s->mode == BZ_M_RUNNING) {
    296 
    297       /*-- fast track the common case --*/
    298       while (True) {
    299          /*-- block full? --*/
    300          if (s->nblock >= s->nblockMAX) break;
    301          /*-- no input? --*/
    302          if (s->strm->avail_in == 0) break;
    303          progress_in = True;
    304          ADD_CHAR_TO_BLOCK ( s, (UInt32)(*((UChar*)(s->strm->next_in))) );
    305          s->strm->next_in++;
    306          s->strm->avail_in--;
    307          s->strm->total_in_lo32++;
    308          if (s->strm->total_in_lo32 == 0) s->strm->total_in_hi32++;
    309       }
    310 
    311    } else {
    312 
    313       /*-- general, uncommon case --*/
    314       while (True) {
    315          /*-- block full? --*/
    316          if (s->nblock >= s->nblockMAX) break;
    317          /*-- no input? --*/
    318          if (s->strm->avail_in == 0) break;
    319          /*-- flush/finish end? --*/
    320          if (s->avail_in_expect == 0) break;
    321          progress_in = True;
    322          ADD_CHAR_TO_BLOCK ( s, (UInt32)(*((UChar*)(s->strm->next_in))) );
    323          s->strm->next_in++;
    324          s->strm->avail_in--;
    325          s->strm->total_in_lo32++;
    326          if (s->strm->total_in_lo32 == 0) s->strm->total_in_hi32++;
    327          s->avail_in_expect--;
    328       }
    329    }
    330    return progress_in;
    331 }
    332 
    333 
    334 /*---------------------------------------------------*/
    335 static
    336 Bool copy_output_until_stop ( EState* s )
    337 {
    338    Bool progress_out = False;
    339 
    340    while (True) {
    341 
    342       /*-- no output space? --*/
    343       if (s->strm->avail_out == 0) break;
    344 
    345       /*-- block done? --*/
    346       if (s->state_out_pos >= s->numZ) break;
    347 
    348       progress_out = True;
    349       *(s->strm->next_out) = s->zbits[s->state_out_pos];
    350       s->state_out_pos++;
    351       s->strm->avail_out--;
    352       s->strm->next_out++;
    353       s->strm->total_out_lo32++;
    354       if (s->strm->total_out_lo32 == 0) s->strm->total_out_hi32++;
    355    }
    356 
    357    return progress_out;
    358 }
    359 
    360 
    361 /*---------------------------------------------------*/
    362 static
    363 Bool handle_compress ( bz_stream* strm )
    364 {
    365    Bool progress_in  = False;
    366    Bool progress_out = False;
    367    EState* s = strm->state;
    368 
    369    while (True) {
    370 
    371       if (s->state == BZ_S_OUTPUT) {
    372          progress_out |= copy_output_until_stop ( s );
    373          if (s->state_out_pos < s->numZ) break;
    374          if (s->mode == BZ_M_FINISHING &&
    375              s->avail_in_expect == 0 &&
    376              isempty_RL(s)) break;
    377          prepare_new_block ( s );
    378          s->state = BZ_S_INPUT;
    379          if (s->mode == BZ_M_FLUSHING &&
    380              s->avail_in_expect == 0 &&
    381              isempty_RL(s)) break;
    382       }
    383 
    384       if (s->state == BZ_S_INPUT) {
    385          progress_in |= copy_input_until_stop ( s );
    386          if (s->mode != BZ_M_RUNNING && s->avail_in_expect == 0) {
    387             flush_RL ( s );
    388             BZ2_compressBlock ( s, (Bool)(s->mode == BZ_M_FINISHING) );
    389             s->state = BZ_S_OUTPUT;
    390          }
    391          else
    392          if (s->nblock >= s->nblockMAX) {
    393             BZ2_compressBlock ( s, False );
    394             s->state = BZ_S_OUTPUT;
    395          }
    396          else
    397          if (s->strm->avail_in == 0) {
    398             break;
    399          }
    400       }
    401 
    402    }
    403 
    404    return progress_in || progress_out;
    405 }
    406 
    407 
    408 /*---------------------------------------------------*/
    409 int BZ_API(BZ2_bzCompress) ( bz_stream *strm, int action )
    410 {
    411    Bool progress;
    412    EState* s;
    413    if (strm == NULL) return BZ_PARAM_ERROR;
    414    s = strm->state;
    415    if (s == NULL) return BZ_PARAM_ERROR;
    416    if (s->strm != strm) return BZ_PARAM_ERROR;
    417 
    418    preswitch:
    419    switch (s->mode) {
    420 
    421       case BZ_M_IDLE:
    422          return BZ_SEQUENCE_ERROR;
    423 
    424       case BZ_M_RUNNING:
    425          if (action == BZ_RUN) {
    426             progress = handle_compress ( strm );
    427             return progress ? BZ_RUN_OK : BZ_PARAM_ERROR;
    428          }
    429          else
    430 	 if (action == BZ_FLUSH) {
    431             s->avail_in_expect = strm->avail_in;
    432             s->mode = BZ_M_FLUSHING;
    433             goto preswitch;
    434          }
    435          else
    436          if (action == BZ_FINISH) {
    437             s->avail_in_expect = strm->avail_in;
    438             s->mode = BZ_M_FINISHING;
    439             goto preswitch;
    440          }
    441          else
    442             return BZ_PARAM_ERROR;
    443 
    444       case BZ_M_FLUSHING:
    445          if (action != BZ_FLUSH) return BZ_SEQUENCE_ERROR;
    446          if (s->avail_in_expect != s->strm->avail_in)
    447             return BZ_SEQUENCE_ERROR;
    448          progress = handle_compress ( strm );
    449          if (s->avail_in_expect > 0 || !isempty_RL(s) ||
    450              s->state_out_pos < s->numZ) return BZ_FLUSH_OK;
    451          s->mode = BZ_M_RUNNING;
    452          return BZ_RUN_OK;
    453 
    454       case BZ_M_FINISHING:
    455          if (action != BZ_FINISH) return BZ_SEQUENCE_ERROR;
    456          if (s->avail_in_expect != s->strm->avail_in)
    457             return BZ_SEQUENCE_ERROR;
    458          progress = handle_compress ( strm );
    459          if (!progress) return BZ_SEQUENCE_ERROR;
    460          if (s->avail_in_expect > 0 || !isempty_RL(s) ||
    461              s->state_out_pos < s->numZ) return BZ_FINISH_OK;
    462          s->mode = BZ_M_IDLE;
    463          return BZ_STREAM_END;
    464    }
    465    return BZ_OK; /*--not reached--*/
    466 }
    467 
    468 
    469 /*---------------------------------------------------*/
    470 int BZ_API(BZ2_bzCompressEnd)  ( bz_stream *strm )
    471 {
    472    EState* s;
    473    if (strm == NULL) return BZ_PARAM_ERROR;
    474    s = strm->state;
    475    if (s == NULL) return BZ_PARAM_ERROR;
    476    if (s->strm != strm) return BZ_PARAM_ERROR;
    477 
    478    if (s->arr1 != NULL) BZFREE(s->arr1);
    479    if (s->arr2 != NULL) BZFREE(s->arr2);
    480    if (s->ftab != NULL) BZFREE(s->ftab);
    481    BZFREE(strm->state);
    482 
    483    strm->state = NULL;
    484 
    485    return BZ_OK;
    486 }
    487 
    488 
    489 /*---------------------------------------------------*/
    490 /*--- Decompression stuff                         ---*/
    491 /*---------------------------------------------------*/
    492 
    493 /*---------------------------------------------------*/
    494 int BZ_API(BZ2_bzDecompressInit)
    495                      ( bz_stream* strm,
    496                        int        verbosity,
    497                        int        small )
    498 {
    499    DState* s;
    500 
    501    if (!bz_config_ok()) return BZ_CONFIG_ERROR;
    502 
    503    if (strm == NULL) return BZ_PARAM_ERROR;
    504    if (small != 0 && small != 1) return BZ_PARAM_ERROR;
    505    if (verbosity < 0 || verbosity > 4) return BZ_PARAM_ERROR;
    506 
    507    if (strm->bzalloc == NULL) strm->bzalloc = default_bzalloc;
    508    if (strm->bzfree == NULL) strm->bzfree = default_bzfree;
    509 
    510    s = BZALLOC( sizeof(DState) );
    511    if (s == NULL) return BZ_MEM_ERROR;
    512    s->strm                  = strm;
    513    strm->state              = s;
    514    s->state                 = BZ_X_MAGIC_1;
    515    s->bsLive                = 0;
    516    s->bsBuff                = 0;
    517    s->calculatedCombinedCRC = 0;
    518    strm->total_in_lo32      = 0;
    519    strm->total_in_hi32      = 0;
    520    strm->total_out_lo32     = 0;
    521    strm->total_out_hi32     = 0;
    522    s->smallDecompress       = (Bool)small;
    523    s->ll4                   = NULL;
    524    s->ll16                  = NULL;
    525    s->tt                    = NULL;
    526    s->currBlockNo           = 0;
    527    s->verbosity             = verbosity;
    528 
    529    return BZ_OK;
    530 }
    531 
    532 
    533 /*---------------------------------------------------*/
    534 /* Return  True iff data corruption is discovered.
    535    Returns False if there is no problem.
    536 */
    537 static
    538 Bool unRLE_obuf_to_output_FAST ( DState* s )
    539 {
    540    UChar k1;
    541 
    542    if (s->blockRandomised) {
    543 
    544       while (True) {
    545          /* try to finish existing run */
    546          while (True) {
    547             if (s->strm->avail_out == 0) return False;
    548             if (s->state_out_len == 0) break;
    549             *( (UChar*)(s->strm->next_out) ) = s->state_out_ch;
    550             BZ_UPDATE_CRC ( s->calculatedBlockCRC, s->state_out_ch );
    551             s->state_out_len--;
    552             s->strm->next_out++;
    553             s->strm->avail_out--;
    554             s->strm->total_out_lo32++;
    555             if (s->strm->total_out_lo32 == 0) s->strm->total_out_hi32++;
    556          }
    557 
    558          /* can a new run be started? */
    559          if (s->nblock_used == s->save_nblock+1) return False;
    560 
    561          /* Only caused by corrupt data stream? */
    562          if (s->nblock_used > s->save_nblock+1)
    563             return True;
    564 
    565          s->state_out_len = 1;
    566          s->state_out_ch = s->k0;
    567          BZ_GET_FAST(k1); BZ_RAND_UPD_MASK;
    568          k1 ^= BZ_RAND_MASK; s->nblock_used++;
    569          if (s->nblock_used == s->save_nblock+1) continue;
    570          if (k1 != s->k0) { s->k0 = k1; continue; };
    571 
    572          s->state_out_len = 2;
    573          BZ_GET_FAST(k1); BZ_RAND_UPD_MASK;
    574          k1 ^= BZ_RAND_MASK; s->nblock_used++;
    575          if (s->nblock_used == s->save_nblock+1) continue;
    576          if (k1 != s->k0) { s->k0 = k1; continue; };
    577 
    578          s->state_out_len = 3;
    579          BZ_GET_FAST(k1); BZ_RAND_UPD_MASK;
    580          k1 ^= BZ_RAND_MASK; s->nblock_used++;
    581          if (s->nblock_used == s->save_nblock+1) continue;
    582          if (k1 != s->k0) { s->k0 = k1; continue; };
    583 
    584          BZ_GET_FAST(k1); BZ_RAND_UPD_MASK;
    585          k1 ^= BZ_RAND_MASK; s->nblock_used++;
    586          s->state_out_len = ((Int32)k1) + 4;
    587          BZ_GET_FAST(s->k0); BZ_RAND_UPD_MASK;
    588          s->k0 ^= BZ_RAND_MASK; s->nblock_used++;
    589       }
    590 
    591    } else {
    592 
    593       /* restore */
    594       UInt32        c_calculatedBlockCRC = s->calculatedBlockCRC;
    595       UChar         c_state_out_ch       = s->state_out_ch;
    596       Int32         c_state_out_len      = s->state_out_len;
    597       Int32         c_nblock_used        = s->nblock_used;
    598       Int32         c_k0                 = s->k0;
    599       UInt32*       c_tt                 = s->tt;
    600       UInt32        c_tPos               = s->tPos;
    601       char*         cs_next_out          = s->strm->next_out;
    602       unsigned int  cs_avail_out         = s->strm->avail_out;
    603       Int32         ro_blockSize100k     = s->blockSize100k;
    604       /* end restore */
    605 
    606       UInt32       avail_out_INIT = cs_avail_out;
    607       Int32        s_save_nblockPP = s->save_nblock+1;
    608       unsigned int total_out_lo32_old;
    609 
    610       while (True) {
    611 
    612          /* try to finish existing run */
    613          if (c_state_out_len > 0) {
    614             while (True) {
    615                if (cs_avail_out == 0) goto return_notr;
    616                if (c_state_out_len == 1) break;
    617                *( (UChar*)(cs_next_out) ) = c_state_out_ch;
    618                BZ_UPDATE_CRC ( c_calculatedBlockCRC, c_state_out_ch );
    619                c_state_out_len--;
    620                cs_next_out++;
    621                cs_avail_out--;
    622             }
    623             s_state_out_len_eq_one:
    624             {
    625                if (cs_avail_out == 0) {
    626                   c_state_out_len = 1; goto return_notr;
    627                };
    628                *( (UChar*)(cs_next_out) ) = c_state_out_ch;
    629                BZ_UPDATE_CRC ( c_calculatedBlockCRC, c_state_out_ch );
    630                cs_next_out++;
    631                cs_avail_out--;
    632             }
    633          }
    634          /* Only caused by corrupt data stream? */
    635          if (c_nblock_used > s_save_nblockPP)
    636             return True;
    637 
    638          /* can a new run be started? */
    639          if (c_nblock_used == s_save_nblockPP) {
    640             c_state_out_len = 0; goto return_notr;
    641          };
    642          c_state_out_ch = c_k0;
    643          BZ_GET_FAST_C(k1); c_nblock_used++;
    644          if (k1 != c_k0) {
    645             c_k0 = k1; goto s_state_out_len_eq_one;
    646          };
    647          if (c_nblock_used == s_save_nblockPP)
    648             goto s_state_out_len_eq_one;
    649 
    650          c_state_out_len = 2;
    651          BZ_GET_FAST_C(k1); c_nblock_used++;
    652          if (c_nblock_used == s_save_nblockPP) continue;
    653          if (k1 != c_k0) { c_k0 = k1; continue; };
    654 
    655          c_state_out_len = 3;
    656          BZ_GET_FAST_C(k1); c_nblock_used++;
    657          if (c_nblock_used == s_save_nblockPP) continue;
    658          if (k1 != c_k0) { c_k0 = k1; continue; };
    659 
    660          BZ_GET_FAST_C(k1); c_nblock_used++;
    661          c_state_out_len = ((Int32)k1) + 4;
    662          BZ_GET_FAST_C(c_k0); c_nblock_used++;
    663       }
    664 
    665       return_notr:
    666       total_out_lo32_old = s->strm->total_out_lo32;
    667       s->strm->total_out_lo32 += (avail_out_INIT - cs_avail_out);
    668       if (s->strm->total_out_lo32 < total_out_lo32_old)
    669          s->strm->total_out_hi32++;
    670 
    671       /* save */
    672       s->calculatedBlockCRC = c_calculatedBlockCRC;
    673       s->state_out_ch       = c_state_out_ch;
    674       s->state_out_len      = c_state_out_len;
    675       s->nblock_used        = c_nblock_used;
    676       s->k0                 = c_k0;
    677       s->tt                 = c_tt;
    678       s->tPos               = c_tPos;
    679       s->strm->next_out     = cs_next_out;
    680       s->strm->avail_out    = cs_avail_out;
    681       /* end save */
    682    }
    683    return False;
    684 }
    685 
    686 
    687 
    688 /*---------------------------------------------------*/
    689 __inline__ Int32 BZ2_indexIntoF ( Int32 indx, Int32 *cftab )
    690 {
    691    Int32 nb, na, mid;
    692    nb = 0;
    693    na = 256;
    694    do {
    695       mid = (nb + na) >> 1;
    696       if (indx >= cftab[mid]) nb = mid; else na = mid;
    697    }
    698    while (na - nb != 1);
    699    return nb;
    700 }
    701 
    702 
    703 /*---------------------------------------------------*/
    704 /* Return  True iff data corruption is discovered.
    705    Returns False if there is no problem.
    706 */
    707 static
    708 Bool unRLE_obuf_to_output_SMALL ( DState* s )
    709 {
    710    UChar k1;
    711 
    712    if (s->blockRandomised) {
    713 
    714       while (True) {
    715          /* try to finish existing run */
    716          while (True) {
    717             if (s->strm->avail_out == 0) return False;
    718             if (s->state_out_len == 0) break;
    719             *( (UChar*)(s->strm->next_out) ) = s->state_out_ch;
    720             BZ_UPDATE_CRC ( s->calculatedBlockCRC, s->state_out_ch );
    721             s->state_out_len--;
    722             s->strm->next_out++;
    723             s->strm->avail_out--;
    724             s->strm->total_out_lo32++;
    725             if (s->strm->total_out_lo32 == 0) s->strm->total_out_hi32++;
    726          }
    727 
    728          /* can a new run be started? */
    729          if (s->nblock_used == s->save_nblock+1) return False;
    730 
    731          /* Only caused by corrupt data stream? */
    732          if (s->nblock_used > s->save_nblock+1)
    733             return True;
    734 
    735          s->state_out_len = 1;
    736          s->state_out_ch = s->k0;
    737          BZ_GET_SMALL(k1); BZ_RAND_UPD_MASK;
    738          k1 ^= BZ_RAND_MASK; s->nblock_used++;
    739          if (s->nblock_used == s->save_nblock+1) continue;
    740          if (k1 != s->k0) { s->k0 = k1; continue; };
    741 
    742          s->state_out_len = 2;
    743          BZ_GET_SMALL(k1); BZ_RAND_UPD_MASK;
    744          k1 ^= BZ_RAND_MASK; s->nblock_used++;
    745          if (s->nblock_used == s->save_nblock+1) continue;
    746          if (k1 != s->k0) { s->k0 = k1; continue; };
    747 
    748          s->state_out_len = 3;
    749          BZ_GET_SMALL(k1); BZ_RAND_UPD_MASK;
    750          k1 ^= BZ_RAND_MASK; s->nblock_used++;
    751          if (s->nblock_used == s->save_nblock+1) continue;
    752          if (k1 != s->k0) { s->k0 = k1; continue; };
    753 
    754          BZ_GET_SMALL(k1); BZ_RAND_UPD_MASK;
    755          k1 ^= BZ_RAND_MASK; s->nblock_used++;
    756          s->state_out_len = ((Int32)k1) + 4;
    757          BZ_GET_SMALL(s->k0); BZ_RAND_UPD_MASK;
    758          s->k0 ^= BZ_RAND_MASK; s->nblock_used++;
    759       }
    760 
    761    } else {
    762 
    763       while (True) {
    764          /* try to finish existing run */
    765          while (True) {
    766             if (s->strm->avail_out == 0) return False;
    767             if (s->state_out_len == 0) break;
    768             *( (UChar*)(s->strm->next_out) ) = s->state_out_ch;
    769             BZ_UPDATE_CRC ( s->calculatedBlockCRC, s->state_out_ch );
    770             s->state_out_len--;
    771             s->strm->next_out++;
    772             s->strm->avail_out--;
    773             s->strm->total_out_lo32++;
    774             if (s->strm->total_out_lo32 == 0) s->strm->total_out_hi32++;
    775          }
    776 
    777          /* can a new run be started? */
    778          if (s->nblock_used == s->save_nblock+1) return False;
    779 
    780          /* Only caused by corrupt data stream? */
    781          if (s->nblock_used > s->save_nblock+1)
    782             return True;
    783 
    784          s->state_out_len = 1;
    785          s->state_out_ch = s->k0;
    786          BZ_GET_SMALL(k1); s->nblock_used++;
    787          if (s->nblock_used == s->save_nblock+1) continue;
    788          if (k1 != s->k0) { s->k0 = k1; continue; };
    789 
    790          s->state_out_len = 2;
    791          BZ_GET_SMALL(k1); s->nblock_used++;
    792          if (s->nblock_used == s->save_nblock+1) continue;
    793          if (k1 != s->k0) { s->k0 = k1; continue; };
    794 
    795          s->state_out_len = 3;
    796          BZ_GET_SMALL(k1); s->nblock_used++;
    797          if (s->nblock_used == s->save_nblock+1) continue;
    798          if (k1 != s->k0) { s->k0 = k1; continue; };
    799 
    800          BZ_GET_SMALL(k1); s->nblock_used++;
    801          s->state_out_len = ((Int32)k1) + 4;
    802          BZ_GET_SMALL(s->k0); s->nblock_used++;
    803       }
    804 
    805    }
    806 }
    807 
    808 
    809 /*---------------------------------------------------*/
    810 int BZ_API(BZ2_bzDecompress) ( bz_stream *strm )
    811 {
    812    Bool    corrupt;
    813    DState* s;
    814    if (strm == NULL) return BZ_PARAM_ERROR;
    815    s = strm->state;
    816    if (s == NULL) return BZ_PARAM_ERROR;
    817    if (s->strm != strm) return BZ_PARAM_ERROR;
    818 
    819    while (True) {
    820       if (s->state == BZ_X_IDLE) return BZ_SEQUENCE_ERROR;
    821       if (s->state == BZ_X_OUTPUT) {
    822          if (s->smallDecompress)
    823             corrupt = unRLE_obuf_to_output_SMALL ( s ); else
    824             corrupt = unRLE_obuf_to_output_FAST  ( s );
    825          if (corrupt) return BZ_DATA_ERROR;
    826          if (s->nblock_used == s->save_nblock+1 && s->state_out_len == 0) {
    827             BZ_FINALISE_CRC ( s->calculatedBlockCRC );
    828             if (s->verbosity >= 3)
    829                VPrintf2 ( " {0x%08x, 0x%08x}", s->storedBlockCRC,
    830                           s->calculatedBlockCRC );
    831             if (s->verbosity >= 2) VPrintf0 ( "]" );
    832             if (s->calculatedBlockCRC != s->storedBlockCRC)
    833                return BZ_DATA_ERROR;
    834             s->calculatedCombinedCRC
    835                = (s->calculatedCombinedCRC << 1) |
    836                     (s->calculatedCombinedCRC >> 31);
    837             s->calculatedCombinedCRC ^= s->calculatedBlockCRC;
    838             s->state = BZ_X_BLKHDR_1;
    839          } else {
    840             return BZ_OK;
    841          }
    842       }
    843       if (s->state >= BZ_X_MAGIC_1) {
    844          Int32 r = BZ2_decompress ( s );
    845          if (r == BZ_STREAM_END) {
    846             if (s->verbosity >= 3)
    847                VPrintf2 ( "\n    combined CRCs: stored = 0x%08x, computed = 0x%08x",
    848                           s->storedCombinedCRC, s->calculatedCombinedCRC );
    849             if (s->calculatedCombinedCRC != s->storedCombinedCRC)
    850                return BZ_DATA_ERROR;
    851             return r;
    852          }
    853          if (s->state != BZ_X_OUTPUT) return r;
    854       }
    855    }
    856 
    857    AssertH ( 0, 6001 );
    858 
    859    return 0;  /*NOTREACHED*/
    860 }
    861 
    862 
    863 /*---------------------------------------------------*/
    864 int BZ_API(BZ2_bzDecompressEnd)  ( bz_stream *strm )
    865 {
    866    DState* s;
    867    if (strm == NULL) return BZ_PARAM_ERROR;
    868    s = strm->state;
    869    if (s == NULL) return BZ_PARAM_ERROR;
    870    if (s->strm != strm) return BZ_PARAM_ERROR;
    871 
    872    if (s->tt   != NULL) BZFREE(s->tt);
    873    if (s->ll16 != NULL) BZFREE(s->ll16);
    874    if (s->ll4  != NULL) BZFREE(s->ll4);
    875 
    876    BZFREE(strm->state);
    877    strm->state = NULL;
    878 
    879    return BZ_OK;
    880 }
    881 
    882 
    883 #ifndef BZ_NO_STDIO
    884 /*---------------------------------------------------*/
    885 /*--- File I/O stuff                              ---*/
    886 /*---------------------------------------------------*/
    887 
    888 #define BZ_SETERR(eee)                    \
    889 {                                         \
    890    if (bzerror != NULL) *bzerror = eee;   \
    891    if (bzf != NULL) bzf->lastErr = eee;   \
    892 }
    893 
    894 typedef
    895    struct {
    896       FILE*     handle;
    897       Char      buf[BZ_MAX_UNUSED];
    898       Int32     bufN;
    899       Bool      writing;
    900       bz_stream strm;
    901       Int32     lastErr;
    902       Bool      initialisedOk;
    903    }
    904    bzFile;
    905 
    906 
    907 /*---------------------------------------------*/
    908 static Bool myfeof ( FILE* f )
    909 {
    910    Int32 c = fgetc ( f );
    911    if (c == EOF) return True;
    912    ungetc ( c, f );
    913    return False;
    914 }
    915 
    916 
    917 /*---------------------------------------------------*/
    918 BZFILE* BZ_API(BZ2_bzWriteOpen)
    919                     ( int*  bzerror,
    920                       FILE* f,
    921                       int   blockSize100k,
    922                       int   verbosity,
    923                       int   workFactor )
    924 {
    925    Int32   ret;
    926    bzFile* bzf = NULL;
    927 
    928    BZ_SETERR(BZ_OK);
    929 
    930    if (f == NULL ||
    931        (blockSize100k < 1 || blockSize100k > 9) ||
    932        (workFactor < 0 || workFactor > 250) ||
    933        (verbosity < 0 || verbosity > 4))
    934       { BZ_SETERR(BZ_PARAM_ERROR); return NULL; };
    935 
    936    if (ferror(f))
    937       { BZ_SETERR(BZ_IO_ERROR); return NULL; };
    938 
    939    bzf = malloc ( sizeof(bzFile) );
    940    if (bzf == NULL)
    941       { BZ_SETERR(BZ_MEM_ERROR); return NULL; };
    942 
    943    BZ_SETERR(BZ_OK);
    944    bzf->initialisedOk = False;
    945    bzf->bufN          = 0;
    946    bzf->handle        = f;
    947    bzf->writing       = True;
    948    bzf->strm.bzalloc  = NULL;
    949    bzf->strm.bzfree   = NULL;
    950    bzf->strm.opaque   = NULL;
    951 
    952    if (workFactor == 0) workFactor = 30;
    953    ret = BZ2_bzCompressInit ( &(bzf->strm), blockSize100k,
    954                               verbosity, workFactor );
    955    if (ret != BZ_OK)
    956       { BZ_SETERR(ret); free(bzf); return NULL; };
    957 
    958    bzf->strm.avail_in = 0;
    959    bzf->initialisedOk = True;
    960    return bzf;
    961 }
    962 
    963 
    964 
    965 /*---------------------------------------------------*/
    966 void BZ_API(BZ2_bzWrite)
    967              ( int*    bzerror,
    968                BZFILE* b,
    969                void*   buf,
    970                int     len )
    971 {
    972    Int32 n, n2, ret;
    973    bzFile* bzf = (bzFile*)b;
    974 
    975    BZ_SETERR(BZ_OK);
    976    if (bzf == NULL || buf == NULL || len < 0)
    977       { BZ_SETERR(BZ_PARAM_ERROR); return; };
    978    if (!(bzf->writing))
    979       { BZ_SETERR(BZ_SEQUENCE_ERROR); return; };
    980    if (ferror(bzf->handle))
    981       { BZ_SETERR(BZ_IO_ERROR); return; };
    982 
    983    if (len == 0)
    984       { BZ_SETERR(BZ_OK); return; };
    985 
    986    bzf->strm.avail_in = len;
    987    bzf->strm.next_in  = buf;
    988 
    989    while (True) {
    990       bzf->strm.avail_out = BZ_MAX_UNUSED;
    991       bzf->strm.next_out = bzf->buf;
    992       ret = BZ2_bzCompress ( &(bzf->strm), BZ_RUN );
    993       if (ret != BZ_RUN_OK)
    994          { BZ_SETERR(ret); return; };
    995 
    996       if (bzf->strm.avail_out < BZ_MAX_UNUSED) {
    997          n = BZ_MAX_UNUSED - bzf->strm.avail_out;
    998          n2 = fwrite ( (void*)(bzf->buf), sizeof(UChar),
    999                        n, bzf->handle );
   1000          if (n != n2 || ferror(bzf->handle))
   1001             { BZ_SETERR(BZ_IO_ERROR); return; };
   1002       }
   1003 
   1004       if (bzf->strm.avail_in == 0)
   1005          { BZ_SETERR(BZ_OK); return; };
   1006    }
   1007 }
   1008 
   1009 
   1010 /*---------------------------------------------------*/
   1011 void BZ_API(BZ2_bzWriteClose)
   1012                   ( int*          bzerror,
   1013                     BZFILE*       b,
   1014                     int           abandon,
   1015                     unsigned int* nbytes_in,
   1016                     unsigned int* nbytes_out )
   1017 {
   1018    BZ2_bzWriteClose64 ( bzerror, b, abandon,
   1019                         nbytes_in, NULL, nbytes_out, NULL );
   1020 }
   1021 
   1022 
   1023 void BZ_API(BZ2_bzWriteClose64)
   1024                   ( int*          bzerror,
   1025                     BZFILE*       b,
   1026                     int           abandon,
   1027                     unsigned int* nbytes_in_lo32,
   1028                     unsigned int* nbytes_in_hi32,
   1029                     unsigned int* nbytes_out_lo32,
   1030                     unsigned int* nbytes_out_hi32 )
   1031 {
   1032    Int32   n, n2, ret;
   1033    bzFile* bzf = (bzFile*)b;
   1034 
   1035    if (bzf == NULL)
   1036       { BZ_SETERR(BZ_OK); return; };
   1037    if (!(bzf->writing))
   1038       { BZ_SETERR(BZ_SEQUENCE_ERROR); return; };
   1039    if (ferror(bzf->handle))
   1040       { BZ_SETERR(BZ_IO_ERROR); return; };
   1041 
   1042    if (nbytes_in_lo32 != NULL) *nbytes_in_lo32 = 0;
   1043    if (nbytes_in_hi32 != NULL) *nbytes_in_hi32 = 0;
   1044    if (nbytes_out_lo32 != NULL) *nbytes_out_lo32 = 0;
   1045    if (nbytes_out_hi32 != NULL) *nbytes_out_hi32 = 0;
   1046 
   1047    if ((!abandon) && bzf->lastErr == BZ_OK) {
   1048       while (True) {
   1049          bzf->strm.avail_out = BZ_MAX_UNUSED;
   1050          bzf->strm.next_out = bzf->buf;
   1051          ret = BZ2_bzCompress ( &(bzf->strm), BZ_FINISH );
   1052          if (ret != BZ_FINISH_OK && ret != BZ_STREAM_END)
   1053             { BZ_SETERR(ret); return; };
   1054 
   1055          if (bzf->strm.avail_out < BZ_MAX_UNUSED) {
   1056             n = BZ_MAX_UNUSED - bzf->strm.avail_out;
   1057             n2 = fwrite ( (void*)(bzf->buf), sizeof(UChar),
   1058                           n, bzf->handle );
   1059             if (n != n2 || ferror(bzf->handle))
   1060                { BZ_SETERR(BZ_IO_ERROR); return; };
   1061          }
   1062 
   1063          if (ret == BZ_STREAM_END) break;
   1064       }
   1065    }
   1066 
   1067    if ( !abandon && !ferror ( bzf->handle ) ) {
   1068       fflush ( bzf->handle );
   1069       if (ferror(bzf->handle))
   1070          { BZ_SETERR(BZ_IO_ERROR); return; };
   1071    }
   1072 
   1073    if (nbytes_in_lo32 != NULL)
   1074       *nbytes_in_lo32 = bzf->strm.total_in_lo32;
   1075    if (nbytes_in_hi32 != NULL)
   1076       *nbytes_in_hi32 = bzf->strm.total_in_hi32;
   1077    if (nbytes_out_lo32 != NULL)
   1078       *nbytes_out_lo32 = bzf->strm.total_out_lo32;
   1079    if (nbytes_out_hi32 != NULL)
   1080       *nbytes_out_hi32 = bzf->strm.total_out_hi32;
   1081 
   1082    BZ_SETERR(BZ_OK);
   1083    BZ2_bzCompressEnd ( &(bzf->strm) );
   1084    free ( bzf );
   1085 }
   1086 
   1087 
   1088 /*---------------------------------------------------*/
   1089 BZFILE* BZ_API(BZ2_bzReadOpen)
   1090                    ( int*  bzerror,
   1091                      FILE* f,
   1092                      int   verbosity,
   1093                      int   small,
   1094                      void* unused,
   1095                      int   nUnused )
   1096 {
   1097    bzFile* bzf = NULL;
   1098    int     ret;
   1099 
   1100    BZ_SETERR(BZ_OK);
   1101 
   1102    if (f == NULL ||
   1103        (small != 0 && small != 1) ||
   1104        (verbosity < 0 || verbosity > 4) ||
   1105        (unused == NULL && nUnused != 0) ||
   1106        (unused != NULL && (nUnused < 0 || nUnused > BZ_MAX_UNUSED)))
   1107       { BZ_SETERR(BZ_PARAM_ERROR); return NULL; };
   1108 
   1109    if (ferror(f))
   1110       { BZ_SETERR(BZ_IO_ERROR); return NULL; };
   1111 
   1112    bzf = malloc ( sizeof(bzFile) );
   1113    if (bzf == NULL)
   1114       { BZ_SETERR(BZ_MEM_ERROR); return NULL; };
   1115 
   1116    BZ_SETERR(BZ_OK);
   1117 
   1118    bzf->initialisedOk = False;
   1119    bzf->handle        = f;
   1120    bzf->bufN          = 0;
   1121    bzf->writing       = False;
   1122    bzf->strm.bzalloc  = NULL;
   1123    bzf->strm.bzfree   = NULL;
   1124    bzf->strm.opaque   = NULL;
   1125 
   1126    while (nUnused > 0) {
   1127       bzf->buf[bzf->bufN] = *((UChar*)(unused)); bzf->bufN++;
   1128       unused = ((void*)( 1 + ((UChar*)(unused))  ));
   1129       nUnused--;
   1130    }
   1131 
   1132    ret = BZ2_bzDecompressInit ( &(bzf->strm), verbosity, small );
   1133    if (ret != BZ_OK)
   1134       { BZ_SETERR(ret); free(bzf); return NULL; };
   1135 
   1136    bzf->strm.avail_in = bzf->bufN;
   1137    bzf->strm.next_in  = bzf->buf;
   1138 
   1139    bzf->initialisedOk = True;
   1140    return bzf;
   1141 }
   1142 
   1143 
   1144 /*---------------------------------------------------*/
   1145 void BZ_API(BZ2_bzReadClose) ( int *bzerror, BZFILE *b )
   1146 {
   1147    bzFile* bzf = (bzFile*)b;
   1148 
   1149    BZ_SETERR(BZ_OK);
   1150    if (bzf == NULL)
   1151       { BZ_SETERR(BZ_OK); return; };
   1152 
   1153    if (bzf->writing)
   1154       { BZ_SETERR(BZ_SEQUENCE_ERROR); return; };
   1155 
   1156    if (bzf->initialisedOk)
   1157       (void)BZ2_bzDecompressEnd ( &(bzf->strm) );
   1158    free ( bzf );
   1159 }
   1160 
   1161 
   1162 /*---------------------------------------------------*/
   1163 int BZ_API(BZ2_bzRead)
   1164            ( int*    bzerror,
   1165              BZFILE* b,
   1166              void*   buf,
   1167              int     len )
   1168 {
   1169    Int32   n, ret;
   1170    bzFile* bzf = (bzFile*)b;
   1171 
   1172    BZ_SETERR(BZ_OK);
   1173 
   1174    if (bzf == NULL || buf == NULL || len < 0)
   1175       { BZ_SETERR(BZ_PARAM_ERROR); return 0; };
   1176 
   1177    if (bzf->writing)
   1178       { BZ_SETERR(BZ_SEQUENCE_ERROR); return 0; };
   1179 
   1180    if (len == 0)
   1181       { BZ_SETERR(BZ_OK); return 0; };
   1182 
   1183    bzf->strm.avail_out = len;
   1184    bzf->strm.next_out = buf;
   1185 
   1186    while (True) {
   1187 
   1188       if (ferror(bzf->handle))
   1189          { BZ_SETERR(BZ_IO_ERROR); return 0; };
   1190 
   1191       if (bzf->strm.avail_in == 0 && !myfeof(bzf->handle)) {
   1192          n = fread ( bzf->buf, sizeof(UChar),
   1193                      BZ_MAX_UNUSED, bzf->handle );
   1194          if (ferror(bzf->handle))
   1195             { BZ_SETERR(BZ_IO_ERROR); return 0; };
   1196          bzf->bufN = n;
   1197          bzf->strm.avail_in = bzf->bufN;
   1198          bzf->strm.next_in = bzf->buf;
   1199       }
   1200 
   1201       ret = BZ2_bzDecompress ( &(bzf->strm) );
   1202 
   1203       if (ret != BZ_OK && ret != BZ_STREAM_END)
   1204          { BZ_SETERR(ret); return 0; };
   1205 
   1206       if (ret == BZ_OK && myfeof(bzf->handle) &&
   1207           bzf->strm.avail_in == 0 && bzf->strm.avail_out > 0)
   1208          { BZ_SETERR(BZ_UNEXPECTED_EOF); return 0; };
   1209 
   1210       if (ret == BZ_STREAM_END)
   1211          { BZ_SETERR(BZ_STREAM_END);
   1212            return len - bzf->strm.avail_out; };
   1213       if (bzf->strm.avail_out == 0)
   1214          { BZ_SETERR(BZ_OK); return len; };
   1215 
   1216    }
   1217 
   1218    return 0; /*not reached*/
   1219 }
   1220 
   1221 
   1222 /*---------------------------------------------------*/
   1223 void BZ_API(BZ2_bzReadGetUnused)
   1224                      ( int*    bzerror,
   1225                        BZFILE* b,
   1226                        void**  unused,
   1227                        int*    nUnused )
   1228 {
   1229    bzFile* bzf = (bzFile*)b;
   1230    if (bzf == NULL)
   1231       { BZ_SETERR(BZ_PARAM_ERROR); return; };
   1232    if (bzf->lastErr != BZ_STREAM_END)
   1233       { BZ_SETERR(BZ_SEQUENCE_ERROR); return; };
   1234    if (unused == NULL || nUnused == NULL)
   1235       { BZ_SETERR(BZ_PARAM_ERROR); return; };
   1236 
   1237    BZ_SETERR(BZ_OK);
   1238    *nUnused = bzf->strm.avail_in;
   1239    *unused = bzf->strm.next_in;
   1240 }
   1241 #endif
   1242 
   1243 
   1244 /*---------------------------------------------------*/
   1245 /*--- Misc convenience stuff                      ---*/
   1246 /*---------------------------------------------------*/
   1247 
   1248 /*---------------------------------------------------*/
   1249 int BZ_API(BZ2_bzBuffToBuffCompress)
   1250                          ( char*         dest,
   1251                            unsigned int* destLen,
   1252                            char*         source,
   1253                            unsigned int  sourceLen,
   1254                            int           blockSize100k,
   1255                            int           verbosity,
   1256                            int           workFactor )
   1257 {
   1258    bz_stream strm;
   1259    int ret;
   1260 
   1261    if (dest == NULL || destLen == NULL ||
   1262        source == NULL ||
   1263        blockSize100k < 1 || blockSize100k > 9 ||
   1264        verbosity < 0 || verbosity > 4 ||
   1265        workFactor < 0 || workFactor > 250)
   1266       return BZ_PARAM_ERROR;
   1267 
   1268    if (workFactor == 0) workFactor = 30;
   1269    strm.bzalloc = NULL;
   1270    strm.bzfree = NULL;
   1271    strm.opaque = NULL;
   1272    ret = BZ2_bzCompressInit ( &strm, blockSize100k,
   1273                               verbosity, workFactor );
   1274    if (ret != BZ_OK) return ret;
   1275 
   1276    strm.next_in = source;
   1277    strm.next_out = dest;
   1278    strm.avail_in = sourceLen;
   1279    strm.avail_out = *destLen;
   1280 
   1281    ret = BZ2_bzCompress ( &strm, BZ_FINISH );
   1282    if (ret == BZ_FINISH_OK) goto output_overflow;
   1283    if (ret != BZ_STREAM_END) goto errhandler;
   1284 
   1285    /* normal termination */
   1286    *destLen -= strm.avail_out;
   1287    BZ2_bzCompressEnd ( &strm );
   1288    return BZ_OK;
   1289 
   1290    output_overflow:
   1291    BZ2_bzCompressEnd ( &strm );
   1292    return BZ_OUTBUFF_FULL;
   1293 
   1294    errhandler:
   1295    BZ2_bzCompressEnd ( &strm );
   1296    return ret;
   1297 }
   1298 
   1299 
   1300 /*---------------------------------------------------*/
   1301 int BZ_API(BZ2_bzBuffToBuffDecompress)
   1302                            ( char*         dest,
   1303                              unsigned int* destLen,
   1304                              char*         source,
   1305                              unsigned int  sourceLen,
   1306                              int           small,
   1307                              int           verbosity )
   1308 {
   1309    bz_stream strm;
   1310    int ret;
   1311 
   1312    if (dest == NULL || destLen == NULL ||
   1313        source == NULL ||
   1314        (small != 0 && small != 1) ||
   1315        verbosity < 0 || verbosity > 4)
   1316           return BZ_PARAM_ERROR;
   1317 
   1318    strm.bzalloc = NULL;
   1319    strm.bzfree = NULL;
   1320    strm.opaque = NULL;
   1321    ret = BZ2_bzDecompressInit ( &strm, verbosity, small );
   1322    if (ret != BZ_OK) return ret;
   1323 
   1324    strm.next_in = source;
   1325    strm.next_out = dest;
   1326    strm.avail_in = sourceLen;
   1327    strm.avail_out = *destLen;
   1328 
   1329    ret = BZ2_bzDecompress ( &strm );
   1330    if (ret == BZ_OK) goto output_overflow_or_eof;
   1331    if (ret != BZ_STREAM_END) goto errhandler;
   1332 
   1333    /* normal termination */
   1334    *destLen -= strm.avail_out;
   1335    BZ2_bzDecompressEnd ( &strm );
   1336    return BZ_OK;
   1337 
   1338    output_overflow_or_eof:
   1339    if (strm.avail_out > 0) {
   1340       BZ2_bzDecompressEnd ( &strm );
   1341       return BZ_UNEXPECTED_EOF;
   1342    } else {
   1343       BZ2_bzDecompressEnd ( &strm );
   1344       return BZ_OUTBUFF_FULL;
   1345    };
   1346 
   1347    errhandler:
   1348    BZ2_bzDecompressEnd ( &strm );
   1349    return ret;
   1350 }
   1351 
   1352 
   1353 /*---------------------------------------------------*/
   1354 /*--
   1355    Code contributed by Yoshioka Tsuneo (tsuneo (at) rr.iij4u.or.jp)
   1356    to support better zlib compatibility.
   1357    This code is not _officially_ part of libbzip2 (yet);
   1358    I haven't tested it, documented it, or considered the
   1359    threading-safeness of it.
   1360    If this code breaks, please contact both Yoshioka and me.
   1361 --*/
   1362 /*---------------------------------------------------*/
   1363 
   1364 /*---------------------------------------------------*/
   1365 /*--
   1366    return version like "0.9.5d, 4-Sept-1999".
   1367 --*/
   1368 const char * BZ_API(BZ2_bzlibVersion)(void)
   1369 {
   1370    return BZ_VERSION;
   1371 }
   1372 
   1373 
   1374 #ifndef BZ_NO_STDIO
   1375 /*---------------------------------------------------*/
   1376 
   1377 #if defined(_WIN32) || defined(OS2) || defined(MSDOS)
   1378 #   include <fcntl.h>
   1379 #   include <io.h>
   1380 #   define SET_BINARY_MODE(file) setmode(fileno(file),O_BINARY)
   1381 #else
   1382 #   define SET_BINARY_MODE(file)
   1383 #endif
   1384 static
   1385 BZFILE * bzopen_or_bzdopen
   1386                ( const char *path,   /* no use when bzdopen */
   1387                  int fd,             /* no use when bzdopen */
   1388                  const char *mode,
   1389                  int open_mode)      /* bzopen: 0, bzdopen:1 */
   1390 {
   1391    int    bzerr;
   1392    char   unused[BZ_MAX_UNUSED];
   1393    int    blockSize100k = 9;
   1394    int    writing       = 0;
   1395    char   mode2[10]     = "";
   1396    FILE   *fp           = NULL;
   1397    BZFILE *bzfp         = NULL;
   1398    int    verbosity     = 0;
   1399    int    workFactor    = 30;
   1400    int    smallMode     = 0;
   1401    int    nUnused       = 0;
   1402 
   1403    if (mode == NULL) return NULL;
   1404    while (*mode) {
   1405       switch (*mode) {
   1406       case 'r':
   1407          writing = 0; break;
   1408       case 'w':
   1409          writing = 1; break;
   1410       case 's':
   1411          smallMode = 1; break;
   1412       default:
   1413          if (isdigit((int)(*mode))) {
   1414             blockSize100k = *mode-BZ_HDR_0;
   1415          }
   1416       }
   1417       mode++;
   1418    }
   1419    strcat(mode2, writing ? "w" : "r" );
   1420    strcat(mode2,"b");   /* binary mode */
   1421 
   1422    if (open_mode==0) {
   1423       if (path==NULL || strcmp(path,"")==0) {
   1424         fp = (writing ? stdout : stdin);
   1425         SET_BINARY_MODE(fp);
   1426       } else {
   1427         fp = fopen(path,mode2);
   1428       }
   1429    } else {
   1430 #ifdef BZ_STRICT_ANSI
   1431       fp = NULL;
   1432 #else
   1433       fp = fdopen(fd,mode2);
   1434 #endif
   1435    }
   1436    if (fp == NULL) return NULL;
   1437 
   1438    if (writing) {
   1439       /* Guard against total chaos and anarchy -- JRS */
   1440       if (blockSize100k < 1) blockSize100k = 1;
   1441       if (blockSize100k > 9) blockSize100k = 9;
   1442       bzfp = BZ2_bzWriteOpen(&bzerr,fp,blockSize100k,
   1443                              verbosity,workFactor);
   1444    } else {
   1445       bzfp = BZ2_bzReadOpen(&bzerr,fp,verbosity,smallMode,
   1446                             unused,nUnused);
   1447    }
   1448    if (bzfp == NULL) {
   1449       if (fp != stdin && fp != stdout) fclose(fp);
   1450       return NULL;
   1451    }
   1452    return bzfp;
   1453 }
   1454 
   1455 
   1456 /*---------------------------------------------------*/
   1457 /*--
   1458    open file for read or write.
   1459       ex) bzopen("file","w9")
   1460       case path="" or NULL => use stdin or stdout.
   1461 --*/
   1462 BZFILE * BZ_API(BZ2_bzopen)
   1463                ( const char *path,
   1464                  const char *mode )
   1465 {
   1466    return bzopen_or_bzdopen(path,-1,mode,/*bzopen*/0);
   1467 }
   1468 
   1469 
   1470 /*---------------------------------------------------*/
   1471 BZFILE * BZ_API(BZ2_bzdopen)
   1472                ( int fd,
   1473                  const char *mode )
   1474 {
   1475    return bzopen_or_bzdopen(NULL,fd,mode,/*bzdopen*/1);
   1476 }
   1477 
   1478 
   1479 /*---------------------------------------------------*/
   1480 int BZ_API(BZ2_bzread) (BZFILE* b, void* buf, int len )
   1481 {
   1482    int bzerr, nread;
   1483    if (((bzFile*)b)->lastErr == BZ_STREAM_END) return 0;
   1484    nread = BZ2_bzRead(&bzerr,b,buf,len);
   1485    if (bzerr == BZ_OK || bzerr == BZ_STREAM_END) {
   1486       return nread;
   1487    } else {
   1488       return -1;
   1489    }
   1490 }
   1491 
   1492 
   1493 /*---------------------------------------------------*/
   1494 int BZ_API(BZ2_bzwrite) (BZFILE* b, void* buf, int len )
   1495 {
   1496    int bzerr;
   1497 
   1498    BZ2_bzWrite(&bzerr,b,buf,len);
   1499    if(bzerr == BZ_OK){
   1500       return len;
   1501    }else{
   1502       return -1;
   1503    }
   1504 }
   1505 
   1506 
   1507 /*---------------------------------------------------*/
   1508 int BZ_API(BZ2_bzflush) (BZFILE *b)
   1509 {
   1510    /* do nothing now... */
   1511    return 0;
   1512 }
   1513 
   1514 
   1515 /*---------------------------------------------------*/
   1516 void BZ_API(BZ2_bzclose) (BZFILE* b)
   1517 {
   1518    int bzerr;
   1519    FILE *fp;
   1520 
   1521    if (b==NULL) {return;}
   1522    fp = ((bzFile *)b)->handle;
   1523    if(((bzFile*)b)->writing){
   1524       BZ2_bzWriteClose(&bzerr,b,0,NULL,NULL);
   1525       if(bzerr != BZ_OK){
   1526          BZ2_bzWriteClose(NULL,b,1,NULL,NULL);
   1527       }
   1528    }else{
   1529       BZ2_bzReadClose(&bzerr,b);
   1530    }
   1531    if(fp!=stdin && fp!=stdout){
   1532       fclose(fp);
   1533    }
   1534 }
   1535 
   1536 
   1537 /*---------------------------------------------------*/
   1538 /*--
   1539    return last error code
   1540 --*/
   1541 static const char *bzerrorstrings[] = {
   1542        "OK"
   1543       ,"SEQUENCE_ERROR"
   1544       ,"PARAM_ERROR"
   1545       ,"MEM_ERROR"
   1546       ,"DATA_ERROR"
   1547       ,"DATA_ERROR_MAGIC"
   1548       ,"IO_ERROR"
   1549       ,"UNEXPECTED_EOF"
   1550       ,"OUTBUFF_FULL"
   1551       ,"CONFIG_ERROR"
   1552       ,"???"   /* for future */
   1553       ,"???"   /* for future */
   1554       ,"???"   /* for future */
   1555       ,"???"   /* for future */
   1556       ,"???"   /* for future */
   1557       ,"???"   /* for future */
   1558 };
   1559 
   1560 
   1561 const char * BZ_API(BZ2_bzerror) (BZFILE *b, int *errnum)
   1562 {
   1563    int err = ((bzFile *)b)->lastErr;
   1564 
   1565    if(err>0) err = 0;
   1566    *errnum = err;
   1567    return bzerrorstrings[err*-1];
   1568 }
   1569 #endif
   1570 
   1571 
   1572 /*-------------------------------------------------------------*/
   1573 /*--- end                                           bzlib.c ---*/
   1574 /*-------------------------------------------------------------*/
   1575