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