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