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