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