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