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