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