xref: /oneTBB/examples/graph/fgbzip2/bzlib.cpp (revision 6caecf96)
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
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 /*---------------------------------------------------*/
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 /*---------------------------------------------------*/
143 static void* default_bzalloc(void* opaque, Int32 items, Int32 size) {
144     void* v = malloc(items * size);
145     return v;
146 }
147 
148 static void default_bzfree(void* opaque, void* addr) {
149     if (addr != nullptr)
150         free(addr);
151 }
152 
153 /*---------------------------------------------------*/
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 /*---------------------------------------------------*/
166 static void init_RL(EState* s) {
167     s->state_in_ch = 256;
168     s->state_in_len = 0;
169 }
170 
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 /*---------------------------------------------------*/
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 /*---------------------------------------------------*/
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 /*---------------------------------------------------*/
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 /*---------------------------------------------------*/
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 /*---------------------------------------------------*/
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 /*---------------------------------------------------*/
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 /*---------------------------------------------------*/
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 /*---------------------------------------------------*/
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 /*---------------------------------------------------*/
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 */
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 /*---------------------------------------------------*/
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 */
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 /*---------------------------------------------------*/
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 /*---------------------------------------------------*/
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 /*---------------------------------------------*/
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 /*---------------------------------------------------*/
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 /*---------------------------------------------------*/
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 /*---------------------------------------------------*/
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 
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 /*---------------------------------------------------*/
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 /*---------------------------------------------------*/
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 /*---------------------------------------------------*/
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 /*---------------------------------------------------*/
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 /*---------------------------------------------------*/
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 /*---------------------------------------------------*/
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 --*/
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
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 --*/
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 /*---------------------------------------------------*/
1605 BZFILE* BZ_API(BZ2_bzdopen)(int fd, const char* mode) {
1606     return bzopen_or_bzdopen(nullptr, fd, mode, /*bzdopen*/ 1);
1607 }
1608 
1609 /*---------------------------------------------------*/
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 /*---------------------------------------------------*/
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 /*---------------------------------------------------*/
1637 int BZ_API(BZ2_bzflush)(BZFILE* b) {
1638     /* do nothing now... */
1639     return 0;
1640 }
1641 
1642 /*---------------------------------------------------*/
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 
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