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