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