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