xref: /freebsd/contrib/bzip2/bzlib.c (revision 1669d8afc64812c8d2d1d147ae1fd42ff441e1b1)
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.4 of 20 December 2006
12    Copyright (C) 1996-2006 Julian Seward <jseward@bzip.org>
13 
14    Please read the WARNING, DISCLAIMER and PATENTS sections in the
15    README file.
16 
17    This program is released under the terms of the license contained
18    in the file LICENSE.
19    ------------------------------------------------------------------ */
20 
21 /* CHANGES
22    0.9.0    -- original version.
23    0.9.0a/b -- no changes in this file.
24    0.9.0c   -- made zero-length BZ_FLUSH work correctly in bzCompress().
25      fixed bzWrite/bzRead to ignore zero-length requests.
26      fixed bzread to correctly handle read requests after EOF.
27      wrong parameter order in call to bzDecompressInit in
28      bzBuffToBuffDecompress.  Fixed.
29 */
30 
31 #include <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 me at: jseward@bzip.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.  Julian Seward, 15 February 2005.\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       /* end restore */
609 
610       UInt32       avail_out_INIT = cs_avail_out;
611       Int32        s_save_nblockPP = s->save_nblock+1;
612       unsigned int total_out_lo32_old;
613 
614       while (True) {
615 
616          /* try to finish existing run */
617          if (c_state_out_len > 0) {
618             while (True) {
619                if (cs_avail_out == 0) goto return_notr;
620                if (c_state_out_len == 1) break;
621                *( (UChar*)(cs_next_out) ) = c_state_out_ch;
622                BZ_UPDATE_CRC ( c_calculatedBlockCRC, c_state_out_ch );
623                c_state_out_len--;
624                cs_next_out++;
625                cs_avail_out--;
626             }
627             s_state_out_len_eq_one:
628             {
629                if (cs_avail_out == 0) {
630                   c_state_out_len = 1; goto return_notr;
631                };
632                *( (UChar*)(cs_next_out) ) = c_state_out_ch;
633                BZ_UPDATE_CRC ( c_calculatedBlockCRC, c_state_out_ch );
634                cs_next_out++;
635                cs_avail_out--;
636             }
637          }
638          /* Only caused by corrupt data stream? */
639          if (c_nblock_used > s_save_nblockPP)
640             return True;
641 
642          /* can a new run be started? */
643          if (c_nblock_used == s_save_nblockPP) {
644             c_state_out_len = 0; goto return_notr;
645          };
646          c_state_out_ch = c_k0;
647          BZ_GET_FAST_C(k1); c_nblock_used++;
648          if (k1 != c_k0) {
649             c_k0 = k1; goto s_state_out_len_eq_one;
650          };
651          if (c_nblock_used == s_save_nblockPP)
652             goto s_state_out_len_eq_one;
653 
654          c_state_out_len = 2;
655          BZ_GET_FAST_C(k1); c_nblock_used++;
656          if (c_nblock_used == s_save_nblockPP) continue;
657          if (k1 != c_k0) { c_k0 = k1; continue; };
658 
659          c_state_out_len = 3;
660          BZ_GET_FAST_C(k1); c_nblock_used++;
661          if (c_nblock_used == s_save_nblockPP) continue;
662          if (k1 != c_k0) { c_k0 = k1; continue; };
663 
664          BZ_GET_FAST_C(k1); c_nblock_used++;
665          c_state_out_len = ((Int32)k1) + 4;
666          BZ_GET_FAST_C(c_k0); c_nblock_used++;
667       }
668 
669       return_notr:
670       total_out_lo32_old = s->strm->total_out_lo32;
671       s->strm->total_out_lo32 += (avail_out_INIT - cs_avail_out);
672       if (s->strm->total_out_lo32 < total_out_lo32_old)
673          s->strm->total_out_hi32++;
674 
675       /* save */
676       s->calculatedBlockCRC = c_calculatedBlockCRC;
677       s->state_out_ch       = c_state_out_ch;
678       s->state_out_len      = c_state_out_len;
679       s->nblock_used        = c_nblock_used;
680       s->k0                 = c_k0;
681       s->tt                 = c_tt;
682       s->tPos               = c_tPos;
683       s->strm->next_out     = cs_next_out;
684       s->strm->avail_out    = cs_avail_out;
685       /* end save */
686    }
687    return False;
688 }
689 
690 
691 
692 /*---------------------------------------------------*/
693 __inline__ Int32 BZ2_indexIntoF ( Int32 indx, Int32 *cftab )
694 {
695    Int32 nb, na, mid;
696    nb = 0;
697    na = 256;
698    do {
699       mid = (nb + na) >> 1;
700       if (indx >= cftab[mid]) nb = mid; else na = mid;
701    }
702    while (na - nb != 1);
703    return nb;
704 }
705 
706 
707 /*---------------------------------------------------*/
708 /* Return  True iff data corruption is discovered.
709    Returns False if there is no problem.
710 */
711 static
712 Bool unRLE_obuf_to_output_SMALL ( DState* s )
713 {
714    UChar k1;
715 
716    if (s->blockRandomised) {
717 
718       while (True) {
719          /* try to finish existing run */
720          while (True) {
721             if (s->strm->avail_out == 0) return False;
722             if (s->state_out_len == 0) break;
723             *( (UChar*)(s->strm->next_out) ) = s->state_out_ch;
724             BZ_UPDATE_CRC ( s->calculatedBlockCRC, s->state_out_ch );
725             s->state_out_len--;
726             s->strm->next_out++;
727             s->strm->avail_out--;
728             s->strm->total_out_lo32++;
729             if (s->strm->total_out_lo32 == 0) s->strm->total_out_hi32++;
730          }
731 
732          /* can a new run be started? */
733          if (s->nblock_used == s->save_nblock+1) return False;
734 
735          /* Only caused by corrupt data stream? */
736          if (s->nblock_used > s->save_nblock+1)
737             return True;
738 
739          s->state_out_len = 1;
740          s->state_out_ch = s->k0;
741          BZ_GET_SMALL(k1); BZ_RAND_UPD_MASK;
742          k1 ^= BZ_RAND_MASK; s->nblock_used++;
743          if (s->nblock_used == s->save_nblock+1) continue;
744          if (k1 != s->k0) { s->k0 = k1; continue; };
745 
746          s->state_out_len = 2;
747          BZ_GET_SMALL(k1); BZ_RAND_UPD_MASK;
748          k1 ^= BZ_RAND_MASK; s->nblock_used++;
749          if (s->nblock_used == s->save_nblock+1) continue;
750          if (k1 != s->k0) { s->k0 = k1; continue; };
751 
752          s->state_out_len = 3;
753          BZ_GET_SMALL(k1); BZ_RAND_UPD_MASK;
754          k1 ^= BZ_RAND_MASK; s->nblock_used++;
755          if (s->nblock_used == s->save_nblock+1) continue;
756          if (k1 != s->k0) { s->k0 = k1; continue; };
757 
758          BZ_GET_SMALL(k1); BZ_RAND_UPD_MASK;
759          k1 ^= BZ_RAND_MASK; s->nblock_used++;
760          s->state_out_len = ((Int32)k1) + 4;
761          BZ_GET_SMALL(s->k0); BZ_RAND_UPD_MASK;
762          s->k0 ^= BZ_RAND_MASK; s->nblock_used++;
763       }
764 
765    } else {
766 
767       while (True) {
768          /* try to finish existing run */
769          while (True) {
770             if (s->strm->avail_out == 0) return False;
771             if (s->state_out_len == 0) break;
772             *( (UChar*)(s->strm->next_out) ) = s->state_out_ch;
773             BZ_UPDATE_CRC ( s->calculatedBlockCRC, s->state_out_ch );
774             s->state_out_len--;
775             s->strm->next_out++;
776             s->strm->avail_out--;
777             s->strm->total_out_lo32++;
778             if (s->strm->total_out_lo32 == 0) s->strm->total_out_hi32++;
779          }
780 
781          /* can a new run be started? */
782          if (s->nblock_used == s->save_nblock+1) return False;
783 
784          /* Only caused by corrupt data stream? */
785          if (s->nblock_used > s->save_nblock+1)
786             return True;
787 
788          s->state_out_len = 1;
789          s->state_out_ch = s->k0;
790          BZ_GET_SMALL(k1); s->nblock_used++;
791          if (s->nblock_used == s->save_nblock+1) continue;
792          if (k1 != s->k0) { s->k0 = k1; continue; };
793 
794          s->state_out_len = 2;
795          BZ_GET_SMALL(k1); s->nblock_used++;
796          if (s->nblock_used == s->save_nblock+1) continue;
797          if (k1 != s->k0) { s->k0 = k1; continue; };
798 
799          s->state_out_len = 3;
800          BZ_GET_SMALL(k1); s->nblock_used++;
801          if (s->nblock_used == s->save_nblock+1) continue;
802          if (k1 != s->k0) { s->k0 = k1; continue; };
803 
804          BZ_GET_SMALL(k1); s->nblock_used++;
805          s->state_out_len = ((Int32)k1) + 4;
806          BZ_GET_SMALL(s->k0); s->nblock_used++;
807       }
808 
809    }
810 }
811 
812 
813 /*---------------------------------------------------*/
814 int BZ_API(BZ2_bzDecompress) ( bz_stream *strm )
815 {
816    Bool    corrupt;
817    DState* s;
818    if (strm == NULL) return BZ_PARAM_ERROR;
819    s = strm->state;
820    if (s == NULL) return BZ_PARAM_ERROR;
821    if (s->strm != strm) return BZ_PARAM_ERROR;
822 
823    while (True) {
824       if (s->state == BZ_X_IDLE) return BZ_SEQUENCE_ERROR;
825       if (s->state == BZ_X_OUTPUT) {
826          if (s->smallDecompress)
827             corrupt = unRLE_obuf_to_output_SMALL ( s ); else
828             corrupt = unRLE_obuf_to_output_FAST  ( s );
829          if (corrupt) return BZ_DATA_ERROR;
830          if (s->nblock_used == s->save_nblock+1 && s->state_out_len == 0) {
831             BZ_FINALISE_CRC ( s->calculatedBlockCRC );
832             if (s->verbosity >= 3)
833                VPrintf2 ( " {0x%08x, 0x%08x}", s->storedBlockCRC,
834                           s->calculatedBlockCRC );
835             if (s->verbosity >= 2) VPrintf0 ( "]" );
836             if (s->calculatedBlockCRC != s->storedBlockCRC)
837                return BZ_DATA_ERROR;
838             s->calculatedCombinedCRC
839                = (s->calculatedCombinedCRC << 1) |
840                     (s->calculatedCombinedCRC >> 31);
841             s->calculatedCombinedCRC ^= s->calculatedBlockCRC;
842             s->state = BZ_X_BLKHDR_1;
843          } else {
844             return BZ_OK;
845          }
846       }
847       if (s->state >= BZ_X_MAGIC_1) {
848          Int32 r = BZ2_decompress ( s );
849          if (r == BZ_STREAM_END) {
850             if (s->verbosity >= 3)
851                VPrintf2 ( "\n    combined CRCs: stored = 0x%08x, computed = 0x%08x",
852                           s->storedCombinedCRC, s->calculatedCombinedCRC );
853             if (s->calculatedCombinedCRC != s->storedCombinedCRC)
854                return BZ_DATA_ERROR;
855             return r;
856          }
857          if (s->state != BZ_X_OUTPUT) return r;
858       }
859    }
860 
861    AssertH ( 0, 6001 );
862 
863    return 0;  /*NOTREACHED*/
864 }
865 
866 
867 /*---------------------------------------------------*/
868 int BZ_API(BZ2_bzDecompressEnd)  ( bz_stream *strm )
869 {
870    DState* s;
871    if (strm == NULL) return BZ_PARAM_ERROR;
872    s = strm->state;
873    if (s == NULL) return BZ_PARAM_ERROR;
874    if (s->strm != strm) return BZ_PARAM_ERROR;
875 
876    if (s->tt   != NULL) BZFREE(s->tt);
877    if (s->ll16 != NULL) BZFREE(s->ll16);
878    if (s->ll4  != NULL) BZFREE(s->ll4);
879 
880    BZFREE(strm->state);
881    strm->state = NULL;
882 
883    return BZ_OK;
884 }
885 
886 #ifndef BZ_NO_COMPRESS
887 
888 #ifndef BZ_NO_STDIO
889 /*---------------------------------------------------*/
890 /*--- File I/O stuff                              ---*/
891 /*---------------------------------------------------*/
892 
893 #define BZ_SETERR(eee)                    \
894 {                                         \
895    if (bzerror != NULL) *bzerror = eee;   \
896    if (bzf != NULL) bzf->lastErr = eee;   \
897 }
898 
899 typedef
900    struct {
901       FILE*     handle;
902       Char      buf[BZ_MAX_UNUSED];
903       Int32     bufN;
904       Bool      writing;
905       bz_stream strm;
906       Int32     lastErr;
907       Bool      initialisedOk;
908    }
909    bzFile;
910 
911 
912 /*---------------------------------------------*/
913 static Bool myfeof ( FILE* f )
914 {
915    Int32 c = fgetc ( f );
916    if (c == EOF) return True;
917    ungetc ( c, f );
918    return False;
919 }
920 
921 
922 /*---------------------------------------------------*/
923 BZFILE* BZ_API(BZ2_bzWriteOpen)
924                     ( int*  bzerror,
925                       FILE* f,
926                       int   blockSize100k,
927                       int   verbosity,
928                       int   workFactor )
929 {
930    Int32   ret;
931    bzFile* bzf = NULL;
932 
933    BZ_SETERR(BZ_OK);
934 
935    if (f == NULL ||
936        (blockSize100k < 1 || blockSize100k > 9) ||
937        (workFactor < 0 || workFactor > 250) ||
938        (verbosity < 0 || verbosity > 4))
939       { BZ_SETERR(BZ_PARAM_ERROR); return NULL; };
940 
941    if (ferror(f))
942       { BZ_SETERR(BZ_IO_ERROR); return NULL; };
943 
944    bzf = malloc ( sizeof(bzFile) );
945    if (bzf == NULL)
946       { BZ_SETERR(BZ_MEM_ERROR); return NULL; };
947 
948    BZ_SETERR(BZ_OK);
949    bzf->initialisedOk = False;
950    bzf->bufN          = 0;
951    bzf->handle        = f;
952    bzf->writing       = True;
953    bzf->strm.bzalloc  = NULL;
954    bzf->strm.bzfree   = NULL;
955    bzf->strm.opaque   = NULL;
956 
957    if (workFactor == 0) workFactor = 30;
958    ret = BZ2_bzCompressInit ( &(bzf->strm), blockSize100k,
959                               verbosity, workFactor );
960    if (ret != BZ_OK)
961       { BZ_SETERR(ret); free(bzf); return NULL; };
962 
963    bzf->strm.avail_in = 0;
964    bzf->initialisedOk = True;
965    return bzf;
966 }
967 
968 
969 
970 /*---------------------------------------------------*/
971 void BZ_API(BZ2_bzWrite)
972              ( int*    bzerror,
973                BZFILE* b,
974                void*   buf,
975                int     len )
976 {
977    Int32 n, n2, ret;
978    bzFile* bzf = (bzFile*)b;
979 
980    BZ_SETERR(BZ_OK);
981    if (bzf == NULL || buf == NULL || len < 0)
982       { BZ_SETERR(BZ_PARAM_ERROR); return; };
983    if (!(bzf->writing))
984       { BZ_SETERR(BZ_SEQUENCE_ERROR); return; };
985    if (ferror(bzf->handle))
986       { BZ_SETERR(BZ_IO_ERROR); return; };
987 
988    if (len == 0)
989       { BZ_SETERR(BZ_OK); return; };
990 
991    bzf->strm.avail_in = len;
992    bzf->strm.next_in  = buf;
993 
994    while (True) {
995       bzf->strm.avail_out = BZ_MAX_UNUSED;
996       bzf->strm.next_out = bzf->buf;
997       ret = BZ2_bzCompress ( &(bzf->strm), BZ_RUN );
998       if (ret != BZ_RUN_OK)
999          { BZ_SETERR(ret); return; };
1000 
1001       if (bzf->strm.avail_out < BZ_MAX_UNUSED) {
1002          n = BZ_MAX_UNUSED - bzf->strm.avail_out;
1003          n2 = fwrite ( (void*)(bzf->buf), sizeof(UChar),
1004                        n, bzf->handle );
1005          if (n != n2 || ferror(bzf->handle))
1006             { BZ_SETERR(BZ_IO_ERROR); return; };
1007       }
1008 
1009       if (bzf->strm.avail_in == 0)
1010          { BZ_SETERR(BZ_OK); return; };
1011    }
1012 }
1013 
1014 
1015 /*---------------------------------------------------*/
1016 void BZ_API(BZ2_bzWriteClose)
1017                   ( int*          bzerror,
1018                     BZFILE*       b,
1019                     int           abandon,
1020                     unsigned int* nbytes_in,
1021                     unsigned int* nbytes_out )
1022 {
1023    BZ2_bzWriteClose64 ( bzerror, b, abandon,
1024                         nbytes_in, NULL, nbytes_out, NULL );
1025 }
1026 
1027 
1028 void BZ_API(BZ2_bzWriteClose64)
1029                   ( int*          bzerror,
1030                     BZFILE*       b,
1031                     int           abandon,
1032                     unsigned int* nbytes_in_lo32,
1033                     unsigned int* nbytes_in_hi32,
1034                     unsigned int* nbytes_out_lo32,
1035                     unsigned int* nbytes_out_hi32 )
1036 {
1037    Int32   n, n2, ret;
1038    bzFile* bzf = (bzFile*)b;
1039 
1040    if (bzf == NULL)
1041       { BZ_SETERR(BZ_OK); return; };
1042    if (!(bzf->writing))
1043       { BZ_SETERR(BZ_SEQUENCE_ERROR); return; };
1044    if (ferror(bzf->handle))
1045       { BZ_SETERR(BZ_IO_ERROR); return; };
1046 
1047    if (nbytes_in_lo32 != NULL) *nbytes_in_lo32 = 0;
1048    if (nbytes_in_hi32 != NULL) *nbytes_in_hi32 = 0;
1049    if (nbytes_out_lo32 != NULL) *nbytes_out_lo32 = 0;
1050    if (nbytes_out_hi32 != NULL) *nbytes_out_hi32 = 0;
1051 
1052    if ((!abandon) && bzf->lastErr == BZ_OK) {
1053       while (True) {
1054          bzf->strm.avail_out = BZ_MAX_UNUSED;
1055          bzf->strm.next_out = bzf->buf;
1056          ret = BZ2_bzCompress ( &(bzf->strm), BZ_FINISH );
1057          if (ret != BZ_FINISH_OK && ret != BZ_STREAM_END)
1058             { BZ_SETERR(ret); return; };
1059 
1060          if (bzf->strm.avail_out < BZ_MAX_UNUSED) {
1061             n = BZ_MAX_UNUSED - bzf->strm.avail_out;
1062             n2 = fwrite ( (void*)(bzf->buf), sizeof(UChar),
1063                           n, bzf->handle );
1064             if (n != n2 || ferror(bzf->handle))
1065                { BZ_SETERR(BZ_IO_ERROR); return; };
1066          }
1067 
1068          if (ret == BZ_STREAM_END) break;
1069       }
1070    }
1071 
1072    if ( !abandon && !ferror ( bzf->handle ) ) {
1073       fflush ( bzf->handle );
1074       if (ferror(bzf->handle))
1075          { BZ_SETERR(BZ_IO_ERROR); return; };
1076    }
1077 
1078    if (nbytes_in_lo32 != NULL)
1079       *nbytes_in_lo32 = bzf->strm.total_in_lo32;
1080    if (nbytes_in_hi32 != NULL)
1081       *nbytes_in_hi32 = bzf->strm.total_in_hi32;
1082    if (nbytes_out_lo32 != NULL)
1083       *nbytes_out_lo32 = bzf->strm.total_out_lo32;
1084    if (nbytes_out_hi32 != NULL)
1085       *nbytes_out_hi32 = bzf->strm.total_out_hi32;
1086 
1087    BZ_SETERR(BZ_OK);
1088    BZ2_bzCompressEnd ( &(bzf->strm) );
1089    free ( bzf );
1090 }
1091 
1092 
1093 /*---------------------------------------------------*/
1094 BZFILE* BZ_API(BZ2_bzReadOpen)
1095                    ( int*  bzerror,
1096                      FILE* f,
1097                      int   verbosity,
1098                      int   small,
1099                      void* unused,
1100                      int   nUnused )
1101 {
1102    bzFile* bzf = NULL;
1103    int     ret;
1104 
1105    BZ_SETERR(BZ_OK);
1106 
1107    if (f == NULL ||
1108        (small != 0 && small != 1) ||
1109        (verbosity < 0 || verbosity > 4) ||
1110        (unused == NULL && nUnused != 0) ||
1111        (unused != NULL && (nUnused < 0 || nUnused > BZ_MAX_UNUSED)))
1112       { BZ_SETERR(BZ_PARAM_ERROR); return NULL; };
1113 
1114    if (ferror(f))
1115       { BZ_SETERR(BZ_IO_ERROR); return NULL; };
1116 
1117    bzf = malloc ( sizeof(bzFile) );
1118    if (bzf == NULL)
1119       { BZ_SETERR(BZ_MEM_ERROR); return NULL; };
1120 
1121    BZ_SETERR(BZ_OK);
1122 
1123    bzf->initialisedOk = False;
1124    bzf->handle        = f;
1125    bzf->bufN          = 0;
1126    bzf->writing       = False;
1127    bzf->strm.bzalloc  = NULL;
1128    bzf->strm.bzfree   = NULL;
1129    bzf->strm.opaque   = NULL;
1130 
1131    while (nUnused > 0) {
1132       bzf->buf[bzf->bufN] = *((UChar*)(unused)); bzf->bufN++;
1133       unused = ((void*)( 1 + ((UChar*)(unused))  ));
1134       nUnused--;
1135    }
1136 
1137    ret = BZ2_bzDecompressInit ( &(bzf->strm), verbosity, small );
1138    if (ret != BZ_OK)
1139       { BZ_SETERR(ret); free(bzf); return NULL; };
1140 
1141    bzf->strm.avail_in = bzf->bufN;
1142    bzf->strm.next_in  = bzf->buf;
1143 
1144    bzf->initialisedOk = True;
1145    return bzf;
1146 }
1147 
1148 
1149 /*---------------------------------------------------*/
1150 void BZ_API(BZ2_bzReadClose) ( int *bzerror, BZFILE *b )
1151 {
1152    bzFile* bzf = (bzFile*)b;
1153 
1154    BZ_SETERR(BZ_OK);
1155    if (bzf == NULL)
1156       { BZ_SETERR(BZ_OK); return; };
1157 
1158    if (bzf->writing)
1159       { BZ_SETERR(BZ_SEQUENCE_ERROR); return; };
1160 
1161    if (bzf->initialisedOk)
1162       (void)BZ2_bzDecompressEnd ( &(bzf->strm) );
1163    free ( bzf );
1164 }
1165 
1166 
1167 /*---------------------------------------------------*/
1168 int BZ_API(BZ2_bzRead)
1169            ( int*    bzerror,
1170              BZFILE* b,
1171              void*   buf,
1172              int     len )
1173 {
1174    Int32   n, ret;
1175    bzFile* bzf = (bzFile*)b;
1176 
1177    BZ_SETERR(BZ_OK);
1178 
1179    if (bzf == NULL || buf == NULL || len < 0)
1180       { BZ_SETERR(BZ_PARAM_ERROR); return 0; };
1181 
1182    if (bzf->writing)
1183       { BZ_SETERR(BZ_SEQUENCE_ERROR); return 0; };
1184 
1185    if (len == 0)
1186       { BZ_SETERR(BZ_OK); return 0; };
1187 
1188    bzf->strm.avail_out = len;
1189    bzf->strm.next_out = buf;
1190 
1191    while (True) {
1192 
1193       if (ferror(bzf->handle))
1194          { BZ_SETERR(BZ_IO_ERROR); return 0; };
1195 
1196       if (bzf->strm.avail_in == 0 && !myfeof(bzf->handle)) {
1197          n = fread ( bzf->buf, sizeof(UChar),
1198                      BZ_MAX_UNUSED, bzf->handle );
1199          if (ferror(bzf->handle))
1200             { BZ_SETERR(BZ_IO_ERROR); return 0; };
1201          bzf->bufN = n;
1202          bzf->strm.avail_in = bzf->bufN;
1203          bzf->strm.next_in = bzf->buf;
1204       }
1205 
1206       ret = BZ2_bzDecompress ( &(bzf->strm) );
1207 
1208       if (ret != BZ_OK && ret != BZ_STREAM_END)
1209          { BZ_SETERR(ret); return 0; };
1210 
1211       if (ret == BZ_OK && myfeof(bzf->handle) &&
1212           bzf->strm.avail_in == 0 && bzf->strm.avail_out > 0)
1213          { BZ_SETERR(BZ_UNEXPECTED_EOF); return 0; };
1214 
1215       if (ret == BZ_STREAM_END)
1216          { BZ_SETERR(BZ_STREAM_END);
1217            return len - bzf->strm.avail_out; };
1218       if (bzf->strm.avail_out == 0)
1219          { BZ_SETERR(BZ_OK); return len; };
1220 
1221    }
1222 
1223    return 0; /*not reached*/
1224 }
1225 
1226 
1227 /*---------------------------------------------------*/
1228 void BZ_API(BZ2_bzReadGetUnused)
1229                      ( int*    bzerror,
1230                        BZFILE* b,
1231                        void**  unused,
1232                        int*    nUnused )
1233 {
1234    bzFile* bzf = (bzFile*)b;
1235    if (bzf == NULL)
1236       { BZ_SETERR(BZ_PARAM_ERROR); return; };
1237    if (bzf->lastErr != BZ_STREAM_END)
1238       { BZ_SETERR(BZ_SEQUENCE_ERROR); return; };
1239    if (unused == NULL || nUnused == NULL)
1240       { BZ_SETERR(BZ_PARAM_ERROR); return; };
1241 
1242    BZ_SETERR(BZ_OK);
1243    *nUnused = bzf->strm.avail_in;
1244    *unused = bzf->strm.next_in;
1245 }
1246 #endif
1247 
1248 
1249 /*---------------------------------------------------*/
1250 /*--- Misc convenience stuff                      ---*/
1251 /*---------------------------------------------------*/
1252 
1253 /*---------------------------------------------------*/
1254 int BZ_API(BZ2_bzBuffToBuffCompress)
1255                          ( char*         dest,
1256                            unsigned int* destLen,
1257                            char*         source,
1258                            unsigned int  sourceLen,
1259                            int           blockSize100k,
1260                            int           verbosity,
1261                            int           workFactor )
1262 {
1263    bz_stream strm;
1264    int ret;
1265 
1266    if (dest == NULL || destLen == NULL ||
1267        source == NULL ||
1268        blockSize100k < 1 || blockSize100k > 9 ||
1269        verbosity < 0 || verbosity > 4 ||
1270        workFactor < 0 || workFactor > 250)
1271       return BZ_PARAM_ERROR;
1272 
1273    if (workFactor == 0) workFactor = 30;
1274    strm.bzalloc = NULL;
1275    strm.bzfree = NULL;
1276    strm.opaque = NULL;
1277    ret = BZ2_bzCompressInit ( &strm, blockSize100k,
1278                               verbosity, workFactor );
1279    if (ret != BZ_OK) return ret;
1280 
1281    strm.next_in = source;
1282    strm.next_out = dest;
1283    strm.avail_in = sourceLen;
1284    strm.avail_out = *destLen;
1285 
1286    ret = BZ2_bzCompress ( &strm, BZ_FINISH );
1287    if (ret == BZ_FINISH_OK) goto output_overflow;
1288    if (ret != BZ_STREAM_END) goto errhandler;
1289 
1290    /* normal termination */
1291    *destLen -= strm.avail_out;
1292    BZ2_bzCompressEnd ( &strm );
1293    return BZ_OK;
1294 
1295    output_overflow:
1296    BZ2_bzCompressEnd ( &strm );
1297    return BZ_OUTBUFF_FULL;
1298 
1299    errhandler:
1300    BZ2_bzCompressEnd ( &strm );
1301    return ret;
1302 }
1303 
1304 
1305 /*---------------------------------------------------*/
1306 int BZ_API(BZ2_bzBuffToBuffDecompress)
1307                            ( char*         dest,
1308                              unsigned int* destLen,
1309                              char*         source,
1310                              unsigned int  sourceLen,
1311                              int           small,
1312                              int           verbosity )
1313 {
1314    bz_stream strm;
1315    int ret;
1316 
1317    if (dest == NULL || destLen == NULL ||
1318        source == NULL ||
1319        (small != 0 && small != 1) ||
1320        verbosity < 0 || verbosity > 4)
1321           return BZ_PARAM_ERROR;
1322 
1323    strm.bzalloc = NULL;
1324    strm.bzfree = NULL;
1325    strm.opaque = NULL;
1326    ret = BZ2_bzDecompressInit ( &strm, verbosity, small );
1327    if (ret != BZ_OK) return ret;
1328 
1329    strm.next_in = source;
1330    strm.next_out = dest;
1331    strm.avail_in = sourceLen;
1332    strm.avail_out = *destLen;
1333 
1334    ret = BZ2_bzDecompress ( &strm );
1335    if (ret == BZ_OK) goto output_overflow_or_eof;
1336    if (ret != BZ_STREAM_END) goto errhandler;
1337 
1338    /* normal termination */
1339    *destLen -= strm.avail_out;
1340    BZ2_bzDecompressEnd ( &strm );
1341    return BZ_OK;
1342 
1343    output_overflow_or_eof:
1344    if (strm.avail_out > 0) {
1345       BZ2_bzDecompressEnd ( &strm );
1346       return BZ_UNEXPECTED_EOF;
1347    } else {
1348       BZ2_bzDecompressEnd ( &strm );
1349       return BZ_OUTBUFF_FULL;
1350    };
1351 
1352    errhandler:
1353    BZ2_bzDecompressEnd ( &strm );
1354    return ret;
1355 }
1356 
1357 
1358 /*---------------------------------------------------*/
1359 /*--
1360    Code contributed by Yoshioka Tsuneo (tsuneo@rr.iij4u.or.jp)
1361    to support better zlib compatibility.
1362    This code is not _officially_ part of libbzip2 (yet);
1363    I haven't tested it, documented it, or considered the
1364    threading-safeness of it.
1365    If this code breaks, please contact both Yoshioka and me.
1366 --*/
1367 /*---------------------------------------------------*/
1368 
1369 /*---------------------------------------------------*/
1370 /*--
1371    return version like "0.9.5d, 4-Sept-1999".
1372 --*/
1373 const char * BZ_API(BZ2_bzlibVersion)(void)
1374 {
1375    return BZ_VERSION;
1376 }
1377 
1378 
1379 #ifndef BZ_NO_STDIO
1380 /*---------------------------------------------------*/
1381 
1382 #if defined(_WIN32) || defined(OS2) || defined(MSDOS)
1383 #   include <fcntl.h>
1384 #   include <io.h>
1385 #   define SET_BINARY_MODE(file) setmode(fileno(file),O_BINARY)
1386 #else
1387 #   define SET_BINARY_MODE(file)
1388 #endif
1389 static
1390 BZFILE * bzopen_or_bzdopen
1391                ( const char *path,   /* no use when bzdopen */
1392                  int fd,             /* no use when bzdopen */
1393                  const char *mode,
1394                  int open_mode)      /* bzopen: 0, bzdopen:1 */
1395 {
1396    int    bzerr;
1397    char   unused[BZ_MAX_UNUSED];
1398    int    blockSize100k = 9;
1399    int    writing       = 0;
1400    char   mode2[10]     = "";
1401    FILE   *fp           = NULL;
1402    BZFILE *bzfp         = NULL;
1403    int    verbosity     = 0;
1404    int    workFactor    = 30;
1405    int    smallMode     = 0;
1406    int    nUnused       = 0;
1407 
1408    if (mode == NULL) return NULL;
1409    while (*mode) {
1410       switch (*mode) {
1411       case 'r':
1412          writing = 0; break;
1413       case 'w':
1414          writing = 1; break;
1415       case 's':
1416          smallMode = 1; break;
1417       default:
1418          if (isdigit((int)(*mode))) {
1419             blockSize100k = *mode-BZ_HDR_0;
1420          }
1421       }
1422       mode++;
1423    }
1424    strcat(mode2, writing ? "w" : "r" );
1425    strcat(mode2,"b");   /* binary mode */
1426 
1427    if (open_mode==0) {
1428       if (path==NULL || strcmp(path,"")==0) {
1429         fp = (writing ? stdout : stdin);
1430         SET_BINARY_MODE(fp);
1431       } else {
1432         fp = fopen(path,mode2);
1433       }
1434    } else {
1435 #ifdef BZ_STRICT_ANSI
1436       fp = NULL;
1437 #else
1438       fp = fdopen(fd,mode2);
1439 #endif
1440    }
1441    if (fp == NULL) return NULL;
1442 
1443    if (writing) {
1444       /* Guard against total chaos and anarchy -- JRS */
1445       if (blockSize100k < 1) blockSize100k = 1;
1446       if (blockSize100k > 9) blockSize100k = 9;
1447       bzfp = BZ2_bzWriteOpen(&bzerr,fp,blockSize100k,
1448                              verbosity,workFactor);
1449    } else {
1450       bzfp = BZ2_bzReadOpen(&bzerr,fp,verbosity,smallMode,
1451                             unused,nUnused);
1452    }
1453    if (bzfp == NULL) {
1454       if (fp != stdin && fp != stdout) fclose(fp);
1455       return NULL;
1456    }
1457    return bzfp;
1458 }
1459 
1460 
1461 /*---------------------------------------------------*/
1462 /*--
1463    open file for read or write.
1464       ex) bzopen("file","w9")
1465       case path="" or NULL => use stdin or stdout.
1466 --*/
1467 BZFILE * BZ_API(BZ2_bzopen)
1468                ( const char *path,
1469                  const char *mode )
1470 {
1471    return bzopen_or_bzdopen(path,-1,mode,/*bzopen*/0);
1472 }
1473 
1474 
1475 /*---------------------------------------------------*/
1476 BZFILE * BZ_API(BZ2_bzdopen)
1477                ( int fd,
1478                  const char *mode )
1479 {
1480    return bzopen_or_bzdopen(NULL,fd,mode,/*bzdopen*/1);
1481 }
1482 
1483 
1484 /*---------------------------------------------------*/
1485 int BZ_API(BZ2_bzread) (BZFILE* b, void* buf, int len )
1486 {
1487    int bzerr, nread;
1488    if (((bzFile*)b)->lastErr == BZ_STREAM_END) return 0;
1489    nread = BZ2_bzRead(&bzerr,b,buf,len);
1490    if (bzerr == BZ_OK || bzerr == BZ_STREAM_END) {
1491       return nread;
1492    } else {
1493       return -1;
1494    }
1495 }
1496 
1497 
1498 /*---------------------------------------------------*/
1499 int BZ_API(BZ2_bzwrite) (BZFILE* b, void* buf, int len )
1500 {
1501    int bzerr;
1502 
1503    BZ2_bzWrite(&bzerr,b,buf,len);
1504    if(bzerr == BZ_OK){
1505       return len;
1506    }else{
1507       return -1;
1508    }
1509 }
1510 
1511 
1512 /*---------------------------------------------------*/
1513 int BZ_API(BZ2_bzflush) (BZFILE *b)
1514 {
1515    /* do nothing now... */
1516    return 0;
1517 }
1518 
1519 
1520 /*---------------------------------------------------*/
1521 void BZ_API(BZ2_bzclose) (BZFILE* b)
1522 {
1523    int bzerr;
1524    FILE *fp;
1525 
1526    if (b==NULL) {return;}
1527    fp = ((bzFile *)b)->handle;
1528    if(((bzFile*)b)->writing){
1529       BZ2_bzWriteClose(&bzerr,b,0,NULL,NULL);
1530       if(bzerr != BZ_OK){
1531          BZ2_bzWriteClose(NULL,b,1,NULL,NULL);
1532       }
1533    }else{
1534       BZ2_bzReadClose(&bzerr,b);
1535    }
1536    if(fp!=stdin && fp!=stdout){
1537       fclose(fp);
1538    }
1539 }
1540 
1541 
1542 /*---------------------------------------------------*/
1543 /*--
1544    return last error code
1545 --*/
1546 static const char *bzerrorstrings[] = {
1547        "OK"
1548       ,"SEQUENCE_ERROR"
1549       ,"PARAM_ERROR"
1550       ,"MEM_ERROR"
1551       ,"DATA_ERROR"
1552       ,"DATA_ERROR_MAGIC"
1553       ,"IO_ERROR"
1554       ,"UNEXPECTED_EOF"
1555       ,"OUTBUFF_FULL"
1556       ,"CONFIG_ERROR"
1557       ,"???"   /* for future */
1558       ,"???"   /* for future */
1559       ,"???"   /* for future */
1560       ,"???"   /* for future */
1561       ,"???"   /* for future */
1562       ,"???"   /* for future */
1563 };
1564 
1565 
1566 const char * BZ_API(BZ2_bzerror) (BZFILE *b, int *errnum)
1567 {
1568    int err = ((bzFile *)b)->lastErr;
1569 
1570    if(err>0) err = 0;
1571    *errnum = err;
1572    return bzerrorstrings[err*-1];
1573 }
1574 #endif
1575 
1576 #endif /* BZ_NO_COMPRESS */
1577 
1578 /*-------------------------------------------------------------*/
1579 /*--- end                                           bzlib.c ---*/
1580 /*-------------------------------------------------------------*/
1581