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