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