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