1 #pragma prototyped
2 
3 /*-------------------------------------------------------------*/
4 /*--- Library top-level functions.                          ---*/
5 /*---                                               bzlib.c ---*/
6 /*-------------------------------------------------------------*/
7 
8 /*--
9   This file is a part of bzip2 and/or libbzip2, a program and
10   library for lossless, block-sorting data compression.
11 
12   Copyright (C) 1996-1998 Julian R Seward.  All rights reserved.
13 
14   Redistribution and use in source and binary forms, with or without
15   modification, are permitted provided that the following conditions
16   are met:
17 
18   1. Redistributions of source code must retain the above copyright
19      notice, this list of conditions and the following disclaimer.
20 
21   2. The origin of this software must not be misrepresented; you must
22      not claim that you wrote the original software.  If you use this
23      software in a product, an acknowledgment in the product
24      documentation would be appreciated but is not required.
25 
26   3. Altered source versions must be plainly marked as such, and must
27      not be misrepresented as being the original software.
28 
29   4. The name of the author may not be used to endorse or promote
30      products derived from this software without specific prior written
31      permission.
32 
33   THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
34   OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
35   WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
36   ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
37   DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
38   DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
39   GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
40   INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
41   WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
42   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
43   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
44 
45   Julian Seward, Guildford, Surrey, UK.
46   jseward@acm.org
47   bzip2/libbzip2 version 0.9.0c of 18 October 1998
48 
49   This program is based on (at least) the work of:
50      Mike Burrows
51      David Wheeler
52      Peter Fenwick
53      Alistair Moffat
54      Radford Neal
55      Ian H. Witten
56      Robert Sedgewick
57      Jon L. Bentley
58 
59   For more information on these sources, see the manual.
60 --*/
61 
62 /*--
63    CHANGES
64    ~~~~~~~
65    0.9.0 -- original version.
66 
67    0.9.0a/b -- no changes in this file.
68 
69    0.9.0c
70       * made zero-length BZ_FLUSH work correctly in bzCompress().
71       * fixed bzWrite/bzRead to ignore zero-length requests.
72       * fixed bzread to correctly handle read requests after EOF.
73       * wrong parameter order in call to bzDecompressInit in
74         bzBuffToBuffDecompress.  Fixed.
75 --*/
76 
77 #include "bzhdr.h"
78 
79 
80 /*---------------------------------------------------*/
81 /*--- Compression stuff                           ---*/
82 /*---------------------------------------------------*/
83 
84 
85 /*---------------------------------------------------*/
86 #ifndef BZ_NO_STDIO
bz__AssertH__fail(int errcode)87 void bz__AssertH__fail ( int errcode )
88 {
89    fprintf(stderr,
90       "\n\nbzip2/libbzip2, v0.9.0c: internal error number %d.\n"
91       "This is a bug in bzip2/libbzip2, v0.9.0c.  Please report\n"
92       "it to me at: jseward@acm.org.  If this happened when\n"
93       "you were using some program which uses libbzip2 as a\n"
94       "component, you should also report this bug to the author(s)\n"
95       "of that program.  Please make an effort to report this bug;\n"
96       "timely and accurate bug reports eventually lead to higher\n"
97       "quality software.  Thx.  Julian Seward, 18 October 1998.\n\n",
98       errcode
99    );
100    exit(3);
101 }
102 #endif
103 
104 
105 /*---------------------------------------------------*/
106 static
default_bzalloc(void * opaque,Int32 items,Int32 size)107 void* default_bzalloc ( void* opaque, Int32 items, Int32 size )
108 {
109    void* v = malloc ( items * size );
110    return v;
111 }
112 
113 static
default_bzfree(void * opaque,void * addr)114 void default_bzfree ( void* opaque, void* addr )
115 {
116    if (addr != NULL) free ( addr );
117 }
118 
119 
120 /*---------------------------------------------------*/
121 static
prepare_new_block(EState * s)122 void prepare_new_block ( EState* s )
123 {
124    Int32 i;
125    s->nblock = 0;
126    s->numZ = 0;
127    s->state_out_pos = 0;
128    BZ_INITIALISE_CRC ( s->blockCRC );
129    for (i = 0; i < 256; i++) s->inUse[i] = False;
130    s->blockNo++;
131 }
132 
133 
134 /*---------------------------------------------------*/
135 static
init_RL(EState * s)136 void init_RL ( EState* s )
137 {
138    s->state_in_ch  = 256;
139    s->state_in_len = 0;
140 }
141 
142 
143 static
isempty_RL(EState * s)144 Bool isempty_RL ( EState* s )
145 {
146    if (s->state_in_ch < 256 && s->state_in_len > 0)
147       return False; else
148       return True;
149 }
150 
151 
152 /*---------------------------------------------------*/
BZ_API(bzCompressInit)153 int BZ_API(bzCompressInit)
154                     ( bz_stream* strm,
155                      int        blockSize100k,
156                      int        verbosity,
157                      int        workFactor )
158 {
159    Int32   n;
160    EState* s;
161 
162    if (strm == NULL ||
163        blockSize100k < 1 || blockSize100k > 9 ||
164        workFactor < 0 || workFactor > 250)
165      return BZ_PARAM_ERROR;
166 
167    if (workFactor == 0) workFactor = 30;
168    if (strm->bzalloc == NULL) strm->bzalloc = default_bzalloc;
169    if (strm->bzfree == NULL) strm->bzfree = default_bzfree;
170 
171    s = BZALLOC( sizeof(EState) );
172    if (s == NULL) return BZ_MEM_ERROR;
173    s->strm = strm;
174 
175    s->block    = NULL;
176    s->quadrant = NULL;
177    s->zptr     = NULL;
178    s->ftab     = NULL;
179 
180    n           = 100000 * blockSize100k;
181    s->block    = BZALLOC( (n + BZ_NUM_OVERSHOOT_BYTES) * sizeof(UChar) );
182    s->quadrant = BZALLOC( (n + BZ_NUM_OVERSHOOT_BYTES) * sizeof(Int16) );
183    s->zptr     = BZALLOC( n                            * sizeof(Int32) );
184    s->ftab     = BZALLOC( 65537                        * sizeof(Int32) );
185 
186    if (s->block == NULL || s->quadrant == NULL ||
187        s->zptr == NULL  || s->ftab == NULL) {
188       if (s->block    != NULL) BZFREE(s->block);
189       if (s->quadrant != NULL) BZFREE(s->quadrant);
190       if (s->zptr     != NULL) BZFREE(s->zptr);
191       if (s->ftab     != NULL) BZFREE(s->ftab);
192       if (s           != NULL) BZFREE(s);
193       return BZ_MEM_ERROR;
194    }
195 
196    s->szptr = (UInt16*)(s->zptr);
197 
198    s->blockNo           = 0;
199    s->state             = BZ_S_INPUT;
200    s->mode              = BZ_M_RUNNING;
201    s->combinedCRC       = 0;
202    s->blockSize100k     = blockSize100k;
203    s->nblockMAX         = 100000 * blockSize100k - 19;
204    s->verbosity         = verbosity;
205    s->workFactor        = workFactor;
206    s->nBlocksRandomised = 0;
207    strm->state          = s;
208    strm->total_in       = 0;
209    strm->total_out      = 0;
210    init_RL ( s );
211    prepare_new_block ( s );
212    return BZ_OK;
213 }
214 
215 
216 /*---------------------------------------------------*/
217 static
add_pair_to_block(EState * s)218 void add_pair_to_block ( EState* s )
219 {
220    Int32 i;
221    UChar ch = (UChar)(s->state_in_ch);
222    for (i = 0; i < s->state_in_len; i++) {
223       BZ_UPDATE_CRC( s->blockCRC, ch );
224    }
225    s->inUse[s->state_in_ch] = True;
226    switch (s->state_in_len) {
227       case 1:
228          s->block[s->nblock] = (UChar)ch; s->nblock++;
229          break;
230       case 2:
231          s->block[s->nblock] = (UChar)ch; s->nblock++;
232          s->block[s->nblock] = (UChar)ch; s->nblock++;
233          break;
234       case 3:
235          s->block[s->nblock] = (UChar)ch; s->nblock++;
236          s->block[s->nblock] = (UChar)ch; s->nblock++;
237          s->block[s->nblock] = (UChar)ch; s->nblock++;
238          break;
239       default:
240          s->inUse[s->state_in_len-4] = True;
241          s->block[s->nblock] = (UChar)ch; s->nblock++;
242          s->block[s->nblock] = (UChar)ch; s->nblock++;
243          s->block[s->nblock] = (UChar)ch; s->nblock++;
244          s->block[s->nblock] = (UChar)ch; s->nblock++;
245          s->block[s->nblock] = (UChar)(s->state_in_len-4);
246          s->nblock++;
247          break;
248    }
249 }
250 
251 
252 /*---------------------------------------------------*/
253 static
flush_RL(EState * s)254 void flush_RL ( EState* s )
255 {
256    if (s->state_in_ch < 256) add_pair_to_block ( s );
257    init_RL ( s );
258 }
259 
260 
261 /*---------------------------------------------------*/
262 #define ADD_CHAR_TO_BLOCK(zs,zchh0)               \
263 {                                                 \
264    UInt32 zchh = (UInt32)(zchh0);                 \
265    /*-- fast track the common case --*/           \
266    if (zchh != zs->state_in_ch &&                 \
267        zs->state_in_len == 1) {                   \
268       UChar ch = (UChar)(zs->state_in_ch);        \
269       BZ_UPDATE_CRC( zs->blockCRC, ch );          \
270       zs->inUse[zs->state_in_ch] = True;          \
271       zs->block[zs->nblock] = (UChar)ch;          \
272       zs->nblock++;                               \
273       zs->state_in_ch = zchh;                     \
274    }                                              \
275    else                                           \
276    /*-- general, uncommon cases --*/              \
277    if (zchh != zs->state_in_ch ||                 \
278       zs->state_in_len == 255) {                  \
279       if (zs->state_in_ch < 256)                  \
280          add_pair_to_block ( zs );                \
281       zs->state_in_ch = zchh;                     \
282       zs->state_in_len = 1;                       \
283    } else {                                       \
284       zs->state_in_len++;                         \
285    }                                              \
286 }
287 
288 
289 /*---------------------------------------------------*/
290 static
copy_input_until_stop(EState * s)291 Bool copy_input_until_stop ( EState* s )
292 {
293    Bool progress_in = False;
294 
295    if (s->mode == BZ_M_RUNNING) {
296 
297       /*-- fast track the common case --*/
298       while (True) {
299          /*-- block full? --*/
300          if (s->nblock >= s->nblockMAX) break;
301          /*-- no input? --*/
302          if (s->strm->avail_in == 0) break;
303          progress_in = True;
304          ADD_CHAR_TO_BLOCK ( s, (UInt32)(*((UChar*)(s->strm->next_in))) );
305          s->strm->next_in++;
306          s->strm->avail_in--;
307          s->strm->total_in++;
308       }
309 
310    } else {
311 
312       /*-- general, uncommon case --*/
313       while (True) {
314          /*-- block full? --*/
315          if (s->nblock >= s->nblockMAX) break;
316          /*-- no input? --*/
317          if (s->strm->avail_in == 0) break;
318          /*-- flush/finish end? --*/
319          if (s->avail_in_expect == 0) break;
320          progress_in = True;
321          ADD_CHAR_TO_BLOCK ( s, (UInt32)(*((UChar*)(s->strm->next_in))) );
322          s->strm->next_in++;
323          s->strm->avail_in--;
324          s->strm->total_in++;
325          s->avail_in_expect--;
326       }
327    }
328    return progress_in;
329 }
330 
331 
332 /*---------------------------------------------------*/
333 static
copy_output_until_stop(EState * s)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) = ((UChar*)(s->quadrant))[s->state_out_pos];
348       s->state_out_pos++;
349       s->strm->avail_out--;
350       s->strm->next_out++;
351       s->strm->total_out++;
352 
353    }
354 
355    return progress_out;
356 }
357 
358 
359 /*---------------------------------------------------*/
360 static
handle_compress(bz_stream * strm)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             compressBlock ( s, s->mode == BZ_M_FINISHING );
387             s->state = BZ_S_OUTPUT;
388          }
389          else
390          if (s->nblock >= s->nblockMAX) {
391             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 /*---------------------------------------------------*/
BZ_API(bzCompress)407 int BZ_API(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) return BZ_SEQUENCE_ERROR;
445          progress = handle_compress ( strm );
446          if (s->avail_in_expect > 0 || !isempty_RL(s) ||
447              s->state_out_pos < s->numZ) return BZ_FLUSH_OK;
448          s->mode = BZ_M_RUNNING;
449          return BZ_RUN_OK;
450 
451       case BZ_M_FINISHING:
452          if (action != BZ_FINISH) return BZ_SEQUENCE_ERROR;
453          if (s->avail_in_expect != s->strm->avail_in) return BZ_SEQUENCE_ERROR;
454          progress = handle_compress ( strm );
455          if (!progress) return BZ_SEQUENCE_ERROR;
456          if (s->avail_in_expect > 0 || !isempty_RL(s) ||
457              s->state_out_pos < s->numZ) return BZ_FINISH_OK;
458          s->mode = BZ_M_IDLE;
459          return BZ_STREAM_END;
460    }
461    return BZ_OK; /*--not reached--*/
462 }
463 
464 
465 /*---------------------------------------------------*/
BZ_API(bzCompressEnd)466 int BZ_API(bzCompressEnd)  ( bz_stream *strm )
467 {
468    EState* s;
469    if (strm == NULL) return BZ_PARAM_ERROR;
470    s = strm->state;
471    if (s == NULL) return BZ_PARAM_ERROR;
472    if (s->strm != strm) return BZ_PARAM_ERROR;
473 
474    if (s->block    != NULL) BZFREE(s->block);
475    if (s->quadrant != NULL) BZFREE(s->quadrant);
476    if (s->zptr     != NULL) BZFREE(s->zptr);
477    if (s->ftab     != NULL) BZFREE(s->ftab);
478    BZFREE(strm->state);
479 
480    strm->state = NULL;
481 
482    return BZ_OK;
483 }
484 
485 
486 /*---------------------------------------------------*/
487 /*--- Decompression stuff                         ---*/
488 /*---------------------------------------------------*/
489 
490 /*---------------------------------------------------*/
BZ_API(bzDecompressInit)491 int BZ_API(bzDecompressInit)
492                      ( bz_stream* strm,
493                        int        verbosity,
494                        int        small )
495 {
496    DState* s;
497 
498    if (strm == NULL) return BZ_PARAM_ERROR;
499    if (small != 0 && small != 1) return BZ_PARAM_ERROR;
500    if (verbosity < 0 || verbosity > 4) return BZ_PARAM_ERROR;
501 
502    if (strm->bzalloc == NULL) strm->bzalloc = default_bzalloc;
503    if (strm->bzfree == NULL) strm->bzfree = default_bzfree;
504 
505    s = BZALLOC( sizeof(DState) );
506    if (s == NULL) return BZ_MEM_ERROR;
507    s->strm                  = strm;
508    strm->state              = s;
509    s->state                 = BZ_X_MAGIC_1;
510    s->bsLive                = 0;
511    s->bsBuff                = 0;
512    s->calculatedCombinedCRC = 0;
513    strm->total_in           = 0;
514    strm->total_out          = 0;
515    s->smallDecompress       = (Bool)small;
516    s->ll4                   = NULL;
517    s->ll16                  = NULL;
518    s->tt                    = NULL;
519    s->currBlockNo           = 0;
520    s->verbosity             = verbosity;
521 
522    return BZ_OK;
523 }
524 
525 
526 /*---------------------------------------------------*/
527 static
unRLE_obuf_to_output_FAST(DState * s)528 void unRLE_obuf_to_output_FAST ( DState* s )
529 {
530    UChar k1;
531 
532    if (s->blockRandomised) {
533 
534       while (True) {
535          /* try to finish existing run */
536          while (True) {
537             if (s->strm->avail_out == 0) return;
538             if (s->state_out_len == 0) break;
539             *( (UChar*)(s->strm->next_out) ) = s->state_out_ch;
540             BZ_UPDATE_CRC ( s->calculatedBlockCRC, s->state_out_ch );
541             s->state_out_len--;
542             s->strm->next_out++;
543             s->strm->avail_out--;
544             s->strm->total_out++;
545          }
546 
547          /* can a new run be started? */
548          if (s->nblock_used == s->save_nblock+1) return;
549 
550 
551          s->state_out_len = 1;
552          s->state_out_ch = s->k0;
553          BZ_GET_FAST(k1); BZ_RAND_UPD_MASK;
554          k1 ^= BZ_RAND_MASK; s->nblock_used++;
555          if (s->nblock_used == s->save_nblock+1) continue;
556          if (k1 != s->k0) { s->k0 = k1; continue; };
557 
558          s->state_out_len = 2;
559          BZ_GET_FAST(k1); BZ_RAND_UPD_MASK;
560          k1 ^= BZ_RAND_MASK; s->nblock_used++;
561          if (s->nblock_used == s->save_nblock+1) continue;
562          if (k1 != s->k0) { s->k0 = k1; continue; };
563 
564          s->state_out_len = 3;
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          BZ_GET_FAST(k1); BZ_RAND_UPD_MASK;
571          k1 ^= BZ_RAND_MASK; s->nblock_used++;
572          s->state_out_len = ((Int32)k1) + 4;
573          BZ_GET_FAST(s->k0); BZ_RAND_UPD_MASK;
574          s->k0 ^= BZ_RAND_MASK; s->nblock_used++;
575       }
576 
577    } else {
578 
579       /* restore */
580       UInt32        c_calculatedBlockCRC = s->calculatedBlockCRC;
581       UChar         c_state_out_ch       = s->state_out_ch;
582       Int32         c_state_out_len      = s->state_out_len;
583       Int32         c_nblock_used        = s->nblock_used;
584       Int32         c_k0                 = s->k0;
585       UInt32*       c_tt                 = s->tt;
586       UInt32        c_tPos               = s->tPos;
587       char*         cs_next_out          = s->strm->next_out;
588       unsigned int  cs_avail_out         = s->strm->avail_out;
589       /* end restore */
590 
591       UInt32 avail_out_INIT = cs_avail_out;
592       Int32  s_save_nblockPP = s->save_nblock+1;
593 
594       while (True) {
595 
596          /* try to finish existing run */
597          if (c_state_out_len > 0) {
598             while (True) {
599                if (cs_avail_out == 0) goto return_notr;
600                if (c_state_out_len == 1) break;
601                *( (UChar*)(cs_next_out) ) = c_state_out_ch;
602                BZ_UPDATE_CRC ( c_calculatedBlockCRC, c_state_out_ch );
603                c_state_out_len--;
604                cs_next_out++;
605                cs_avail_out--;
606             }
607             s_state_out_len_eq_one:
608             {
609                if (cs_avail_out == 0) {
610                   c_state_out_len = 1; goto return_notr;
611                };
612                *( (UChar*)(cs_next_out) ) = c_state_out_ch;
613                BZ_UPDATE_CRC ( c_calculatedBlockCRC, c_state_out_ch );
614                cs_next_out++;
615                cs_avail_out--;
616             }
617          }
618          /* can a new run be started? */
619          if (c_nblock_used == s_save_nblockPP) {
620             c_state_out_len = 0; goto return_notr;
621          };
622          c_state_out_ch = c_k0;
623          BZ_GET_FAST_C(k1); c_nblock_used++;
624          if (k1 != c_k0) {
625             c_k0 = k1; goto s_state_out_len_eq_one;
626          };
627          if (c_nblock_used == s_save_nblockPP)
628             goto s_state_out_len_eq_one;
629 
630          c_state_out_len = 2;
631          BZ_GET_FAST_C(k1); c_nblock_used++;
632          if (c_nblock_used == s_save_nblockPP) continue;
633          if (k1 != c_k0) { c_k0 = k1; continue; };
634 
635          c_state_out_len = 3;
636          BZ_GET_FAST_C(k1); c_nblock_used++;
637          if (c_nblock_used == s_save_nblockPP) continue;
638          if (k1 != c_k0) { c_k0 = k1; continue; };
639 
640          BZ_GET_FAST_C(k1); c_nblock_used++;
641          c_state_out_len = ((Int32)k1) + 4;
642          BZ_GET_FAST_C(c_k0); c_nblock_used++;
643       }
644 
645       return_notr:
646       s->strm->total_out += (avail_out_INIT - cs_avail_out);
647 
648       /* save */
649       s->calculatedBlockCRC = c_calculatedBlockCRC;
650       s->state_out_ch       = c_state_out_ch;
651       s->state_out_len      = c_state_out_len;
652       s->nblock_used        = c_nblock_used;
653       s->k0                 = c_k0;
654       s->tt                 = c_tt;
655       s->tPos               = c_tPos;
656       s->strm->next_out     = cs_next_out;
657       s->strm->avail_out    = cs_avail_out;
658       /* end save */
659    }
660 }
661 
662 
663 
664 /*---------------------------------------------------*/
indexIntoF(Int32 indx,Int32 * cftab)665 __inline__ Int32 indexIntoF ( Int32 indx, Int32 *cftab )
666 {
667    Int32 nb, na, mid;
668    nb = 0;
669    na = 256;
670    do {
671       mid = (nb + na) >> 1;
672       if (indx >= cftab[mid]) nb = mid; else na = mid;
673    }
674    while (na - nb != 1);
675    return nb;
676 }
677 
678 
679 /*---------------------------------------------------*/
680 static
unRLE_obuf_to_output_SMALL(DState * s)681 void unRLE_obuf_to_output_SMALL ( DState* s )
682 {
683    UChar k1;
684 
685    if (s->blockRandomised) {
686 
687       while (True) {
688          /* try to finish existing run */
689          while (True) {
690             if (s->strm->avail_out == 0) return;
691             if (s->state_out_len == 0) break;
692             *( (UChar*)(s->strm->next_out) ) = s->state_out_ch;
693             BZ_UPDATE_CRC ( s->calculatedBlockCRC, s->state_out_ch );
694             s->state_out_len--;
695             s->strm->next_out++;
696             s->strm->avail_out--;
697             s->strm->total_out++;
698          }
699 
700          /* can a new run be started? */
701          if (s->nblock_used == s->save_nblock+1) return;
702 
703 
704          s->state_out_len = 1;
705          s->state_out_ch = s->k0;
706          BZ_GET_SMALL(k1); BZ_RAND_UPD_MASK;
707          k1 ^= BZ_RAND_MASK; s->nblock_used++;
708          if (s->nblock_used == s->save_nblock+1) continue;
709          if (k1 != s->k0) { s->k0 = k1; continue; };
710 
711          s->state_out_len = 2;
712          BZ_GET_SMALL(k1); BZ_RAND_UPD_MASK;
713          k1 ^= BZ_RAND_MASK; s->nblock_used++;
714          if (s->nblock_used == s->save_nblock+1) continue;
715          if (k1 != s->k0) { s->k0 = k1; continue; };
716 
717          s->state_out_len = 3;
718          BZ_GET_SMALL(k1); BZ_RAND_UPD_MASK;
719          k1 ^= BZ_RAND_MASK; s->nblock_used++;
720          if (s->nblock_used == s->save_nblock+1) continue;
721          if (k1 != s->k0) { s->k0 = k1; continue; };
722 
723          BZ_GET_SMALL(k1); BZ_RAND_UPD_MASK;
724          k1 ^= BZ_RAND_MASK; s->nblock_used++;
725          s->state_out_len = ((Int32)k1) + 4;
726          BZ_GET_SMALL(s->k0); BZ_RAND_UPD_MASK;
727          s->k0 ^= BZ_RAND_MASK; s->nblock_used++;
728       }
729 
730    } else {
731 
732       while (True) {
733          /* try to finish existing run */
734          while (True) {
735             if (s->strm->avail_out == 0) return;
736             if (s->state_out_len == 0) break;
737             *( (UChar*)(s->strm->next_out) ) = s->state_out_ch;
738             BZ_UPDATE_CRC ( s->calculatedBlockCRC, s->state_out_ch );
739             s->state_out_len--;
740             s->strm->next_out++;
741             s->strm->avail_out--;
742             s->strm->total_out++;
743          }
744 
745          /* can a new run be started? */
746          if (s->nblock_used == s->save_nblock+1) return;
747 
748          s->state_out_len = 1;
749          s->state_out_ch = s->k0;
750          BZ_GET_SMALL(k1); s->nblock_used++;
751          if (s->nblock_used == s->save_nblock+1) continue;
752          if (k1 != s->k0) { s->k0 = k1; continue; };
753 
754          s->state_out_len = 2;
755          BZ_GET_SMALL(k1); s->nblock_used++;
756          if (s->nblock_used == s->save_nblock+1) continue;
757          if (k1 != s->k0) { s->k0 = k1; continue; };
758 
759          s->state_out_len = 3;
760          BZ_GET_SMALL(k1); s->nblock_used++;
761          if (s->nblock_used == s->save_nblock+1) continue;
762          if (k1 != s->k0) { s->k0 = k1; continue; };
763 
764          BZ_GET_SMALL(k1); s->nblock_used++;
765          s->state_out_len = ((Int32)k1) + 4;
766          BZ_GET_SMALL(s->k0); s->nblock_used++;
767       }
768 
769    }
770 }
771 
772 
773 /*---------------------------------------------------*/
BZ_API(bzDecompress)774 int BZ_API(bzDecompress) ( bz_stream *strm )
775 {
776    DState* s;
777    if (strm == NULL) return BZ_PARAM_ERROR;
778    s = strm->state;
779    if (s == NULL) return BZ_PARAM_ERROR;
780    if (s->strm != strm) return BZ_PARAM_ERROR;
781 
782    while (True) {
783       if (s->state == BZ_X_IDLE) return BZ_SEQUENCE_ERROR;
784       if (s->state == BZ_X_OUTPUT) {
785          if (s->smallDecompress)
786             unRLE_obuf_to_output_SMALL ( s ); else
787             unRLE_obuf_to_output_FAST  ( s );
788          if (s->nblock_used == s->save_nblock+1 && s->state_out_len == 0) {
789             BZ_FINALISE_CRC ( s->calculatedBlockCRC );
790             if (s->verbosity >= 3)
791                VPrintf2 ( " {0x%x, 0x%x}", s->storedBlockCRC,
792                           s->calculatedBlockCRC );
793             if (s->verbosity >= 2) VPrintf0 ( "]" );
794             if (s->calculatedBlockCRC != s->storedBlockCRC)
795                return BZ_DATA_ERROR;
796             s->calculatedCombinedCRC
797                = (s->calculatedCombinedCRC << 1) |
798                     (s->calculatedCombinedCRC >> 31);
799             s->calculatedCombinedCRC ^= s->calculatedBlockCRC;
800             s->state = BZ_X_BLKHDR_1;
801          } else {
802             return BZ_OK;
803          }
804       }
805       if (s->state >= BZ_X_MAGIC_1) {
806          Int32 r = decompress ( s );
807          if (r == BZ_STREAM_END) {
808             if (s->verbosity >= 3)
809                VPrintf2 ( "\n    combined CRCs: stored = 0x%x, computed = 0x%x",
810                           s->storedCombinedCRC, s->calculatedCombinedCRC );
811             if (s->calculatedCombinedCRC != s->storedCombinedCRC)
812                return BZ_DATA_ERROR;
813             return r;
814          }
815          if (s->state != BZ_X_OUTPUT) return r;
816       }
817    }
818 
819    AssertH ( 0, 6001 );
820    /*notreached*/
821 }
822 
823 
824 /*---------------------------------------------------*/
BZ_API(bzDecompressEnd)825 int BZ_API(bzDecompressEnd)  ( bz_stream *strm )
826 {
827    DState* s;
828    if (strm == NULL) return BZ_PARAM_ERROR;
829    s = strm->state;
830    if (s == NULL) return BZ_PARAM_ERROR;
831    if (s->strm != strm) return BZ_PARAM_ERROR;
832 
833    if (s->tt   != NULL) BZFREE(s->tt);
834    if (s->ll16 != NULL) BZFREE(s->ll16);
835    if (s->ll4  != NULL) BZFREE(s->ll4);
836 
837    BZFREE(strm->state);
838    strm->state = NULL;
839 
840    return BZ_OK;
841 }
842 
843 
844 #ifndef BZ_NO_STDIO
845 /*---------------------------------------------------*/
846 /*--- File I/O stuff                              ---*/
847 /*---------------------------------------------------*/
848 
849 #define BZ_SETERR(eee)                    \
850 {                                         \
851    if (bzerror != NULL) *bzerror = eee;   \
852    if (bzf != NULL) bzf->lastErr = eee;   \
853 }
854 
855 typedef
856    struct {
857       FILE*     handle;
858       Char      buf[BZ_MAX_UNUSED];
859       Int32     bufN;
860       Bool      writing;
861       bz_stream strm;
862       Int32     lastErr;
863       Bool      initialisedOk;
864       Bool	noclose;
865    }
866    bzFile;
867 
868 
869 /*---------------------------------------------*/
myfeof(FILE * f)870 static Bool myfeof ( FILE* f )
871 {
872    Int32 c = fgetc ( f );
873    if (c == EOF) return True;
874    ungetc ( c, f );
875    return False;
876 }
877 
878 
879 /*---------------------------------------------------*/
BZ_API(bzWriteOpen)880 BZFILE* BZ_API(bzWriteOpen)
881                     ( int*  bzerror,
882                       FILE* f,
883                       int   blockSize100k,
884                       int   verbosity,
885                       int   workFactor )
886 {
887    Int32   ret;
888    bzFile* bzf = NULL;
889 
890    BZ_SETERR(BZ_OK);
891 
892    if (f == NULL ||
893        (blockSize100k < 1 || blockSize100k > 9) ||
894        (workFactor < 0 || workFactor > 250) ||
895        (verbosity < 0 || verbosity > 4))
896       { BZ_SETERR(BZ_PARAM_ERROR); return NULL; };
897 
898    if (ferror(f))
899       { BZ_SETERR(BZ_IO_ERROR); return NULL; };
900 
901    bzf = malloc ( sizeof(bzFile) );
902    if (bzf == NULL)
903       { BZ_SETERR(BZ_MEM_ERROR); return NULL; };
904 
905    BZ_SETERR(BZ_OK);
906    bzf->initialisedOk = False;
907    bzf->bufN          = 0;
908    bzf->handle        = f;
909    bzf->writing       = True;
910    bzf->strm.bzalloc  = NULL;
911    bzf->strm.bzfree   = NULL;
912    bzf->strm.opaque   = NULL;
913 
914    if (workFactor == 0) workFactor = 30;
915    ret = bzCompressInit ( &(bzf->strm), blockSize100k,
916                           verbosity, workFactor );
917    if (ret != BZ_OK)
918       { BZ_SETERR(ret); free(bzf); return NULL; };
919 
920    bzf->strm.avail_in = 0;
921    bzf->initialisedOk = True;
922    return bzf;
923 }
924 
925 
926 
927 /*---------------------------------------------------*/
BZ_API(bzWrite)928 void BZ_API(bzWrite)
929              ( int*    bzerror,
930                BZFILE* b,
931                void*   buf,
932                int     len )
933 {
934    Int32 n, n2, ret;
935    bzFile* bzf = (bzFile*)b;
936 
937    BZ_SETERR(BZ_OK);
938    if (bzf == NULL || buf == NULL || len < 0)
939       { BZ_SETERR(BZ_PARAM_ERROR); return; };
940    if (!(bzf->writing))
941       { BZ_SETERR(BZ_SEQUENCE_ERROR); return; };
942    if (ferror(bzf->handle))
943       { BZ_SETERR(BZ_IO_ERROR); return; };
944 
945    if (len == 0)
946       { BZ_SETERR(BZ_OK); return; };
947 
948    bzf->strm.avail_in = len;
949    bzf->strm.next_in  = buf;
950 
951    while (True) {
952       bzf->strm.avail_out = BZ_MAX_UNUSED;
953       bzf->strm.next_out = bzf->buf;
954       ret = bzCompress ( &(bzf->strm), BZ_RUN );
955       if (ret != BZ_RUN_OK)
956          { BZ_SETERR(ret); return; };
957 
958       if (bzf->strm.avail_out < BZ_MAX_UNUSED) {
959          n = BZ_MAX_UNUSED - bzf->strm.avail_out;
960          n2 = fwrite ( (void*)(bzf->buf), sizeof(UChar),
961                        n, bzf->handle );
962          if (n != n2 || ferror(bzf->handle))
963             { BZ_SETERR(BZ_IO_ERROR); return; };
964       }
965 
966       if (bzf->strm.avail_in == 0)
967          { BZ_SETERR(BZ_OK); return; };
968    }
969 }
970 
971 
972 /*---------------------------------------------------*/
BZ_API(bzWriteClose)973 void BZ_API(bzWriteClose)
974                   ( int*          bzerror,
975                     BZFILE*       b,
976                     int           abandon,
977                     unsigned int* nbytes_in,
978                     unsigned int* nbytes_out )
979 {
980    Int32   n, n2, ret;
981    bzFile* bzf = (bzFile*)b;
982 
983    if (bzf == NULL)
984       { BZ_SETERR(BZ_OK); return; };
985    if (!(bzf->writing))
986       { BZ_SETERR(BZ_SEQUENCE_ERROR); return; };
987    if (ferror(bzf->handle))
988       { BZ_SETERR(BZ_IO_ERROR); return; };
989 
990    if (nbytes_in != NULL) *nbytes_in = 0;
991    if (nbytes_out != NULL) *nbytes_out = 0;
992 
993    if ((!abandon) && bzf->lastErr == BZ_OK) {
994       while (True) {
995          bzf->strm.avail_out = BZ_MAX_UNUSED;
996          bzf->strm.next_out = bzf->buf;
997          ret = bzCompress ( &(bzf->strm), BZ_FINISH );
998          if (ret != BZ_FINISH_OK && ret != BZ_STREAM_END)
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 (ret == BZ_STREAM_END) break;
1010       }
1011    }
1012 
1013    if ( !abandon && !ferror ( bzf->handle ) ) {
1014       fflush ( bzf->handle );
1015       if (ferror(bzf->handle))
1016          { BZ_SETERR(BZ_IO_ERROR); return; };
1017    }
1018 
1019    if (nbytes_in != NULL) *nbytes_in = bzf->strm.total_in;
1020    if (nbytes_out != NULL) *nbytes_out = bzf->strm.total_out;
1021 
1022    BZ_SETERR(BZ_OK);
1023    bzCompressEnd ( &(bzf->strm) );
1024    free ( bzf );
1025 }
1026 
1027 
1028 /*---------------------------------------------------*/
BZ_API(bzReadOpen)1029 BZFILE* BZ_API(bzReadOpen)
1030                    ( int*  bzerror,
1031                      FILE* f,
1032                      int   verbosity,
1033                      int   small,
1034                      void* unused,
1035                      int   nUnused )
1036 {
1037    bzFile* bzf = NULL;
1038    int     ret;
1039 
1040    BZ_SETERR(BZ_OK);
1041 
1042    if (f == NULL ||
1043        (small != 0 && small != 1) ||
1044        (verbosity < 0 || verbosity > 4) ||
1045        (unused == NULL && nUnused != 0) ||
1046        (unused != NULL && (nUnused < 0 || nUnused > BZ_MAX_UNUSED)))
1047       { BZ_SETERR(BZ_PARAM_ERROR); return NULL; };
1048 
1049    if (ferror(f))
1050       { BZ_SETERR(BZ_IO_ERROR); return NULL; };
1051 
1052    bzf = malloc ( sizeof(bzFile) );
1053    if (bzf == NULL)
1054       { BZ_SETERR(BZ_MEM_ERROR); return NULL; };
1055 
1056    BZ_SETERR(BZ_OK);
1057 
1058    bzf->initialisedOk = False;
1059    bzf->handle        = f;
1060    bzf->bufN          = 0;
1061    bzf->writing       = False;
1062    bzf->strm.bzalloc  = NULL;
1063    bzf->strm.bzfree   = NULL;
1064    bzf->strm.opaque   = NULL;
1065 
1066    while (nUnused > 0) {
1067       bzf->buf[bzf->bufN] = *((UChar*)(unused)); bzf->bufN++;
1068       unused = ((void*)( 1 + ((UChar*)(unused))  ));
1069       nUnused--;
1070    }
1071 
1072    ret = bzDecompressInit ( &(bzf->strm), verbosity, small );
1073    if (ret != BZ_OK)
1074       { BZ_SETERR(ret); free(bzf); return NULL; };
1075 
1076    bzf->strm.avail_in = bzf->bufN;
1077    bzf->strm.next_in  = bzf->buf;
1078 
1079    bzf->initialisedOk = True;
1080    return bzf;
1081 }
1082 
1083 
1084 /*---------------------------------------------------*/
BZ_API(bzReadClose)1085 void BZ_API(bzReadClose) ( int *bzerror, BZFILE *b )
1086 {
1087    bzFile* bzf = (bzFile*)b;
1088 
1089    BZ_SETERR(BZ_OK);
1090    if (bzf == NULL)
1091       { BZ_SETERR(BZ_OK); return; };
1092 
1093    if (bzf->writing)
1094       { BZ_SETERR(BZ_SEQUENCE_ERROR); return; };
1095 
1096    if (bzf->initialisedOk)
1097       (void)bzDecompressEnd ( &(bzf->strm) );
1098    free ( bzf );
1099 }
1100 
1101 
1102 /*---------------------------------------------------*/
BZ_API(bzRead)1103 int BZ_API(bzRead)
1104            ( int*    bzerror,
1105              BZFILE* b,
1106              void*   buf,
1107              int     len )
1108 {
1109    Int32   n, ret;
1110    bzFile* bzf = (bzFile*)b;
1111 
1112    BZ_SETERR(BZ_OK);
1113 
1114    if (bzf == NULL || buf == NULL || len < 0)
1115       { BZ_SETERR(BZ_PARAM_ERROR); return 0; };
1116 
1117    if (bzf->writing)
1118       { BZ_SETERR(BZ_SEQUENCE_ERROR); return 0; };
1119 
1120    if (len == 0)
1121       { BZ_SETERR(BZ_OK); return 0; };
1122 
1123    bzf->strm.avail_out = len;
1124    bzf->strm.next_out = buf;
1125 
1126    while (True) {
1127 
1128       if (ferror(bzf->handle))
1129          { BZ_SETERR(BZ_IO_ERROR); return 0; };
1130 
1131       if (bzf->strm.avail_in == 0 && !myfeof(bzf->handle)) {
1132          n = fread ( bzf->buf, sizeof(UChar),
1133                      BZ_MAX_UNUSED, bzf->handle );
1134          if (ferror(bzf->handle))
1135             { BZ_SETERR(BZ_IO_ERROR); return 0; };
1136          bzf->bufN = n;
1137          bzf->strm.avail_in = bzf->bufN;
1138          bzf->strm.next_in = bzf->buf;
1139       }
1140 
1141       ret = bzDecompress ( &(bzf->strm) );
1142 
1143       if (ret != BZ_OK && ret != BZ_STREAM_END)
1144          { BZ_SETERR(ret); return 0; };
1145 
1146       if (ret == BZ_OK && myfeof(bzf->handle) &&
1147           bzf->strm.avail_in == 0 && bzf->strm.avail_out > 0)
1148          { BZ_SETERR(BZ_UNEXPECTED_EOF); return 0; };
1149 
1150       if (ret == BZ_STREAM_END)
1151          { BZ_SETERR(BZ_STREAM_END);
1152            return len - bzf->strm.avail_out; };
1153       if (bzf->strm.avail_out == 0)
1154          { BZ_SETERR(BZ_OK); return len; };
1155 
1156    }
1157 
1158    return 0; /*not reached*/
1159 }
1160 
1161 
1162 /*---------------------------------------------------*/
BZ_API(bzReadGetUnused)1163 void BZ_API(bzReadGetUnused)
1164                      ( int*    bzerror,
1165                        BZFILE* b,
1166                        void*   vUnused,
1167                        int*    nUnused )
1168 {
1169    void** unused = (void*)vUnused;
1170    bzFile* bzf = (bzFile*)b;
1171    if (bzf == NULL)
1172       { BZ_SETERR(BZ_PARAM_ERROR); return; };
1173    if (bzf->lastErr != BZ_STREAM_END)
1174       { BZ_SETERR(BZ_SEQUENCE_ERROR); return; };
1175    if (unused == NULL || nUnused == NULL)
1176       { BZ_SETERR(BZ_PARAM_ERROR); return; };
1177 
1178    BZ_SETERR(BZ_OK);
1179    *nUnused = bzf->strm.avail_in;
1180    *unused = bzf->strm.next_in;
1181 }
1182 #endif
1183 
1184 
1185 /*---------------------------------------------------*/
1186 /*--- Misc convenience stuff                      ---*/
1187 /*---------------------------------------------------*/
1188 
1189 /*---------------------------------------------------*/
BZ_API(bzBuffToBuffCompress)1190 int BZ_API(bzBuffToBuffCompress)
1191                          ( char*         dest,
1192                            unsigned int* destLen,
1193                            char*         source,
1194                            unsigned int  sourceLen,
1195                            int           blockSize100k,
1196                            int           verbosity,
1197                            int           workFactor )
1198 {
1199    bz_stream strm;
1200    int ret;
1201 
1202    if (dest == NULL || destLen == NULL ||
1203        source == NULL ||
1204        blockSize100k < 1 || blockSize100k > 9 ||
1205        verbosity < 0 || verbosity > 4 ||
1206        workFactor < 0 || workFactor > 250)
1207       return BZ_PARAM_ERROR;
1208 
1209    if (workFactor == 0) workFactor = 30;
1210    strm.bzalloc = NULL;
1211    strm.bzfree = NULL;
1212    strm.opaque = NULL;
1213    ret = bzCompressInit ( &strm, blockSize100k,
1214                           verbosity, workFactor );
1215    if (ret != BZ_OK) return ret;
1216 
1217    strm.next_in = source;
1218    strm.next_out = dest;
1219    strm.avail_in = sourceLen;
1220    strm.avail_out = *destLen;
1221 
1222    ret = bzCompress ( &strm, BZ_FINISH );
1223    if (ret == BZ_FINISH_OK) goto output_overflow;
1224    if (ret != BZ_STREAM_END) goto errhandler;
1225 
1226    /* normal termination */
1227    *destLen -= strm.avail_out;
1228    bzCompressEnd ( &strm );
1229    return BZ_OK;
1230 
1231    output_overflow:
1232    bzCompressEnd ( &strm );
1233    return BZ_OUTBUFF_FULL;
1234 
1235    errhandler:
1236    bzCompressEnd ( &strm );
1237    return ret;
1238 }
1239 
1240 
1241 /*---------------------------------------------------*/
BZ_API(bzBuffToBuffDecompress)1242 int BZ_API(bzBuffToBuffDecompress)
1243                            ( char*         dest,
1244                              unsigned int* destLen,
1245                              char*         source,
1246                              unsigned int  sourceLen,
1247                              int           small,
1248                              int           verbosity )
1249 {
1250    bz_stream strm;
1251    int ret;
1252 
1253    if (dest == NULL || destLen == NULL ||
1254        source == NULL ||
1255        (small != 0 && small != 1) ||
1256        verbosity < 0 || verbosity > 4)
1257           return BZ_PARAM_ERROR;
1258 
1259    strm.bzalloc = NULL;
1260    strm.bzfree = NULL;
1261    strm.opaque = NULL;
1262    ret = bzDecompressInit ( &strm, verbosity, small );
1263    if (ret != BZ_OK) return ret;
1264 
1265    strm.next_in = source;
1266    strm.next_out = dest;
1267    strm.avail_in = sourceLen;
1268    strm.avail_out = *destLen;
1269 
1270    ret = bzDecompress ( &strm );
1271    if (ret == BZ_OK) goto output_overflow_or_eof;
1272    if (ret != BZ_STREAM_END) goto errhandler;
1273 
1274    /* normal termination */
1275    *destLen -= strm.avail_out;
1276    bzDecompressEnd ( &strm );
1277    return BZ_OK;
1278 
1279    output_overflow_or_eof:
1280    if (strm.avail_out > 0) {
1281       bzDecompressEnd ( &strm );
1282       return BZ_UNEXPECTED_EOF;
1283    } else {
1284       bzDecompressEnd ( &strm );
1285       return BZ_OUTBUFF_FULL;
1286    };
1287 
1288    errhandler:
1289    bzDecompressEnd ( &strm );
1290    return BZ_SEQUENCE_ERROR;
1291 }
1292 
1293 
1294 /*---------------------------------------------------*/
1295 /*--
1296    Code contributed by Yoshioka Tsuneo
1297    (QWF00133@niftyserve.or.jp/tsuneo-y@is.aist-nara.ac.jp),
1298    to support better zlib compatibility.
1299    This code is not _officially_ part of libbzip2 (yet);
1300    I haven't tested it, documented it, or considered the
1301    threading-safeness of it.
1302    If this code breaks, please contact both Yoshioka and me.
1303 --*/
1304 /*---------------------------------------------------*/
1305 
1306 /*---------------------------------------------------*/
1307 /*--
1308    return version like "0.9.0c".
1309 --*/
BZ_API(bzlibVersion)1310 const char * BZ_API(bzlibVersion)(void)
1311 {
1312    return BZ_VERSION;
1313 }
1314 
1315 
1316 #ifndef BZ_NO_STDIO
1317 /*---------------------------------------------------*/
1318 
1319 #if defined(_WIN32) && !_WINIX || defined(OS2) || defined(MSDOS)
1320 #   include <fcntl.h>
1321 #   include <io.h>
1322 #   ifdef _MSC_VER
1323 #      define SET_BINARY_MODE(file) _setmode(_fileno(file),O_BINARY)
1324 #   else
1325 #      define SET_BINARY_MODE(file) setmode(fileno(file),O_BINARY)
1326 #   endif
1327 #else
1328 #   define SET_BINARY_MODE(file)
1329 #endif
1330 static
bzopen_internal(const char * path,FILE * fp,int fd,const char * mode,const void * buf,unsigned int len)1331 BZFILE * bzopen_internal
1332                ( const char *path,   /* if !=0 */
1333 		 FILE *fp,	     /* if !=0 && path==0 */
1334                  int fd,             /* if path==0 && fp==0 */
1335                  const char *mode,
1336 		 const void* buf,
1337 		 unsigned int len)
1338 {
1339    int    bzerr;
1340    char   unused[BZ_MAX_UNUSED];
1341    char   mode2[10];
1342    int    blockSize100k = 9;
1343    int    writing       = 0;
1344    BZFILE *bzfp         = NULL;
1345    int    verbosity     = 0;
1346    int    workFactor    = 30;
1347    int    smallMode     = 0;
1348    int    nUnused       = 0;
1349    int    noClose	= 0;
1350 
1351    if(mode==NULL){return NULL;}
1352    while(*mode){
1353       switch(*mode){
1354       case 'r':
1355          writing = 0;break;
1356       case 'w':
1357          writing = 1;break;
1358       case 's':
1359          smallMode = 1;break;
1360       case 'o':
1361          noClose = 1;break;
1362       default:
1363          if(isdigit(*mode)){
1364             blockSize100k = 0;
1365             while(isdigit(*mode)){
1366                blockSize100k = blockSize100k*10 + *mode-'0';
1367                mode++;
1368             }
1369          }else{
1370             /* ignore */
1371          }
1372       }
1373       mode++;
1374    }
1375    strcpy(mode2, writing ? "w" : "r" );
1376    strcat(mode2,"b");   /* binary mode */
1377 
1378    if(path) {
1379       if(path[0]==0){
1380         fp = (writing ? stdout : stdin);
1381 	noClose = 1;
1382         SET_BINARY_MODE(fp);
1383       }else{
1384         fp = fopen(path,mode2);
1385       }
1386    }else if (fp==0) {
1387 #ifdef BZ_STRICT_ANSI
1388       fp = NULL;
1389 #else
1390       fp = fdopen(fd,mode2);
1391 #endif
1392    }
1393    if(fp==NULL){return NULL;}
1394 
1395    if(writing){
1396       bzfp = bzWriteOpen(&bzerr,fp,blockSize100k,verbosity,workFactor);
1397    }else{
1398       bzfp = bzReadOpen(&bzerr,fp,verbosity,smallMode,unused,nUnused);
1399    }
1400    if(bzfp==NULL){
1401       if(!noClose) fclose(fp);
1402       return NULL;
1403    }
1404    ((bzFile*)bzfp)->noclose = noClose;
1405    return bzfp;
1406 }
1407 
1408 
1409 /*---------------------------------------------------*/
1410 /*--
1411    open file for read or write.
1412       ex) bzopen("file","w9")
1413       case path="" or NULL => use stdin or stdout.
1414 --*/
BZ_API(bzopen)1415 BZFILE * BZ_API(bzopen)
1416                ( const char *path,
1417                  const char *mode )
1418 {
1419    return bzopen_internal(path,NULL,-1,mode,NULL,0);
1420 }
1421 
1422 
1423 /*---------------------------------------------------*/
BZ_API(bzfopen)1424 BZFILE * BZ_API(bzfopen)
1425                ( FILE *fp,
1426                  const char *mode )
1427 {
1428    return bzopen_internal(NULL,fp,-1,mode,NULL,0);
1429 }
1430 
1431 
1432 /*---------------------------------------------------*/
BZ_API(bzdopen)1433 BZFILE * BZ_API(bzdopen)
1434                ( int fd,
1435                  const char *mode )
1436 {
1437    return bzopen_internal(NULL,NULL,fd,mode,NULL,0);
1438 }
1439 
1440 /*---------------------------------------------------*/
BZ_API(bzbopen)1441 BZFILE * BZ_API(bzbopen)
1442                ( int          fd,
1443                  const char*  mode,
1444 		 const void*  buf,
1445 		 unsigned int len )
1446 {
1447    return bzopen_internal(NULL,NULL,fd,mode,buf,len);
1448 }
1449 
1450 /*---------------------------------------------------*/
BZ_API(bzread)1451 int BZ_API(bzread) (BZFILE* b, void* buf, int len )
1452 {
1453    int bzerr, nread;
1454    if (((bzFile*)b)->lastErr == BZ_STREAM_END) return 0;
1455    nread = bzRead(&bzerr,b,buf,len);
1456    if (bzerr == BZ_OK || bzerr == BZ_STREAM_END) {
1457       return nread;
1458    } else {
1459       return -1;
1460    }
1461 }
1462 
1463 
1464 /*---------------------------------------------------*/
BZ_API(bzwrite)1465 int BZ_API(bzwrite) (BZFILE* b, const void* buf, int len )
1466 {
1467    int bzerr;
1468 
1469    bzWrite(&bzerr,b,(void*)buf,len);
1470    if(bzerr == BZ_OK){
1471       return len;
1472    }else{
1473       return -1;
1474    }
1475 }
1476 
1477 
1478 /*---------------------------------------------------*/
BZ_API(bzflush)1479 int BZ_API(bzflush) (BZFILE *b)
1480 {
1481    Int32 n, n2, ret;
1482    bzFile* bzf = (bzFile*)b;
1483 
1484    if (bzf == NULL)
1485       return -1;
1486    if (!(bzf->writing))
1487       return 0;
1488    if (ferror(bzf->handle))
1489       return -1;
1490 
1491    do {
1492       bzf->strm.avail_out = BZ_MAX_UNUSED;
1493       bzf->strm.next_out = bzf->buf;
1494       ret = bzCompress ( &(bzf->strm), BZ_FLUSH );
1495       if (ret != BZ_FLUSH_OK && ret != BZ_RUN_OK)
1496 	 return -1;
1497       if (bzf->strm.avail_out < BZ_MAX_UNUSED) {
1498          n = BZ_MAX_UNUSED - bzf->strm.avail_out;
1499          n2 = fwrite ( (void*)(bzf->buf), sizeof(UChar), n, bzf->handle );
1500          if (n != n2 || ferror(bzf->handle))
1501             return -1;
1502       }
1503 
1504    } while (ret == BZ_FLUSH_OK);
1505    return 0;
1506 }
1507 
1508 
1509 /*---------------------------------------------------*/
BZ_API(bzclose)1510 int BZ_API(bzclose) (BZFILE* b)
1511 {
1512    int bzerr;
1513    FILE *fp = ((bzFile *)b)->handle;
1514 
1515    if(b==NULL){return -1;}
1516    if(((bzFile*)b)->writing){
1517       bzWriteClose(&bzerr,b,0,NULL,NULL);
1518       if(bzerr != BZ_OK){
1519          bzWriteClose(NULL,b,1,NULL,NULL);
1520 	 return -1;
1521       }
1522    }else{
1523       bzReadClose(&bzerr,b);
1524       if(bzerr != BZ_OK)
1525 	 return -1;
1526    }
1527    if(!((bzFile*)b)->noclose){
1528       return fclose(fp);
1529    }
1530    return 0;
1531 }
1532 
1533 
1534 /*---------------------------------------------------*/
1535 /*--
1536    return last error code
1537 --*/
1538 static char *bzerrorstrings[] = {
1539        "OK"
1540       ,"SEQUENCE_ERROR"
1541       ,"PARAM_ERROR"
1542       ,"MEM_ERROR"
1543       ,"DATA_ERROR"
1544       ,"DATA_ERROR_MAGIC"
1545       ,"IO_ERROR"
1546       ,"UNEXPECTED_EOF"
1547       ,"OUTBUFF_FULL"
1548       ,"???"   /* for future */
1549       ,"???"   /* for future */
1550       ,"???"   /* for future */
1551       ,"???"   /* for future */
1552       ,"???"   /* for future */
1553       ,"???"   /* for future */
1554 };
1555 
1556 
BZ_API(bzerror)1557 const char * BZ_API(bzerror) (BZFILE *b, int *errnum)
1558 {
1559    int err = ((bzFile *)b)->lastErr;
1560 
1561    if(err>0) err = 0;
1562    *errnum = err;
1563    return bzerrorstrings[err*-1];
1564 }
1565 #endif
1566 
1567 
1568 /*-------------------------------------------------------------*/
1569 /*--- end                                           bzlib.c ---*/
1570 /*-------------------------------------------------------------*/
1571