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