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