source: trunk/third/bzip2/bzlib.c @ 17062

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