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