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