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