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