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