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