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