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