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