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