bzlib.c revision 78556
111814Swpaul
211814Swpaul/*-------------------------------------------------------------*/
311814Swpaul/*--- Library top-level functions.                          ---*/
411814Swpaul/*---                                               bzlib.c ---*/
511814Swpaul/*-------------------------------------------------------------*/
611814Swpaul
711814Swpaul/*--
811814Swpaul  This file is a part of bzip2 and/or libbzip2, a program and
911814Swpaul  library for lossless, block-sorting data compression.
1011814Swpaul
1111814Swpaul  Copyright (C) 1996-2000 Julian R Seward.  All rights reserved.
1211814Swpaul
1311814Swpaul  Redistribution and use in source and binary forms, with or without
1411814Swpaul  modification, are permitted provided that the following conditions
1511814Swpaul  are met:
1611814Swpaul
1711814Swpaul  1. Redistributions of source code must retain the above copyright
1811814Swpaul     notice, this list of conditions and the following disclaimer.
1911814Swpaul
2011814Swpaul  2. The origin of this software must not be misrepresented; you must
2111814Swpaul     not claim that you wrote the original software.  If you use this
2211814Swpaul     software in a product, an acknowledgment in the product
2311814Swpaul     documentation would be appreciated but is not required.
2411814Swpaul
2511814Swpaul  3. Altered source versions must be plainly marked as such, and must
2611814Swpaul     not be misrepresented as being the original software.
2711814Swpaul
2811814Swpaul  4. The name of the author may not be used to endorse or promote
2911814Swpaul     products derived from this software without specific prior written
3011814Swpaul     permission.
3111814Swpaul
3211814Swpaul  THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
3311814Swpaul  OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
3411814Swpaul  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
3511814Swpaul  ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
3611814Swpaul  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
3711814Swpaul  DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
3815754Swpaul  GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
3911814Swpaul  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
4011814Swpaul  WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
4111814Swpaul  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
4211814Swpaul  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
4311814Swpaul
4411814Swpaul  Julian Seward, Cambridge, UK.
4511814Swpaul  jseward@acm.org
4615754Swpaul  bzip2/libbzip2 version 1.0 of 21 March 2000
4715754Swpaul
4815754Swpaul  This program is based on (at least) the work of:
4915754Swpaul     Mike Burrows
5011814Swpaul     David Wheeler
5111814Swpaul     Peter Fenwick
5211814Swpaul     Alistair Moffat
5311814Swpaul     Radford Neal
5411814Swpaul     Ian H. Witten
5511814Swpaul     Robert Sedgewick
5611814Swpaul     Jon L. Bentley
5711814Swpaul
5811814Swpaul  For more information on these sources, see the manual.
5911814Swpaul--*/
6011814Swpaul
6111814Swpaul/*--
6211814Swpaul   CHANGES
6311814Swpaul   ~~~~~~~
6411814Swpaul   0.9.0 -- original version.
6511814Swpaul
6611814Swpaul   0.9.0a/b -- no changes in this file.
6711814Swpaul
6811814Swpaul   0.9.0c
6911814Swpaul      * made zero-length BZ_FLUSH work correctly in bzCompress().
7011814Swpaul      * fixed bzWrite/bzRead to ignore zero-length requests.
7111814Swpaul      * fixed bzread to correctly handle read requests after EOF.
7211814Swpaul      * wrong parameter order in call to bzDecompressInit in
7311814Swpaul        bzBuffToBuffDecompress.  Fixed.
7411814Swpaul--*/
7511814Swpaul
7611814Swpaul#include "bzlib_private.h"
7711814Swpaul
7815754Swpaul
7915754Swpaul/*---------------------------------------------------*/
8011814Swpaul/*--- Compression stuff                           ---*/
8111814Swpaul/*---------------------------------------------------*/
8211814Swpaul
8311814Swpaul
8411814Swpaul/*---------------------------------------------------*/
8511814Swpaul#ifndef BZ_NO_STDIO
8615754Swpaulvoid BZ2_bz__AssertH__fail ( int errcode )
8711814Swpaul{
8815754Swpaul   fprintf(stderr,
8911814Swpaul      "\n\nbzip2/libbzip2: internal error number %d.\n"
9011814Swpaul      "This is a bug in bzip2/libbzip2, %s.\n"
9111814Swpaul      "Please report it to me at: jseward@acm.org.  If this happened\n"
9211814Swpaul      "when you were using some program which uses libbzip2 as a\n"
9311814Swpaul      "component, you should also report this bug to the author(s)\n"
9411814Swpaul      "of that program.  Please make an effort to report this bug;\n"
9511814Swpaul      "timely and accurate bug reports eventually lead to higher\n"
9615754Swpaul      "quality software.  Thanks.  Julian Seward, 21 March 2000.\n\n",
9715754Swpaul      errcode,
9815754Swpaul      BZ2_bzlibVersion()
9915754Swpaul   );
10011814Swpaul   exit(3);
10111814Swpaul}
10211814Swpaul#endif
10315754Swpaul
10415754Swpaul
10515754Swpaul/*---------------------------------------------------*/
10615754Swpaulstatic
10711814Swpaulint bz_config_ok ( void )
10811814Swpaul{
10911814Swpaul   if (sizeof(int)   != 4) return 0;
11011814Swpaul   if (sizeof(short) != 2) return 0;
11111814Swpaul   if (sizeof(char)  != 1) return 0;
11211814Swpaul   return 1;
11311814Swpaul}
11411814Swpaul
11511814Swpaul
11611814Swpaul/*---------------------------------------------------*/
11711814Swpaulstatic
11815754Swpaulvoid* default_bzalloc ( void* opaque, Int32 items, Int32 size )
11915754Swpaul{
12015754Swpaul   void* v = malloc ( items * size );
12111814Swpaul   return v;
12211814Swpaul}
12311814Swpaul
12411814Swpaulstatic
12511814Swpaulvoid default_bzfree ( void* opaque, void* addr )
12611814Swpaul{
12711814Swpaul   if (addr != NULL) free ( addr );
12811814Swpaul}
12911814Swpaul
13011814Swpaul
13111814Swpaul/*---------------------------------------------------*/
13211814Swpaulstatic
13311814Swpaulvoid prepare_new_block ( EState* s )
13411814Swpaul{
13511814Swpaul   Int32 i;
13611814Swpaul   s->nblock = 0;
13711814Swpaul   s->numZ = 0;
13811814Swpaul   s->state_out_pos = 0;
13911814Swpaul   BZ_INITIALISE_CRC ( s->blockCRC );
14011814Swpaul   for (i = 0; i < 256; i++) s->inUse[i] = False;
14111814Swpaul   s->blockNo++;
14211814Swpaul}
14311814Swpaul
14411814Swpaul
14511814Swpaul/*---------------------------------------------------*/
14611814Swpaulstatic
14711814Swpaulvoid init_RL ( EState* s )
14811814Swpaul{
14911814Swpaul   s->state_in_ch  = 256;
15011814Swpaul   s->state_in_len = 0;
15111814Swpaul}
15211814Swpaul
15311814Swpaul
15411814Swpaulstatic
15511814SwpaulBool isempty_RL ( EState* s )
15611814Swpaul{
15711814Swpaul   if (s->state_in_ch < 256 && s->state_in_len > 0)
15811814Swpaul      return False; else
15911814Swpaul      return True;
16011814Swpaul}
16111814Swpaul
16211814Swpaul
16311814Swpaul/*---------------------------------------------------*/
16411814Swpaulint BZ_API(BZ2_bzCompressInit)
16511814Swpaul                    ( bz_stream* strm,
16611814Swpaul                     int        blockSize100k,
16711814Swpaul                     int        verbosity,
16811814Swpaul                     int        workFactor )
16911814Swpaul{
17011814Swpaul   Int32   n;
17111814Swpaul   EState* s;
17211814Swpaul
17311814Swpaul   if (!bz_config_ok()) return BZ_CONFIG_ERROR;
17411814Swpaul
17511814Swpaul   if (strm == NULL ||
17611814Swpaul       blockSize100k < 1 || blockSize100k > 9 ||
17711814Swpaul       workFactor < 0 || workFactor > 250)
17811814Swpaul     return BZ_PARAM_ERROR;
17911814Swpaul
18011814Swpaul   if (workFactor == 0) workFactor = 30;
18111814Swpaul   if (strm->bzalloc == NULL) strm->bzalloc = default_bzalloc;
18211814Swpaul   if (strm->bzfree == NULL) strm->bzfree = default_bzfree;
183
184   s = BZALLOC( sizeof(EState) );
185   if (s == NULL) return BZ_MEM_ERROR;
186   s->strm = strm;
187
188   s->arr1 = NULL;
189   s->arr2 = NULL;
190   s->ftab = NULL;
191
192   n       = 100000 * blockSize100k;
193   s->arr1 = BZALLOC( n                  * sizeof(UInt32) );
194   s->arr2 = BZALLOC( (n+BZ_N_OVERSHOOT) * sizeof(UInt32) );
195   s->ftab = BZALLOC( 65537              * sizeof(UInt32) );
196
197   if (s->arr1 == NULL || s->arr2 == NULL || s->ftab == NULL) {
198      if (s->arr1 != NULL) BZFREE(s->arr1);
199      if (s->arr2 != NULL) BZFREE(s->arr2);
200      if (s->ftab != NULL) BZFREE(s->ftab);
201      if (s       != NULL) BZFREE(s);
202      return BZ_MEM_ERROR;
203   }
204
205   s->blockNo           = 0;
206   s->state             = BZ_S_INPUT;
207   s->mode              = BZ_M_RUNNING;
208   s->combinedCRC       = 0;
209   s->blockSize100k     = blockSize100k;
210   s->nblockMAX         = 100000 * blockSize100k - 19;
211   s->verbosity         = verbosity;
212   s->workFactor        = workFactor;
213
214   s->block             = (UChar*)s->arr2;
215   s->mtfv              = (UInt16*)s->arr1;
216   s->zbits             = NULL;
217   s->ptr               = (UInt32*)s->arr1;
218
219   strm->state          = s;
220   strm->total_in_lo32  = 0;
221   strm->total_in_hi32  = 0;
222   strm->total_out_lo32 = 0;
223   strm->total_out_hi32 = 0;
224   init_RL ( s );
225   prepare_new_block ( s );
226   return BZ_OK;
227}
228
229
230/*---------------------------------------------------*/
231static
232void add_pair_to_block ( EState* s )
233{
234   Int32 i;
235   UChar ch = (UChar)(s->state_in_ch);
236   for (i = 0; i < s->state_in_len; i++) {
237      BZ_UPDATE_CRC( s->blockCRC, ch );
238   }
239   s->inUse[s->state_in_ch] = True;
240   switch (s->state_in_len) {
241      case 1:
242         s->block[s->nblock] = (UChar)ch; s->nblock++;
243         break;
244      case 2:
245         s->block[s->nblock] = (UChar)ch; s->nblock++;
246         s->block[s->nblock] = (UChar)ch; s->nblock++;
247         break;
248      case 3:
249         s->block[s->nblock] = (UChar)ch; s->nblock++;
250         s->block[s->nblock] = (UChar)ch; s->nblock++;
251         s->block[s->nblock] = (UChar)ch; s->nblock++;
252         break;
253      default:
254         s->inUse[s->state_in_len-4] = True;
255         s->block[s->nblock] = (UChar)ch; s->nblock++;
256         s->block[s->nblock] = (UChar)ch; s->nblock++;
257         s->block[s->nblock] = (UChar)ch; s->nblock++;
258         s->block[s->nblock] = (UChar)ch; s->nblock++;
259         s->block[s->nblock] = ((UChar)(s->state_in_len-4));
260         s->nblock++;
261         break;
262   }
263}
264
265
266/*---------------------------------------------------*/
267static
268void flush_RL ( EState* s )
269{
270   if (s->state_in_ch < 256) add_pair_to_block ( s );
271   init_RL ( s );
272}
273
274
275/*---------------------------------------------------*/
276#define ADD_CHAR_TO_BLOCK(zs,zchh0)               \
277{                                                 \
278   UInt32 zchh = (UInt32)(zchh0);                 \
279   /*-- fast track the common case --*/           \
280   if (zchh != zs->state_in_ch &&                 \
281       zs->state_in_len == 1) {                   \
282      UChar ch = (UChar)(zs->state_in_ch);        \
283      BZ_UPDATE_CRC( zs->blockCRC, ch );          \
284      zs->inUse[zs->state_in_ch] = True;          \
285      zs->block[zs->nblock] = (UChar)ch;          \
286      zs->nblock++;                               \
287      zs->state_in_ch = zchh;                     \
288   }                                              \
289   else                                           \
290   /*-- general, uncommon cases --*/              \
291   if (zchh != zs->state_in_ch ||                 \
292      zs->state_in_len == 255) {                  \
293      if (zs->state_in_ch < 256)                  \
294         add_pair_to_block ( zs );                \
295      zs->state_in_ch = zchh;                     \
296      zs->state_in_len = 1;                       \
297   } else {                                       \
298      zs->state_in_len++;                         \
299   }                                              \
300}
301
302
303/*---------------------------------------------------*/
304static
305Bool copy_input_until_stop ( EState* s )
306{
307   Bool progress_in = False;
308
309   if (s->mode == BZ_M_RUNNING) {
310
311      /*-- fast track the common case --*/
312      while (True) {
313         /*-- block full? --*/
314         if (s->nblock >= s->nblockMAX) break;
315         /*-- no input? --*/
316         if (s->strm->avail_in == 0) break;
317         progress_in = True;
318         ADD_CHAR_TO_BLOCK ( s, (UInt32)(*((UChar*)(s->strm->next_in))) );
319         s->strm->next_in++;
320         s->strm->avail_in--;
321         s->strm->total_in_lo32++;
322         if (s->strm->total_in_lo32 == 0) s->strm->total_in_hi32++;
323      }
324
325   } else {
326
327      /*-- general, uncommon case --*/
328      while (True) {
329         /*-- block full? --*/
330         if (s->nblock >= s->nblockMAX) break;
331         /*-- no input? --*/
332         if (s->strm->avail_in == 0) break;
333         /*-- flush/finish end? --*/
334         if (s->avail_in_expect == 0) break;
335         progress_in = True;
336         ADD_CHAR_TO_BLOCK ( s, (UInt32)(*((UChar*)(s->strm->next_in))) );
337         s->strm->next_in++;
338         s->strm->avail_in--;
339         s->strm->total_in_lo32++;
340         if (s->strm->total_in_lo32 == 0) s->strm->total_in_hi32++;
341         s->avail_in_expect--;
342      }
343   }
344   return progress_in;
345}
346
347
348/*---------------------------------------------------*/
349static
350Bool copy_output_until_stop ( EState* s )
351{
352   Bool progress_out = False;
353
354   while (True) {
355
356      /*-- no output space? --*/
357      if (s->strm->avail_out == 0) break;
358
359      /*-- block done? --*/
360      if (s->state_out_pos >= s->numZ) break;
361
362      progress_out = True;
363      *(s->strm->next_out) = s->zbits[s->state_out_pos];
364      s->state_out_pos++;
365      s->strm->avail_out--;
366      s->strm->next_out++;
367      s->strm->total_out_lo32++;
368      if (s->strm->total_out_lo32 == 0) s->strm->total_out_hi32++;
369   }
370
371   return progress_out;
372}
373
374
375/*---------------------------------------------------*/
376static
377Bool handle_compress ( bz_stream* strm )
378{
379   Bool progress_in  = False;
380   Bool progress_out = False;
381   EState* s = strm->state;
382
383   while (True) {
384
385      if (s->state == BZ_S_OUTPUT) {
386         progress_out |= copy_output_until_stop ( s );
387         if (s->state_out_pos < s->numZ) break;
388         if (s->mode == BZ_M_FINISHING &&
389             s->avail_in_expect == 0 &&
390             isempty_RL(s)) break;
391         prepare_new_block ( s );
392         s->state = BZ_S_INPUT;
393         if (s->mode == BZ_M_FLUSHING &&
394             s->avail_in_expect == 0 &&
395             isempty_RL(s)) break;
396      }
397
398      if (s->state == BZ_S_INPUT) {
399         progress_in |= copy_input_until_stop ( s );
400         if (s->mode != BZ_M_RUNNING && s->avail_in_expect == 0) {
401            flush_RL ( s );
402            BZ2_compressBlock ( s, (Bool)(s->mode == BZ_M_FINISHING) );
403            s->state = BZ_S_OUTPUT;
404         }
405         else
406         if (s->nblock >= s->nblockMAX) {
407            BZ2_compressBlock ( s, False );
408            s->state = BZ_S_OUTPUT;
409         }
410         else
411         if (s->strm->avail_in == 0) {
412            break;
413         }
414      }
415
416   }
417
418   return progress_in || progress_out;
419}
420
421
422/*---------------------------------------------------*/
423int BZ_API(BZ2_bzCompress) ( bz_stream *strm, int action )
424{
425   Bool progress;
426   EState* s;
427   if (strm == NULL) return BZ_PARAM_ERROR;
428   s = strm->state;
429   if (s == NULL) return BZ_PARAM_ERROR;
430   if (s->strm != strm) return BZ_PARAM_ERROR;
431
432   preswitch:
433   switch (s->mode) {
434
435      case BZ_M_IDLE:
436         return BZ_SEQUENCE_ERROR;
437
438      case BZ_M_RUNNING:
439         if (action == BZ_RUN) {
440            progress = handle_compress ( strm );
441            return progress ? BZ_RUN_OK : BZ_PARAM_ERROR;
442         }
443         else
444	 if (action == BZ_FLUSH) {
445            s->avail_in_expect = strm->avail_in;
446            s->mode = BZ_M_FLUSHING;
447            goto preswitch;
448         }
449         else
450         if (action == BZ_FINISH) {
451            s->avail_in_expect = strm->avail_in;
452            s->mode = BZ_M_FINISHING;
453            goto preswitch;
454         }
455         else
456            return BZ_PARAM_ERROR;
457
458      case BZ_M_FLUSHING:
459         if (action != BZ_FLUSH) return BZ_SEQUENCE_ERROR;
460         if (s->avail_in_expect != s->strm->avail_in)
461            return BZ_SEQUENCE_ERROR;
462         progress = handle_compress ( strm );
463         if (s->avail_in_expect > 0 || !isempty_RL(s) ||
464             s->state_out_pos < s->numZ) return BZ_FLUSH_OK;
465         s->mode = BZ_M_RUNNING;
466         return BZ_RUN_OK;
467
468      case BZ_M_FINISHING:
469         if (action != BZ_FINISH) return BZ_SEQUENCE_ERROR;
470         if (s->avail_in_expect != s->strm->avail_in)
471            return BZ_SEQUENCE_ERROR;
472         progress = handle_compress ( strm );
473         if (!progress) return BZ_SEQUENCE_ERROR;
474         if (s->avail_in_expect > 0 || !isempty_RL(s) ||
475             s->state_out_pos < s->numZ) return BZ_FINISH_OK;
476         s->mode = BZ_M_IDLE;
477         return BZ_STREAM_END;
478   }
479   return BZ_OK; /*--not reached--*/
480}
481
482
483/*---------------------------------------------------*/
484int BZ_API(BZ2_bzCompressEnd)  ( bz_stream *strm )
485{
486   EState* s;
487   if (strm == NULL) return BZ_PARAM_ERROR;
488   s = strm->state;
489   if (s == NULL) return BZ_PARAM_ERROR;
490   if (s->strm != strm) return BZ_PARAM_ERROR;
491
492   if (s->arr1 != NULL) BZFREE(s->arr1);
493   if (s->arr2 != NULL) BZFREE(s->arr2);
494   if (s->ftab != NULL) BZFREE(s->ftab);
495   BZFREE(strm->state);
496
497   strm->state = NULL;
498
499   return BZ_OK;
500}
501
502
503/*---------------------------------------------------*/
504/*--- Decompression stuff                         ---*/
505/*---------------------------------------------------*/
506
507/*---------------------------------------------------*/
508int BZ_API(BZ2_bzDecompressInit)
509                     ( bz_stream* strm,
510                       int        verbosity,
511                       int        small )
512{
513   DState* s;
514
515   if (!bz_config_ok()) return BZ_CONFIG_ERROR;
516
517   if (strm == NULL) return BZ_PARAM_ERROR;
518   if (small != 0 && small != 1) return BZ_PARAM_ERROR;
519   if (verbosity < 0 || verbosity > 4) return BZ_PARAM_ERROR;
520
521   if (strm->bzalloc == NULL) strm->bzalloc = default_bzalloc;
522   if (strm->bzfree == NULL) strm->bzfree = default_bzfree;
523
524   s = BZALLOC( sizeof(DState) );
525   if (s == NULL) return BZ_MEM_ERROR;
526   s->strm                  = strm;
527   strm->state              = s;
528   s->state                 = BZ_X_MAGIC_1;
529   s->bsLive                = 0;
530   s->bsBuff                = 0;
531   s->calculatedCombinedCRC = 0;
532   strm->total_in_lo32      = 0;
533   strm->total_in_hi32      = 0;
534   strm->total_out_lo32     = 0;
535   strm->total_out_hi32     = 0;
536   s->smallDecompress       = (Bool)small;
537   s->ll4                   = NULL;
538   s->ll16                  = NULL;
539   s->tt                    = NULL;
540   s->currBlockNo           = 0;
541   s->verbosity             = verbosity;
542
543   return BZ_OK;
544}
545
546
547/*---------------------------------------------------*/
548static
549void unRLE_obuf_to_output_FAST ( DState* s )
550{
551   UChar k1;
552
553   if (s->blockRandomised) {
554
555      while (True) {
556         /* try to finish existing run */
557         while (True) {
558            if (s->strm->avail_out == 0) return;
559            if (s->state_out_len == 0) break;
560            *( (UChar*)(s->strm->next_out) ) = s->state_out_ch;
561            BZ_UPDATE_CRC ( s->calculatedBlockCRC, s->state_out_ch );
562            s->state_out_len--;
563            s->strm->next_out++;
564            s->strm->avail_out--;
565            s->strm->total_out_lo32++;
566            if (s->strm->total_out_lo32 == 0) s->strm->total_out_hi32++;
567         }
568
569         /* can a new run be started? */
570         if (s->nblock_used == s->save_nblock+1) return;
571
572
573         s->state_out_len = 1;
574         s->state_out_ch = s->k0;
575         BZ_GET_FAST(k1); BZ_RAND_UPD_MASK;
576         k1 ^= BZ_RAND_MASK; s->nblock_used++;
577         if (s->nblock_used == s->save_nblock+1) continue;
578         if (k1 != s->k0) { s->k0 = k1; continue; };
579
580         s->state_out_len = 2;
581         BZ_GET_FAST(k1); BZ_RAND_UPD_MASK;
582         k1 ^= BZ_RAND_MASK; s->nblock_used++;
583         if (s->nblock_used == s->save_nblock+1) continue;
584         if (k1 != s->k0) { s->k0 = k1; continue; };
585
586         s->state_out_len = 3;
587         BZ_GET_FAST(k1); BZ_RAND_UPD_MASK;
588         k1 ^= BZ_RAND_MASK; s->nblock_used++;
589         if (s->nblock_used == s->save_nblock+1) continue;
590         if (k1 != s->k0) { s->k0 = k1; continue; };
591
592         BZ_GET_FAST(k1); BZ_RAND_UPD_MASK;
593         k1 ^= BZ_RAND_MASK; s->nblock_used++;
594         s->state_out_len = ((Int32)k1) + 4;
595         BZ_GET_FAST(s->k0); BZ_RAND_UPD_MASK;
596         s->k0 ^= BZ_RAND_MASK; s->nblock_used++;
597      }
598
599   } else {
600
601      /* restore */
602      UInt32        c_calculatedBlockCRC = s->calculatedBlockCRC;
603      UChar         c_state_out_ch       = s->state_out_ch;
604      Int32         c_state_out_len      = s->state_out_len;
605      Int32         c_nblock_used        = s->nblock_used;
606      Int32         c_k0                 = s->k0;
607      UInt32*       c_tt                 = s->tt;
608      UInt32        c_tPos               = s->tPos;
609      char*         cs_next_out          = s->strm->next_out;
610      unsigned int  cs_avail_out         = s->strm->avail_out;
611      /* end restore */
612
613      UInt32       avail_out_INIT = cs_avail_out;
614      Int32        s_save_nblockPP = s->save_nblock+1;
615      unsigned int total_out_lo32_old;
616
617      while (True) {
618
619         /* try to finish existing run */
620         if (c_state_out_len > 0) {
621            while (True) {
622               if (cs_avail_out == 0) goto return_notr;
623               if (c_state_out_len == 1) break;
624               *( (UChar*)(cs_next_out) ) = c_state_out_ch;
625               BZ_UPDATE_CRC ( c_calculatedBlockCRC, c_state_out_ch );
626               c_state_out_len--;
627               cs_next_out++;
628               cs_avail_out--;
629            }
630            s_state_out_len_eq_one:
631            {
632               if (cs_avail_out == 0) {
633                  c_state_out_len = 1; goto return_notr;
634               };
635               *( (UChar*)(cs_next_out) ) = c_state_out_ch;
636               BZ_UPDATE_CRC ( c_calculatedBlockCRC, c_state_out_ch );
637               cs_next_out++;
638               cs_avail_out--;
639            }
640         }
641         /* can a new run be started? */
642         if (c_nblock_used == s_save_nblockPP) {
643            c_state_out_len = 0; goto return_notr;
644         };
645         c_state_out_ch = c_k0;
646         BZ_GET_FAST_C(k1); c_nblock_used++;
647         if (k1 != c_k0) {
648            c_k0 = k1; goto s_state_out_len_eq_one;
649         };
650         if (c_nblock_used == s_save_nblockPP)
651            goto s_state_out_len_eq_one;
652
653         c_state_out_len = 2;
654         BZ_GET_FAST_C(k1); c_nblock_used++;
655         if (c_nblock_used == s_save_nblockPP) continue;
656         if (k1 != c_k0) { c_k0 = k1; continue; };
657
658         c_state_out_len = 3;
659         BZ_GET_FAST_C(k1); c_nblock_used++;
660         if (c_nblock_used == s_save_nblockPP) continue;
661         if (k1 != c_k0) { c_k0 = k1; continue; };
662
663         BZ_GET_FAST_C(k1); c_nblock_used++;
664         c_state_out_len = ((Int32)k1) + 4;
665         BZ_GET_FAST_C(c_k0); c_nblock_used++;
666      }
667
668      return_notr:
669      total_out_lo32_old = s->strm->total_out_lo32;
670      s->strm->total_out_lo32 += (avail_out_INIT - cs_avail_out);
671      if (s->strm->total_out_lo32 < total_out_lo32_old)
672         s->strm->total_out_hi32++;
673
674      /* save */
675      s->calculatedBlockCRC = c_calculatedBlockCRC;
676      s->state_out_ch       = c_state_out_ch;
677      s->state_out_len      = c_state_out_len;
678      s->nblock_used        = c_nblock_used;
679      s->k0                 = c_k0;
680      s->tt                 = c_tt;
681      s->tPos               = c_tPos;
682      s->strm->next_out     = cs_next_out;
683      s->strm->avail_out    = cs_avail_out;
684      /* end save */
685   }
686}
687
688
689
690/*---------------------------------------------------*/
691__inline__ Int32 BZ2_indexIntoF ( Int32 indx, Int32 *cftab )
692{
693   Int32 nb, na, mid;
694   nb = 0;
695   na = 256;
696   do {
697      mid = (nb + na) >> 1;
698      if (indx >= cftab[mid]) nb = mid; else na = mid;
699   }
700   while (na - nb != 1);
701   return nb;
702}
703
704
705/*---------------------------------------------------*/
706static
707void unRLE_obuf_to_output_SMALL ( DState* s )
708{
709   UChar k1;
710
711   if (s->blockRandomised) {
712
713      while (True) {
714         /* try to finish existing run */
715         while (True) {
716            if (s->strm->avail_out == 0) return;
717            if (s->state_out_len == 0) break;
718            *( (UChar*)(s->strm->next_out) ) = s->state_out_ch;
719            BZ_UPDATE_CRC ( s->calculatedBlockCRC, s->state_out_ch );
720            s->state_out_len--;
721            s->strm->next_out++;
722            s->strm->avail_out--;
723            s->strm->total_out_lo32++;
724            if (s->strm->total_out_lo32 == 0) s->strm->total_out_hi32++;
725         }
726
727         /* can a new run be started? */
728         if (s->nblock_used == s->save_nblock+1) return;
729
730
731         s->state_out_len = 1;
732         s->state_out_ch = s->k0;
733         BZ_GET_SMALL(k1); BZ_RAND_UPD_MASK;
734         k1 ^= BZ_RAND_MASK; s->nblock_used++;
735         if (s->nblock_used == s->save_nblock+1) continue;
736         if (k1 != s->k0) { s->k0 = k1; continue; };
737
738         s->state_out_len = 2;
739         BZ_GET_SMALL(k1); BZ_RAND_UPD_MASK;
740         k1 ^= BZ_RAND_MASK; s->nblock_used++;
741         if (s->nblock_used == s->save_nblock+1) continue;
742         if (k1 != s->k0) { s->k0 = k1; continue; };
743
744         s->state_out_len = 3;
745         BZ_GET_SMALL(k1); BZ_RAND_UPD_MASK;
746         k1 ^= BZ_RAND_MASK; s->nblock_used++;
747         if (s->nblock_used == s->save_nblock+1) continue;
748         if (k1 != s->k0) { s->k0 = k1; continue; };
749
750         BZ_GET_SMALL(k1); BZ_RAND_UPD_MASK;
751         k1 ^= BZ_RAND_MASK; s->nblock_used++;
752         s->state_out_len = ((Int32)k1) + 4;
753         BZ_GET_SMALL(s->k0); BZ_RAND_UPD_MASK;
754         s->k0 ^= BZ_RAND_MASK; s->nblock_used++;
755      }
756
757   } else {
758
759      while (True) {
760         /* try to finish existing run */
761         while (True) {
762            if (s->strm->avail_out == 0) return;
763            if (s->state_out_len == 0) break;
764            *( (UChar*)(s->strm->next_out) ) = s->state_out_ch;
765            BZ_UPDATE_CRC ( s->calculatedBlockCRC, s->state_out_ch );
766            s->state_out_len--;
767            s->strm->next_out++;
768            s->strm->avail_out--;
769            s->strm->total_out_lo32++;
770            if (s->strm->total_out_lo32 == 0) s->strm->total_out_hi32++;
771         }
772
773         /* can a new run be started? */
774         if (s->nblock_used == s->save_nblock+1) return;
775
776         s->state_out_len = 1;
777         s->state_out_ch = s->k0;
778         BZ_GET_SMALL(k1); s->nblock_used++;
779         if (s->nblock_used == s->save_nblock+1) continue;
780         if (k1 != s->k0) { s->k0 = k1; continue; };
781
782         s->state_out_len = 2;
783         BZ_GET_SMALL(k1); s->nblock_used++;
784         if (s->nblock_used == s->save_nblock+1) continue;
785         if (k1 != s->k0) { s->k0 = k1; continue; };
786
787         s->state_out_len = 3;
788         BZ_GET_SMALL(k1); s->nblock_used++;
789         if (s->nblock_used == s->save_nblock+1) continue;
790         if (k1 != s->k0) { s->k0 = k1; continue; };
791
792         BZ_GET_SMALL(k1); s->nblock_used++;
793         s->state_out_len = ((Int32)k1) + 4;
794         BZ_GET_SMALL(s->k0); s->nblock_used++;
795      }
796
797   }
798}
799
800
801/*---------------------------------------------------*/
802int BZ_API(BZ2_bzDecompress) ( bz_stream *strm )
803{
804   DState* s;
805   if (strm == NULL) return BZ_PARAM_ERROR;
806   s = strm->state;
807   if (s == NULL) return BZ_PARAM_ERROR;
808   if (s->strm != strm) return BZ_PARAM_ERROR;
809
810   while (True) {
811      if (s->state == BZ_X_IDLE) return BZ_SEQUENCE_ERROR;
812      if (s->state == BZ_X_OUTPUT) {
813         if (s->smallDecompress)
814            unRLE_obuf_to_output_SMALL ( s ); else
815            unRLE_obuf_to_output_FAST  ( s );
816         if (s->nblock_used == s->save_nblock+1 && s->state_out_len == 0) {
817            BZ_FINALISE_CRC ( s->calculatedBlockCRC );
818            if (s->verbosity >= 3)
819               VPrintf2 ( " {0x%x, 0x%x}", s->storedBlockCRC,
820                          s->calculatedBlockCRC );
821            if (s->verbosity >= 2) VPrintf0 ( "]" );
822            if (s->calculatedBlockCRC != s->storedBlockCRC)
823               return BZ_DATA_ERROR;
824            s->calculatedCombinedCRC
825               = (s->calculatedCombinedCRC << 1) |
826                    (s->calculatedCombinedCRC >> 31);
827            s->calculatedCombinedCRC ^= s->calculatedBlockCRC;
828            s->state = BZ_X_BLKHDR_1;
829         } else {
830            return BZ_OK;
831         }
832      }
833      if (s->state >= BZ_X_MAGIC_1) {
834         Int32 r = BZ2_decompress ( s );
835         if (r == BZ_STREAM_END) {
836            if (s->verbosity >= 3)
837               VPrintf2 ( "\n    combined CRCs: stored = 0x%x, computed = 0x%x",
838                          s->storedCombinedCRC, s->calculatedCombinedCRC );
839            if (s->calculatedCombinedCRC != s->storedCombinedCRC)
840               return BZ_DATA_ERROR;
841            return r;
842         }
843         if (s->state != BZ_X_OUTPUT) return r;
844      }
845   }
846
847   AssertH ( 0, 6001 );
848
849   return 0;  /*NOTREACHED*/
850}
851
852
853/*---------------------------------------------------*/
854int BZ_API(BZ2_bzDecompressEnd)  ( bz_stream *strm )
855{
856   DState* s;
857   if (strm == NULL) return BZ_PARAM_ERROR;
858   s = strm->state;
859   if (s == NULL) return BZ_PARAM_ERROR;
860   if (s->strm != strm) return BZ_PARAM_ERROR;
861
862   if (s->tt   != NULL) BZFREE(s->tt);
863   if (s->ll16 != NULL) BZFREE(s->ll16);
864   if (s->ll4  != NULL) BZFREE(s->ll4);
865
866   BZFREE(strm->state);
867   strm->state = NULL;
868
869   return BZ_OK;
870}
871
872
873#ifndef BZ_NO_STDIO
874/*---------------------------------------------------*/
875/*--- File I/O stuff                              ---*/
876/*---------------------------------------------------*/
877
878#define BZ_SETERR(eee)                    \
879{                                         \
880   if (bzerror != NULL) *bzerror = eee;   \
881   if (bzf != NULL) bzf->lastErr = eee;   \
882}
883
884typedef
885   struct {
886      FILE*     handle;
887      Char      buf[BZ_MAX_UNUSED];
888      Int32     bufN;
889      Bool      writing;
890      bz_stream strm;
891      Int32     lastErr;
892      Bool      initialisedOk;
893   }
894   bzFile;
895
896
897/*---------------------------------------------*/
898static Bool myfeof ( FILE* f )
899{
900   Int32 c = fgetc ( f );
901   if (c == EOF) return True;
902   ungetc ( c, f );
903   return False;
904}
905
906
907/*---------------------------------------------------*/
908BZFILE* BZ_API(BZ2_bzWriteOpen)
909                    ( int*  bzerror,
910                      FILE* f,
911                      int   blockSize100k,
912                      int   verbosity,
913                      int   workFactor )
914{
915   Int32   ret;
916   bzFile* bzf = NULL;
917
918   BZ_SETERR(BZ_OK);
919
920   if (f == NULL ||
921       (blockSize100k < 1 || blockSize100k > 9) ||
922       (workFactor < 0 || workFactor > 250) ||
923       (verbosity < 0 || verbosity > 4))
924      { BZ_SETERR(BZ_PARAM_ERROR); return NULL; };
925
926   if (ferror(f))
927      { BZ_SETERR(BZ_IO_ERROR); return NULL; };
928
929   bzf = malloc ( sizeof(bzFile) );
930   if (bzf == NULL)
931      { BZ_SETERR(BZ_MEM_ERROR); return NULL; };
932
933   BZ_SETERR(BZ_OK);
934   bzf->initialisedOk = False;
935   bzf->bufN          = 0;
936   bzf->handle        = f;
937   bzf->writing       = True;
938   bzf->strm.bzalloc  = NULL;
939   bzf->strm.bzfree   = NULL;
940   bzf->strm.opaque   = NULL;
941
942   if (workFactor == 0) workFactor = 30;
943   ret = BZ2_bzCompressInit ( &(bzf->strm), blockSize100k,
944                              verbosity, workFactor );
945   if (ret != BZ_OK)
946      { BZ_SETERR(ret); free(bzf); return NULL; };
947
948   bzf->strm.avail_in = 0;
949   bzf->initialisedOk = True;
950   return bzf;
951}
952
953
954
955/*---------------------------------------------------*/
956void BZ_API(BZ2_bzWrite)
957             ( int*    bzerror,
958               BZFILE* b,
959               void*   buf,
960               int     len )
961{
962   Int32 n, n2, ret;
963   bzFile* bzf = (bzFile*)b;
964
965   BZ_SETERR(BZ_OK);
966   if (bzf == NULL || buf == NULL || len < 0)
967      { BZ_SETERR(BZ_PARAM_ERROR); return; };
968   if (!(bzf->writing))
969      { BZ_SETERR(BZ_SEQUENCE_ERROR); return; };
970   if (ferror(bzf->handle))
971      { BZ_SETERR(BZ_IO_ERROR); return; };
972
973   if (len == 0)
974      { BZ_SETERR(BZ_OK); return; };
975
976   bzf->strm.avail_in = len;
977   bzf->strm.next_in  = buf;
978
979   while (True) {
980      bzf->strm.avail_out = BZ_MAX_UNUSED;
981      bzf->strm.next_out = bzf->buf;
982      ret = BZ2_bzCompress ( &(bzf->strm), BZ_RUN );
983      if (ret != BZ_RUN_OK)
984         { BZ_SETERR(ret); return; };
985
986      if (bzf->strm.avail_out < BZ_MAX_UNUSED) {
987         n = BZ_MAX_UNUSED - bzf->strm.avail_out;
988         n2 = fwrite ( (void*)(bzf->buf), sizeof(UChar),
989                       n, bzf->handle );
990         if (n != n2 || ferror(bzf->handle))
991            { BZ_SETERR(BZ_IO_ERROR); return; };
992      }
993
994      if (bzf->strm.avail_in == 0)
995         { BZ_SETERR(BZ_OK); return; };
996   }
997}
998
999
1000/*---------------------------------------------------*/
1001void BZ_API(BZ2_bzWriteClose)
1002                  ( int*          bzerror,
1003                    BZFILE*       b,
1004                    int           abandon,
1005                    unsigned int* nbytes_in,
1006                    unsigned int* nbytes_out )
1007{
1008   BZ2_bzWriteClose64 ( bzerror, b, abandon,
1009                        nbytes_in, NULL, nbytes_out, NULL );
1010}
1011
1012
1013void BZ_API(BZ2_bzWriteClose64)
1014                  ( int*          bzerror,
1015                    BZFILE*       b,
1016                    int           abandon,
1017                    unsigned int* nbytes_in_lo32,
1018                    unsigned int* nbytes_in_hi32,
1019                    unsigned int* nbytes_out_lo32,
1020                    unsigned int* nbytes_out_hi32 )
1021{
1022   Int32   n, n2, ret;
1023   bzFile* bzf = (bzFile*)b;
1024
1025   if (bzf == NULL)
1026      { BZ_SETERR(BZ_OK); return; };
1027   if (!(bzf->writing))
1028      { BZ_SETERR(BZ_SEQUENCE_ERROR); return; };
1029   if (ferror(bzf->handle))
1030      { BZ_SETERR(BZ_IO_ERROR); return; };
1031
1032   if (nbytes_in_lo32 != NULL) *nbytes_in_lo32 = 0;
1033   if (nbytes_in_hi32 != NULL) *nbytes_in_hi32 = 0;
1034   if (nbytes_out_lo32 != NULL) *nbytes_out_lo32 = 0;
1035   if (nbytes_out_hi32 != NULL) *nbytes_out_hi32 = 0;
1036
1037   if ((!abandon) && bzf->lastErr == BZ_OK) {
1038      while (True) {
1039         bzf->strm.avail_out = BZ_MAX_UNUSED;
1040         bzf->strm.next_out = bzf->buf;
1041         ret = BZ2_bzCompress ( &(bzf->strm), BZ_FINISH );
1042         if (ret != BZ_FINISH_OK && ret != BZ_STREAM_END)
1043            { BZ_SETERR(ret); return; };
1044
1045         if (bzf->strm.avail_out < BZ_MAX_UNUSED) {
1046            n = BZ_MAX_UNUSED - bzf->strm.avail_out;
1047            n2 = fwrite ( (void*)(bzf->buf), sizeof(UChar),
1048                          n, bzf->handle );
1049            if (n != n2 || ferror(bzf->handle))
1050               { BZ_SETERR(BZ_IO_ERROR); return; };
1051         }
1052
1053         if (ret == BZ_STREAM_END) break;
1054      }
1055   }
1056
1057   if ( !abandon && !ferror ( bzf->handle ) ) {
1058      fflush ( bzf->handle );
1059      if (ferror(bzf->handle))
1060         { BZ_SETERR(BZ_IO_ERROR); return; };
1061   }
1062
1063   if (nbytes_in_lo32 != NULL)
1064      *nbytes_in_lo32 = bzf->strm.total_in_lo32;
1065   if (nbytes_in_hi32 != NULL)
1066      *nbytes_in_hi32 = bzf->strm.total_in_hi32;
1067   if (nbytes_out_lo32 != NULL)
1068      *nbytes_out_lo32 = bzf->strm.total_out_lo32;
1069   if (nbytes_out_hi32 != NULL)
1070      *nbytes_out_hi32 = bzf->strm.total_out_hi32;
1071
1072   BZ_SETERR(BZ_OK);
1073   BZ2_bzCompressEnd ( &(bzf->strm) );
1074   free ( bzf );
1075}
1076
1077
1078/*---------------------------------------------------*/
1079BZFILE* BZ_API(BZ2_bzReadOpen)
1080                   ( int*  bzerror,
1081                     FILE* f,
1082                     int   verbosity,
1083                     int   small,
1084                     void* unused,
1085                     int   nUnused )
1086{
1087   bzFile* bzf = NULL;
1088   int     ret;
1089
1090   BZ_SETERR(BZ_OK);
1091
1092   if (f == NULL ||
1093       (small != 0 && small != 1) ||
1094       (verbosity < 0 || verbosity > 4) ||
1095       (unused == NULL && nUnused != 0) ||
1096       (unused != NULL && (nUnused < 0 || nUnused > BZ_MAX_UNUSED)))
1097      { BZ_SETERR(BZ_PARAM_ERROR); return NULL; };
1098
1099   if (ferror(f))
1100      { BZ_SETERR(BZ_IO_ERROR); return NULL; };
1101
1102   bzf = malloc ( sizeof(bzFile) );
1103   if (bzf == NULL)
1104      { BZ_SETERR(BZ_MEM_ERROR); return NULL; };
1105
1106   BZ_SETERR(BZ_OK);
1107
1108   bzf->initialisedOk = False;
1109   bzf->handle        = f;
1110   bzf->bufN          = 0;
1111   bzf->writing       = False;
1112   bzf->strm.bzalloc  = NULL;
1113   bzf->strm.bzfree   = NULL;
1114   bzf->strm.opaque   = NULL;
1115
1116   while (nUnused > 0) {
1117      bzf->buf[bzf->bufN] = *((UChar*)(unused)); bzf->bufN++;
1118      unused = ((void*)( 1 + ((UChar*)(unused))  ));
1119      nUnused--;
1120   }
1121
1122   ret = BZ2_bzDecompressInit ( &(bzf->strm), verbosity, small );
1123   if (ret != BZ_OK)
1124      { BZ_SETERR(ret); free(bzf); return NULL; };
1125
1126   bzf->strm.avail_in = bzf->bufN;
1127   bzf->strm.next_in  = bzf->buf;
1128
1129   bzf->initialisedOk = True;
1130   return bzf;
1131}
1132
1133
1134/*---------------------------------------------------*/
1135void BZ_API(BZ2_bzReadClose) ( int *bzerror, BZFILE *b )
1136{
1137   bzFile* bzf = (bzFile*)b;
1138
1139   BZ_SETERR(BZ_OK);
1140   if (bzf == NULL)
1141      { BZ_SETERR(BZ_OK); return; };
1142
1143   if (bzf->writing)
1144      { BZ_SETERR(BZ_SEQUENCE_ERROR); return; };
1145
1146   if (bzf->initialisedOk)
1147      (void)BZ2_bzDecompressEnd ( &(bzf->strm) );
1148   free ( bzf );
1149}
1150
1151
1152/*---------------------------------------------------*/
1153int BZ_API(BZ2_bzRead)
1154           ( int*    bzerror,
1155             BZFILE* b,
1156             void*   buf,
1157             int     len )
1158{
1159   Int32   n, ret;
1160   bzFile* bzf = (bzFile*)b;
1161
1162   BZ_SETERR(BZ_OK);
1163
1164   if (bzf == NULL || buf == NULL || len < 0)
1165      { BZ_SETERR(BZ_PARAM_ERROR); return 0; };
1166
1167   if (bzf->writing)
1168      { BZ_SETERR(BZ_SEQUENCE_ERROR); return 0; };
1169
1170   if (len == 0)
1171      { BZ_SETERR(BZ_OK); return 0; };
1172
1173   bzf->strm.avail_out = len;
1174   bzf->strm.next_out = buf;
1175
1176   while (True) {
1177
1178      if (ferror(bzf->handle))
1179         { BZ_SETERR(BZ_IO_ERROR); return 0; };
1180
1181      if (bzf->strm.avail_in == 0 && !myfeof(bzf->handle)) {
1182         n = fread ( bzf->buf, sizeof(UChar),
1183                     BZ_MAX_UNUSED, bzf->handle );
1184         if (ferror(bzf->handle))
1185            { BZ_SETERR(BZ_IO_ERROR); return 0; };
1186         bzf->bufN = n;
1187         bzf->strm.avail_in = bzf->bufN;
1188         bzf->strm.next_in = bzf->buf;
1189      }
1190
1191      ret = BZ2_bzDecompress ( &(bzf->strm) );
1192
1193      if (ret != BZ_OK && ret != BZ_STREAM_END)
1194         { BZ_SETERR(ret); return 0; };
1195
1196      if (ret == BZ_OK && myfeof(bzf->handle) &&
1197          bzf->strm.avail_in == 0 && bzf->strm.avail_out > 0)
1198         { BZ_SETERR(BZ_UNEXPECTED_EOF); return 0; };
1199
1200      if (ret == BZ_STREAM_END)
1201         { BZ_SETERR(BZ_STREAM_END);
1202           return len - bzf->strm.avail_out; };
1203      if (bzf->strm.avail_out == 0)
1204         { BZ_SETERR(BZ_OK); return len; };
1205
1206   }
1207
1208   return 0; /*not reached*/
1209}
1210
1211
1212/*---------------------------------------------------*/
1213void BZ_API(BZ2_bzReadGetUnused)
1214                     ( int*    bzerror,
1215                       BZFILE* b,
1216                       void**  unused,
1217                       int*    nUnused )
1218{
1219   bzFile* bzf = (bzFile*)b;
1220   if (bzf == NULL)
1221      { BZ_SETERR(BZ_PARAM_ERROR); return; };
1222   if (bzf->lastErr != BZ_STREAM_END)
1223      { BZ_SETERR(BZ_SEQUENCE_ERROR); return; };
1224   if (unused == NULL || nUnused == NULL)
1225      { BZ_SETERR(BZ_PARAM_ERROR); return; };
1226
1227   BZ_SETERR(BZ_OK);
1228   *nUnused = bzf->strm.avail_in;
1229   *unused = bzf->strm.next_in;
1230}
1231#endif
1232
1233
1234/*---------------------------------------------------*/
1235/*--- Misc convenience stuff                      ---*/
1236/*---------------------------------------------------*/
1237
1238/*---------------------------------------------------*/
1239int BZ_API(BZ2_bzBuffToBuffCompress)
1240                         ( char*         dest,
1241                           unsigned int* destLen,
1242                           char*         source,
1243                           unsigned int  sourceLen,
1244                           int           blockSize100k,
1245                           int           verbosity,
1246                           int           workFactor )
1247{
1248   bz_stream strm;
1249   int ret;
1250
1251   if (dest == NULL || destLen == NULL ||
1252       source == NULL ||
1253       blockSize100k < 1 || blockSize100k > 9 ||
1254       verbosity < 0 || verbosity > 4 ||
1255       workFactor < 0 || workFactor > 250)
1256      return BZ_PARAM_ERROR;
1257
1258   if (workFactor == 0) workFactor = 30;
1259   strm.bzalloc = NULL;
1260   strm.bzfree = NULL;
1261   strm.opaque = NULL;
1262   ret = BZ2_bzCompressInit ( &strm, blockSize100k,
1263                              verbosity, workFactor );
1264   if (ret != BZ_OK) return ret;
1265
1266   strm.next_in = source;
1267   strm.next_out = dest;
1268   strm.avail_in = sourceLen;
1269   strm.avail_out = *destLen;
1270
1271   ret = BZ2_bzCompress ( &strm, BZ_FINISH );
1272   if (ret == BZ_FINISH_OK) goto output_overflow;
1273   if (ret != BZ_STREAM_END) goto errhandler;
1274
1275   /* normal termination */
1276   *destLen -= strm.avail_out;
1277   BZ2_bzCompressEnd ( &strm );
1278   return BZ_OK;
1279
1280   output_overflow:
1281   BZ2_bzCompressEnd ( &strm );
1282   return BZ_OUTBUFF_FULL;
1283
1284   errhandler:
1285   BZ2_bzCompressEnd ( &strm );
1286   return ret;
1287}
1288
1289
1290/*---------------------------------------------------*/
1291int BZ_API(BZ2_bzBuffToBuffDecompress)
1292                           ( char*         dest,
1293                             unsigned int* destLen,
1294                             char*         source,
1295                             unsigned int  sourceLen,
1296                             int           small,
1297                             int           verbosity )
1298{
1299   bz_stream strm;
1300   int ret;
1301
1302   if (dest == NULL || destLen == NULL ||
1303       source == NULL ||
1304       (small != 0 && small != 1) ||
1305       verbosity < 0 || verbosity > 4)
1306          return BZ_PARAM_ERROR;
1307
1308   strm.bzalloc = NULL;
1309   strm.bzfree = NULL;
1310   strm.opaque = NULL;
1311   ret = BZ2_bzDecompressInit ( &strm, verbosity, small );
1312   if (ret != BZ_OK) return ret;
1313
1314   strm.next_in = source;
1315   strm.next_out = dest;
1316   strm.avail_in = sourceLen;
1317   strm.avail_out = *destLen;
1318
1319   ret = BZ2_bzDecompress ( &strm );
1320   if (ret == BZ_OK) goto output_overflow_or_eof;
1321   if (ret != BZ_STREAM_END) goto errhandler;
1322
1323   /* normal termination */
1324   *destLen -= strm.avail_out;
1325   BZ2_bzDecompressEnd ( &strm );
1326   return BZ_OK;
1327
1328   output_overflow_or_eof:
1329   if (strm.avail_out > 0) {
1330      BZ2_bzDecompressEnd ( &strm );
1331      return BZ_UNEXPECTED_EOF;
1332   } else {
1333      BZ2_bzDecompressEnd ( &strm );
1334      return BZ_OUTBUFF_FULL;
1335   };
1336
1337   errhandler:
1338   BZ2_bzDecompressEnd ( &strm );
1339   return ret;
1340}
1341
1342
1343/*---------------------------------------------------*/
1344/*--
1345   Code contributed by Yoshioka Tsuneo
1346   (QWF00133@niftyserve.or.jp/tsuneo-y@is.aist-nara.ac.jp),
1347   to support better zlib compatibility.
1348   This code is not _officially_ part of libbzip2 (yet);
1349   I haven't tested it, documented it, or considered the
1350   threading-safeness of it.
1351   If this code breaks, please contact both Yoshioka and me.
1352--*/
1353/*---------------------------------------------------*/
1354
1355/*---------------------------------------------------*/
1356/*--
1357   return version like "0.9.0c".
1358--*/
1359const char * BZ_API(BZ2_bzlibVersion)(void)
1360{
1361   return BZ_VERSION;
1362}
1363
1364
1365#ifndef BZ_NO_STDIO
1366/*---------------------------------------------------*/
1367
1368#if defined(_WIN32) || defined(OS2) || defined(MSDOS)
1369#   include <fcntl.h>
1370#   include <io.h>
1371#   define SET_BINARY_MODE(file) setmode(fileno(file),O_BINARY)
1372#else
1373#   define SET_BINARY_MODE(file)
1374#endif
1375static
1376BZFILE * bzopen_or_bzdopen
1377               ( const char *path,   /* no use when bzdopen */
1378                 int fd,             /* no use when bzdopen */
1379                 const char *mode,
1380                 int open_mode)      /* bzopen: 0, bzdopen:1 */
1381{
1382   int    bzerr;
1383   char   unused[BZ_MAX_UNUSED];
1384   int    blockSize100k = 9;
1385   int    writing       = 0;
1386   char   mode2[10]     = "";
1387   FILE   *fp           = NULL;
1388   BZFILE *bzfp         = NULL;
1389   int    verbosity     = 0;
1390   int    workFactor    = 30;
1391   int    smallMode     = 0;
1392   int    nUnused       = 0;
1393
1394   if (mode == NULL) return NULL;
1395   while (*mode) {
1396      switch (*mode) {
1397      case 'r':
1398         writing = 0; break;
1399      case 'w':
1400         writing = 1; break;
1401      case 's':
1402         smallMode = 1; break;
1403      default:
1404         if (isdigit((int)(*mode))) {
1405            blockSize100k = *mode-'0';
1406         }
1407      }
1408      mode++;
1409   }
1410   strcat(mode2, writing ? "w" : "r" );
1411   strcat(mode2,"b");   /* binary mode */
1412
1413   if (open_mode==0) {
1414      if (path==NULL || strcmp(path,"")==0) {
1415        fp = (writing ? stdout : stdin);
1416        SET_BINARY_MODE(fp);
1417      } else {
1418        fp = fopen(path,mode2);
1419      }
1420   } else {
1421#ifdef BZ_STRICT_ANSI
1422      fp = NULL;
1423#else
1424      fp = fdopen(fd,mode2);
1425#endif
1426   }
1427   if (fp == NULL) return NULL;
1428
1429   if (writing) {
1430      /* Guard against total chaos and anarchy -- JRS */
1431      if (blockSize100k < 1) blockSize100k = 1;
1432      if (blockSize100k > 9) blockSize100k = 9;
1433      bzfp = BZ2_bzWriteOpen(&bzerr,fp,blockSize100k,
1434                             verbosity,workFactor);
1435   } else {
1436      bzfp = BZ2_bzReadOpen(&bzerr,fp,verbosity,smallMode,
1437                            unused,nUnused);
1438   }
1439   if (bzfp == NULL) {
1440      if (fp != stdin && fp != stdout) fclose(fp);
1441      return NULL;
1442   }
1443   return bzfp;
1444}
1445
1446
1447/*---------------------------------------------------*/
1448/*--
1449   open file for read or write.
1450      ex) bzopen("file","w9")
1451      case path="" or NULL => use stdin or stdout.
1452--*/
1453BZFILE * BZ_API(BZ2_bzopen)
1454               ( const char *path,
1455                 const char *mode )
1456{
1457   return bzopen_or_bzdopen(path,-1,mode,/*bzopen*/0);
1458}
1459
1460
1461/*---------------------------------------------------*/
1462BZFILE * BZ_API(BZ2_bzdopen)
1463               ( int fd,
1464                 const char *mode )
1465{
1466   return bzopen_or_bzdopen(NULL,fd,mode,/*bzdopen*/1);
1467}
1468
1469
1470/*---------------------------------------------------*/
1471int BZ_API(BZ2_bzread) (BZFILE* b, void* buf, int len )
1472{
1473   int bzerr, nread;
1474   if (((bzFile*)b)->lastErr == BZ_STREAM_END) return 0;
1475   nread = BZ2_bzRead(&bzerr,b,buf,len);
1476   if (bzerr == BZ_OK || bzerr == BZ_STREAM_END) {
1477      return nread;
1478   } else {
1479      return -1;
1480   }
1481}
1482
1483
1484/*---------------------------------------------------*/
1485int BZ_API(BZ2_bzwrite) (BZFILE* b, void* buf, int len )
1486{
1487   int bzerr;
1488
1489   BZ2_bzWrite(&bzerr,b,buf,len);
1490   if(bzerr == BZ_OK){
1491      return len;
1492   }else{
1493      return -1;
1494   }
1495}
1496
1497
1498/*---------------------------------------------------*/
1499int BZ_API(BZ2_bzflush) (BZFILE *b)
1500{
1501   /* do nothing now... */
1502   return 0;
1503}
1504
1505
1506/*---------------------------------------------------*/
1507void BZ_API(BZ2_bzclose) (BZFILE* b)
1508{
1509   int bzerr;
1510   FILE *fp = ((bzFile *)b)->handle;
1511
1512   if (b==NULL) {return;}
1513   if(((bzFile*)b)->writing){
1514      BZ2_bzWriteClose(&bzerr,b,0,NULL,NULL);
1515      if(bzerr != BZ_OK){
1516         BZ2_bzWriteClose(NULL,b,1,NULL,NULL);
1517      }
1518   }else{
1519      BZ2_bzReadClose(&bzerr,b);
1520   }
1521   if(fp!=stdin && fp!=stdout){
1522      fclose(fp);
1523   }
1524}
1525
1526
1527/*---------------------------------------------------*/
1528/*--
1529   return last error code
1530--*/
1531static char *bzerrorstrings[] = {
1532       "OK"
1533      ,"SEQUENCE_ERROR"
1534      ,"PARAM_ERROR"
1535      ,"MEM_ERROR"
1536      ,"DATA_ERROR"
1537      ,"DATA_ERROR_MAGIC"
1538      ,"IO_ERROR"
1539      ,"UNEXPECTED_EOF"
1540      ,"OUTBUFF_FULL"
1541      ,"CONFIG_ERROR"
1542      ,"???"   /* for future */
1543      ,"???"   /* for future */
1544      ,"???"   /* for future */
1545      ,"???"   /* for future */
1546      ,"???"   /* for future */
1547      ,"???"   /* for future */
1548};
1549
1550
1551const char * BZ_API(BZ2_bzerror) (BZFILE *b, int *errnum)
1552{
1553   int err = ((bzFile *)b)->lastErr;
1554
1555   if(err>0) err = 0;
1556   *errnum = err;
1557   return bzerrorstrings[err*-1];
1558}
1559#endif
1560
1561
1562/*-------------------------------------------------------------*/
1563/*--- end                                           bzlib.c ---*/
1564/*-------------------------------------------------------------*/
1565