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