178556Sobrien
278556Sobrien/*-------------------------------------------------------------*/
378556Sobrien/*--- Library top-level functions.                          ---*/
478556Sobrien/*---                                               bzlib.c ---*/
578556Sobrien/*-------------------------------------------------------------*/
678556Sobrien
7167978Sdelphij/* ------------------------------------------------------------------
8167978Sdelphij   This file is part of bzip2/libbzip2, a program and library for
9167978Sdelphij   lossless, block-sorting data compression.
1078556Sobrien
11351007Sdelphij   bzip2/libbzip2 version 1.0.8 of 13 July 2019
12351007Sdelphij   Copyright (C) 1996-2019 Julian Seward <jseward@acm.org>
1378556Sobrien
14167978Sdelphij   Please read the WARNING, DISCLAIMER and PATENTS sections in the
15167978Sdelphij   README file.
1678556Sobrien
17167978Sdelphij   This program is released under the terms of the license contained
18167978Sdelphij   in the file LICENSE.
19167978Sdelphij   ------------------------------------------------------------------ */
2078556Sobrien
21167978Sdelphij/* CHANGES
22167978Sdelphij   0.9.0    -- original version.
2378556Sobrien   0.9.0a/b -- no changes in this file.
24167978Sdelphij   0.9.0c   -- made zero-length BZ_FLUSH work correctly in bzCompress().
25167978Sdelphij     fixed bzWrite/bzRead to ignore zero-length requests.
26167978Sdelphij     fixed bzread to correctly handle read requests after EOF.
27167978Sdelphij     wrong parameter order in call to bzDecompressInit in
28167978Sdelphij     bzBuffToBuffDecompress.  Fixed.
29167978Sdelphij*/
3078556Sobrien
31146788Ssobomax#include <sys/cdefs.h>
32146788Ssobomax__FBSDID("$FreeBSD: stable/11/contrib/bzip2/bzlib.c 351007 2019-08-14 06:39:20Z delphij $");
33146788Ssobomax
3478556Sobrien#include "bzlib_private.h"
3578556Sobrien
36146788Ssobomax#ifndef BZ_NO_COMPRESS
3778556Sobrien
3878556Sobrien/*---------------------------------------------------*/
3978556Sobrien/*--- Compression stuff                           ---*/
4078556Sobrien/*---------------------------------------------------*/
4178556Sobrien
4278556Sobrien
4378556Sobrien/*---------------------------------------------------*/
4478556Sobrien#ifndef BZ_NO_STDIO
4578556Sobrienvoid BZ2_bz__AssertH__fail ( int errcode )
4678556Sobrien{
4778556Sobrien   fprintf(stderr,
4878556Sobrien      "\n\nbzip2/libbzip2: internal error number %d.\n"
4978556Sobrien      "This is a bug in bzip2/libbzip2, %s.\n"
50351007Sdelphij      "Please report it to: bzip2-devel@sourceware.org.  If this happened\n"
5178556Sobrien      "when you were using some program which uses libbzip2 as a\n"
5278556Sobrien      "component, you should also report this bug to the author(s)\n"
5378556Sobrien      "of that program.  Please make an effort to report this bug;\n"
5478556Sobrien      "timely and accurate bug reports eventually lead to higher\n"
55351007Sdelphij      "quality software.  Thanks.\n\n",
5678556Sobrien      errcode,
5778556Sobrien      BZ2_bzlibVersion()
5878556Sobrien   );
5990067Ssobomax
6090067Ssobomax   if (errcode == 1007) {
6190067Ssobomax   fprintf(stderr,
6290067Ssobomax      "\n*** A special note about internal error number 1007 ***\n"
6390067Ssobomax      "\n"
6490067Ssobomax      "Experience suggests that a common cause of i.e. 1007\n"
6590067Ssobomax      "is unreliable memory or other hardware.  The 1007 assertion\n"
6690067Ssobomax      "just happens to cross-check the results of huge numbers of\n"
6790067Ssobomax      "memory reads/writes, and so acts (unintendedly) as a stress\n"
6890067Ssobomax      "test of your memory system.\n"
6990067Ssobomax      "\n"
7090067Ssobomax      "I suggest the following: try compressing the file again,\n"
7190067Ssobomax      "possibly monitoring progress in detail with the -vv flag.\n"
7290067Ssobomax      "\n"
7390067Ssobomax      "* If the error cannot be reproduced, and/or happens at different\n"
7490067Ssobomax      "  points in compression, you may have a flaky memory system.\n"
7590067Ssobomax      "  Try a memory-test program.  I have used Memtest86\n"
7690067Ssobomax      "  (www.memtest86.com).  At the time of writing it is free (GPLd).\n"
7790067Ssobomax      "  Memtest86 tests memory much more thorougly than your BIOSs\n"
7890067Ssobomax      "  power-on test, and may find failures that the BIOS doesn't.\n"
7990067Ssobomax      "\n"
8090067Ssobomax      "* If the error can be repeatably reproduced, this is a bug in\n"
8190067Ssobomax      "  bzip2, and I would very much like to hear about it.  Please\n"
8290067Ssobomax      "  let me know, and, ideally, save a copy of the file causing the\n"
8390067Ssobomax      "  problem -- without which I will be unable to investigate it.\n"
8490067Ssobomax      "\n"
8590067Ssobomax   );
8690067Ssobomax   }
8790067Ssobomax
8878556Sobrien   exit(3);
8978556Sobrien}
9078556Sobrien#endif
9178556Sobrien
92146788Ssobomax#endif /* BZ_NO_COMPRESS */
9378556Sobrien
9478556Sobrien/*---------------------------------------------------*/
9578556Sobrienstatic
9678556Sobrienint bz_config_ok ( void )
9778556Sobrien{
9878556Sobrien   if (sizeof(int)   != 4) return 0;
9978556Sobrien   if (sizeof(short) != 2) return 0;
10078556Sobrien   if (sizeof(char)  != 1) return 0;
10178556Sobrien   return 1;
10278556Sobrien}
10378556Sobrien
10478556Sobrien
10578556Sobrien/*---------------------------------------------------*/
10678556Sobrienstatic
10778556Sobrienvoid* default_bzalloc ( void* opaque, Int32 items, Int32 size )
10878556Sobrien{
10978556Sobrien   void* v = malloc ( items * size );
11078556Sobrien   return v;
11178556Sobrien}
11278556Sobrien
11378556Sobrienstatic
11478556Sobrienvoid default_bzfree ( void* opaque, void* addr )
11578556Sobrien{
11678556Sobrien   if (addr != NULL) free ( addr );
11778556Sobrien}
11878556Sobrien
119146788Ssobomax#ifndef BZ_NO_COMPRESS
12078556Sobrien
12178556Sobrien/*---------------------------------------------------*/
12278556Sobrienstatic
12378556Sobrienvoid prepare_new_block ( EState* s )
12478556Sobrien{
12578556Sobrien   Int32 i;
12678556Sobrien   s->nblock = 0;
12778556Sobrien   s->numZ = 0;
12878556Sobrien   s->state_out_pos = 0;
12978556Sobrien   BZ_INITIALISE_CRC ( s->blockCRC );
13078556Sobrien   for (i = 0; i < 256; i++) s->inUse[i] = False;
13178556Sobrien   s->blockNo++;
13278556Sobrien}
13378556Sobrien
13478556Sobrien
13578556Sobrien/*---------------------------------------------------*/
13678556Sobrienstatic
13778556Sobrienvoid init_RL ( EState* s )
13878556Sobrien{
13978556Sobrien   s->state_in_ch  = 256;
14078556Sobrien   s->state_in_len = 0;
14178556Sobrien}
14278556Sobrien
14378556Sobrien
14478556Sobrienstatic
14578556SobrienBool isempty_RL ( EState* s )
14678556Sobrien{
14778556Sobrien   if (s->state_in_ch < 256 && s->state_in_len > 0)
14878556Sobrien      return False; else
14978556Sobrien      return True;
15078556Sobrien}
15178556Sobrien
15278556Sobrien
15378556Sobrien/*---------------------------------------------------*/
15478556Sobrienint BZ_API(BZ2_bzCompressInit)
15578556Sobrien                    ( bz_stream* strm,
15678556Sobrien                     int        blockSize100k,
15778556Sobrien                     int        verbosity,
15878556Sobrien                     int        workFactor )
15978556Sobrien{
16078556Sobrien   Int32   n;
16178556Sobrien   EState* s;
16278556Sobrien
16378556Sobrien   if (!bz_config_ok()) return BZ_CONFIG_ERROR;
16478556Sobrien
16578556Sobrien   if (strm == NULL ||
16678556Sobrien       blockSize100k < 1 || blockSize100k > 9 ||
16778556Sobrien       workFactor < 0 || workFactor > 250)
16878556Sobrien     return BZ_PARAM_ERROR;
16978556Sobrien
17078556Sobrien   if (workFactor == 0) workFactor = 30;
17178556Sobrien   if (strm->bzalloc == NULL) strm->bzalloc = default_bzalloc;
17278556Sobrien   if (strm->bzfree == NULL) strm->bzfree = default_bzfree;
17378556Sobrien
17478556Sobrien   s = BZALLOC( sizeof(EState) );
17578556Sobrien   if (s == NULL) return BZ_MEM_ERROR;
17678556Sobrien   s->strm = strm;
17778556Sobrien
17878556Sobrien   s->arr1 = NULL;
17978556Sobrien   s->arr2 = NULL;
18078556Sobrien   s->ftab = NULL;
18178556Sobrien
18278556Sobrien   n       = 100000 * blockSize100k;
18378556Sobrien   s->arr1 = BZALLOC( n                  * sizeof(UInt32) );
18478556Sobrien   s->arr2 = BZALLOC( (n+BZ_N_OVERSHOOT) * sizeof(UInt32) );
18578556Sobrien   s->ftab = BZALLOC( 65537              * sizeof(UInt32) );
18678556Sobrien
18778556Sobrien   if (s->arr1 == NULL || s->arr2 == NULL || s->ftab == NULL) {
18878556Sobrien      if (s->arr1 != NULL) BZFREE(s->arr1);
18978556Sobrien      if (s->arr2 != NULL) BZFREE(s->arr2);
19078556Sobrien      if (s->ftab != NULL) BZFREE(s->ftab);
19178556Sobrien      if (s       != NULL) BZFREE(s);
19278556Sobrien      return BZ_MEM_ERROR;
19378556Sobrien   }
19478556Sobrien
19578556Sobrien   s->blockNo           = 0;
19678556Sobrien   s->state             = BZ_S_INPUT;
19778556Sobrien   s->mode              = BZ_M_RUNNING;
19878556Sobrien   s->combinedCRC       = 0;
19978556Sobrien   s->blockSize100k     = blockSize100k;
20078556Sobrien   s->nblockMAX         = 100000 * blockSize100k - 19;
20178556Sobrien   s->verbosity         = verbosity;
20278556Sobrien   s->workFactor        = workFactor;
20378556Sobrien
20478556Sobrien   s->block             = (UChar*)s->arr2;
20578556Sobrien   s->mtfv              = (UInt16*)s->arr1;
20678556Sobrien   s->zbits             = NULL;
20778556Sobrien   s->ptr               = (UInt32*)s->arr1;
20878556Sobrien
20978556Sobrien   strm->state          = s;
21078556Sobrien   strm->total_in_lo32  = 0;
21178556Sobrien   strm->total_in_hi32  = 0;
21278556Sobrien   strm->total_out_lo32 = 0;
21378556Sobrien   strm->total_out_hi32 = 0;
21478556Sobrien   init_RL ( s );
21578556Sobrien   prepare_new_block ( s );
21678556Sobrien   return BZ_OK;
21778556Sobrien}
21878556Sobrien
21978556Sobrien
22078556Sobrien/*---------------------------------------------------*/
22178556Sobrienstatic
22278556Sobrienvoid add_pair_to_block ( EState* s )
22378556Sobrien{
22478556Sobrien   Int32 i;
22578556Sobrien   UChar ch = (UChar)(s->state_in_ch);
22678556Sobrien   for (i = 0; i < s->state_in_len; i++) {
22778556Sobrien      BZ_UPDATE_CRC( s->blockCRC, ch );
22878556Sobrien   }
22978556Sobrien   s->inUse[s->state_in_ch] = True;
23078556Sobrien   switch (s->state_in_len) {
23178556Sobrien      case 1:
23278556Sobrien         s->block[s->nblock] = (UChar)ch; s->nblock++;
23378556Sobrien         break;
23478556Sobrien      case 2:
23578556Sobrien         s->block[s->nblock] = (UChar)ch; s->nblock++;
23678556Sobrien         s->block[s->nblock] = (UChar)ch; s->nblock++;
23778556Sobrien         break;
23878556Sobrien      case 3:
23978556Sobrien         s->block[s->nblock] = (UChar)ch; s->nblock++;
24078556Sobrien         s->block[s->nblock] = (UChar)ch; s->nblock++;
24178556Sobrien         s->block[s->nblock] = (UChar)ch; s->nblock++;
24278556Sobrien         break;
24378556Sobrien      default:
24478556Sobrien         s->inUse[s->state_in_len-4] = True;
24578556Sobrien         s->block[s->nblock] = (UChar)ch; s->nblock++;
24678556Sobrien         s->block[s->nblock] = (UChar)ch; s->nblock++;
24778556Sobrien         s->block[s->nblock] = (UChar)ch; s->nblock++;
24878556Sobrien         s->block[s->nblock] = (UChar)ch; s->nblock++;
24978556Sobrien         s->block[s->nblock] = ((UChar)(s->state_in_len-4));
25078556Sobrien         s->nblock++;
25178556Sobrien         break;
25278556Sobrien   }
25378556Sobrien}
25478556Sobrien
25578556Sobrien
25678556Sobrien/*---------------------------------------------------*/
25778556Sobrienstatic
25878556Sobrienvoid flush_RL ( EState* s )
25978556Sobrien{
26078556Sobrien   if (s->state_in_ch < 256) add_pair_to_block ( s );
26178556Sobrien   init_RL ( s );
26278556Sobrien}
26378556Sobrien
26478556Sobrien
26578556Sobrien/*---------------------------------------------------*/
26678556Sobrien#define ADD_CHAR_TO_BLOCK(zs,zchh0)               \
26778556Sobrien{                                                 \
26878556Sobrien   UInt32 zchh = (UInt32)(zchh0);                 \
26978556Sobrien   /*-- fast track the common case --*/           \
27078556Sobrien   if (zchh != zs->state_in_ch &&                 \
27178556Sobrien       zs->state_in_len == 1) {                   \
27278556Sobrien      UChar ch = (UChar)(zs->state_in_ch);        \
27378556Sobrien      BZ_UPDATE_CRC( zs->blockCRC, ch );          \
27478556Sobrien      zs->inUse[zs->state_in_ch] = True;          \
27578556Sobrien      zs->block[zs->nblock] = (UChar)ch;          \
27678556Sobrien      zs->nblock++;                               \
27778556Sobrien      zs->state_in_ch = zchh;                     \
27878556Sobrien   }                                              \
27978556Sobrien   else                                           \
28078556Sobrien   /*-- general, uncommon cases --*/              \
28178556Sobrien   if (zchh != zs->state_in_ch ||                 \
28278556Sobrien      zs->state_in_len == 255) {                  \
28378556Sobrien      if (zs->state_in_ch < 256)                  \
28478556Sobrien         add_pair_to_block ( zs );                \
28578556Sobrien      zs->state_in_ch = zchh;                     \
28678556Sobrien      zs->state_in_len = 1;                       \
28778556Sobrien   } else {                                       \
28878556Sobrien      zs->state_in_len++;                         \
28978556Sobrien   }                                              \
29078556Sobrien}
29178556Sobrien
29278556Sobrien
29378556Sobrien/*---------------------------------------------------*/
29478556Sobrienstatic
29578556SobrienBool copy_input_until_stop ( EState* s )
29678556Sobrien{
29778556Sobrien   Bool progress_in = False;
29878556Sobrien
29978556Sobrien   if (s->mode == BZ_M_RUNNING) {
30078556Sobrien
30178556Sobrien      /*-- fast track the common case --*/
30278556Sobrien      while (True) {
30378556Sobrien         /*-- block full? --*/
30478556Sobrien         if (s->nblock >= s->nblockMAX) break;
30578556Sobrien         /*-- no input? --*/
30678556Sobrien         if (s->strm->avail_in == 0) break;
30778556Sobrien         progress_in = True;
30878556Sobrien         ADD_CHAR_TO_BLOCK ( s, (UInt32)(*((UChar*)(s->strm->next_in))) );
30978556Sobrien         s->strm->next_in++;
31078556Sobrien         s->strm->avail_in--;
31178556Sobrien         s->strm->total_in_lo32++;
31278556Sobrien         if (s->strm->total_in_lo32 == 0) s->strm->total_in_hi32++;
31378556Sobrien      }
31478556Sobrien
31578556Sobrien   } else {
31678556Sobrien
31778556Sobrien      /*-- general, uncommon case --*/
31878556Sobrien      while (True) {
31978556Sobrien         /*-- block full? --*/
32078556Sobrien         if (s->nblock >= s->nblockMAX) break;
32178556Sobrien         /*-- no input? --*/
32278556Sobrien         if (s->strm->avail_in == 0) break;
32378556Sobrien         /*-- flush/finish end? --*/
32478556Sobrien         if (s->avail_in_expect == 0) break;
32578556Sobrien         progress_in = True;
32678556Sobrien         ADD_CHAR_TO_BLOCK ( s, (UInt32)(*((UChar*)(s->strm->next_in))) );
32778556Sobrien         s->strm->next_in++;
32878556Sobrien         s->strm->avail_in--;
32978556Sobrien         s->strm->total_in_lo32++;
33078556Sobrien         if (s->strm->total_in_lo32 == 0) s->strm->total_in_hi32++;
33178556Sobrien         s->avail_in_expect--;
33278556Sobrien      }
33378556Sobrien   }
33478556Sobrien   return progress_in;
33578556Sobrien}
33678556Sobrien
33778556Sobrien
33878556Sobrien/*---------------------------------------------------*/
33978556Sobrienstatic
34078556SobrienBool copy_output_until_stop ( EState* s )
34178556Sobrien{
34278556Sobrien   Bool progress_out = False;
34378556Sobrien
34478556Sobrien   while (True) {
34578556Sobrien
34678556Sobrien      /*-- no output space? --*/
34778556Sobrien      if (s->strm->avail_out == 0) break;
34878556Sobrien
34978556Sobrien      /*-- block done? --*/
35078556Sobrien      if (s->state_out_pos >= s->numZ) break;
35178556Sobrien
35278556Sobrien      progress_out = True;
35378556Sobrien      *(s->strm->next_out) = s->zbits[s->state_out_pos];
35478556Sobrien      s->state_out_pos++;
35578556Sobrien      s->strm->avail_out--;
35678556Sobrien      s->strm->next_out++;
35778556Sobrien      s->strm->total_out_lo32++;
35878556Sobrien      if (s->strm->total_out_lo32 == 0) s->strm->total_out_hi32++;
35978556Sobrien   }
36078556Sobrien
36178556Sobrien   return progress_out;
36278556Sobrien}
36378556Sobrien
36478556Sobrien
36578556Sobrien/*---------------------------------------------------*/
36678556Sobrienstatic
36778556SobrienBool handle_compress ( bz_stream* strm )
36878556Sobrien{
36978556Sobrien   Bool progress_in  = False;
37078556Sobrien   Bool progress_out = False;
37178556Sobrien   EState* s = strm->state;
37278556Sobrien
37378556Sobrien   while (True) {
37478556Sobrien
37578556Sobrien      if (s->state == BZ_S_OUTPUT) {
37678556Sobrien         progress_out |= copy_output_until_stop ( s );
37778556Sobrien         if (s->state_out_pos < s->numZ) break;
37878556Sobrien         if (s->mode == BZ_M_FINISHING &&
37978556Sobrien             s->avail_in_expect == 0 &&
38078556Sobrien             isempty_RL(s)) break;
38178556Sobrien         prepare_new_block ( s );
38278556Sobrien         s->state = BZ_S_INPUT;
38378556Sobrien         if (s->mode == BZ_M_FLUSHING &&
38478556Sobrien             s->avail_in_expect == 0 &&
38578556Sobrien             isempty_RL(s)) break;
38678556Sobrien      }
38778556Sobrien
38878556Sobrien      if (s->state == BZ_S_INPUT) {
38978556Sobrien         progress_in |= copy_input_until_stop ( s );
39078556Sobrien         if (s->mode != BZ_M_RUNNING && s->avail_in_expect == 0) {
39178556Sobrien            flush_RL ( s );
39278556Sobrien            BZ2_compressBlock ( s, (Bool)(s->mode == BZ_M_FINISHING) );
39378556Sobrien            s->state = BZ_S_OUTPUT;
39478556Sobrien         }
39578556Sobrien         else
39678556Sobrien         if (s->nblock >= s->nblockMAX) {
39778556Sobrien            BZ2_compressBlock ( s, False );
39878556Sobrien            s->state = BZ_S_OUTPUT;
39978556Sobrien         }
40078556Sobrien         else
40178556Sobrien         if (s->strm->avail_in == 0) {
40278556Sobrien            break;
40378556Sobrien         }
40478556Sobrien      }
40578556Sobrien
40678556Sobrien   }
40778556Sobrien
40878556Sobrien   return progress_in || progress_out;
40978556Sobrien}
41078556Sobrien
41178556Sobrien
41278556Sobrien/*---------------------------------------------------*/
41378556Sobrienint BZ_API(BZ2_bzCompress) ( bz_stream *strm, int action )
41478556Sobrien{
41578556Sobrien   Bool progress;
41678556Sobrien   EState* s;
41778556Sobrien   if (strm == NULL) return BZ_PARAM_ERROR;
41878556Sobrien   s = strm->state;
41978556Sobrien   if (s == NULL) return BZ_PARAM_ERROR;
42078556Sobrien   if (s->strm != strm) return BZ_PARAM_ERROR;
42178556Sobrien
42278556Sobrien   preswitch:
42378556Sobrien   switch (s->mode) {
42478556Sobrien
42578556Sobrien      case BZ_M_IDLE:
42678556Sobrien         return BZ_SEQUENCE_ERROR;
42778556Sobrien
42878556Sobrien      case BZ_M_RUNNING:
42978556Sobrien         if (action == BZ_RUN) {
43078556Sobrien            progress = handle_compress ( strm );
43178556Sobrien            return progress ? BZ_RUN_OK : BZ_PARAM_ERROR;
43278556Sobrien         }
43378556Sobrien         else
43478556Sobrien	 if (action == BZ_FLUSH) {
43578556Sobrien            s->avail_in_expect = strm->avail_in;
43678556Sobrien            s->mode = BZ_M_FLUSHING;
43778556Sobrien            goto preswitch;
43878556Sobrien         }
43978556Sobrien         else
44078556Sobrien         if (action == BZ_FINISH) {
44178556Sobrien            s->avail_in_expect = strm->avail_in;
44278556Sobrien            s->mode = BZ_M_FINISHING;
44378556Sobrien            goto preswitch;
44478556Sobrien         }
44578556Sobrien         else
44678556Sobrien            return BZ_PARAM_ERROR;
44778556Sobrien
44878556Sobrien      case BZ_M_FLUSHING:
44978556Sobrien         if (action != BZ_FLUSH) return BZ_SEQUENCE_ERROR;
45078556Sobrien         if (s->avail_in_expect != s->strm->avail_in)
45178556Sobrien            return BZ_SEQUENCE_ERROR;
45278556Sobrien         progress = handle_compress ( strm );
45378556Sobrien         if (s->avail_in_expect > 0 || !isempty_RL(s) ||
45478556Sobrien             s->state_out_pos < s->numZ) return BZ_FLUSH_OK;
45578556Sobrien         s->mode = BZ_M_RUNNING;
45678556Sobrien         return BZ_RUN_OK;
45778556Sobrien
45878556Sobrien      case BZ_M_FINISHING:
45978556Sobrien         if (action != BZ_FINISH) return BZ_SEQUENCE_ERROR;
46078556Sobrien         if (s->avail_in_expect != s->strm->avail_in)
46178556Sobrien            return BZ_SEQUENCE_ERROR;
46278556Sobrien         progress = handle_compress ( strm );
46378556Sobrien         if (!progress) return BZ_SEQUENCE_ERROR;
46478556Sobrien         if (s->avail_in_expect > 0 || !isempty_RL(s) ||
46578556Sobrien             s->state_out_pos < s->numZ) return BZ_FINISH_OK;
46678556Sobrien         s->mode = BZ_M_IDLE;
46778556Sobrien         return BZ_STREAM_END;
46878556Sobrien   }
46978556Sobrien   return BZ_OK; /*--not reached--*/
47078556Sobrien}
47178556Sobrien
47278556Sobrien
47378556Sobrien/*---------------------------------------------------*/
47478556Sobrienint BZ_API(BZ2_bzCompressEnd)  ( bz_stream *strm )
47578556Sobrien{
47678556Sobrien   EState* s;
47778556Sobrien   if (strm == NULL) return BZ_PARAM_ERROR;
47878556Sobrien   s = strm->state;
47978556Sobrien   if (s == NULL) return BZ_PARAM_ERROR;
48078556Sobrien   if (s->strm != strm) return BZ_PARAM_ERROR;
48178556Sobrien
48278556Sobrien   if (s->arr1 != NULL) BZFREE(s->arr1);
48378556Sobrien   if (s->arr2 != NULL) BZFREE(s->arr2);
48478556Sobrien   if (s->ftab != NULL) BZFREE(s->ftab);
48578556Sobrien   BZFREE(strm->state);
48678556Sobrien
48778556Sobrien   strm->state = NULL;
48878556Sobrien
48978556Sobrien   return BZ_OK;
49078556Sobrien}
49178556Sobrien
492146788Ssobomax#endif /* BZ_NO_COMPRESS */
49378556Sobrien
49478556Sobrien/*---------------------------------------------------*/
49578556Sobrien/*--- Decompression stuff                         ---*/
49678556Sobrien/*---------------------------------------------------*/
49778556Sobrien
49878556Sobrien/*---------------------------------------------------*/
49978556Sobrienint BZ_API(BZ2_bzDecompressInit)
50078556Sobrien                     ( bz_stream* strm,
50178556Sobrien                       int        verbosity,
50278556Sobrien                       int        small )
50378556Sobrien{
50478556Sobrien   DState* s;
50578556Sobrien
50678556Sobrien   if (!bz_config_ok()) return BZ_CONFIG_ERROR;
50778556Sobrien
50878556Sobrien   if (strm == NULL) return BZ_PARAM_ERROR;
50978556Sobrien   if (small != 0 && small != 1) return BZ_PARAM_ERROR;
51078556Sobrien   if (verbosity < 0 || verbosity > 4) return BZ_PARAM_ERROR;
51178556Sobrien
51278556Sobrien   if (strm->bzalloc == NULL) strm->bzalloc = default_bzalloc;
51378556Sobrien   if (strm->bzfree == NULL) strm->bzfree = default_bzfree;
51478556Sobrien
51578556Sobrien   s = BZALLOC( sizeof(DState) );
51678556Sobrien   if (s == NULL) return BZ_MEM_ERROR;
51778556Sobrien   s->strm                  = strm;
51878556Sobrien   strm->state              = s;
51978556Sobrien   s->state                 = BZ_X_MAGIC_1;
52078556Sobrien   s->bsLive                = 0;
52178556Sobrien   s->bsBuff                = 0;
52278556Sobrien   s->calculatedCombinedCRC = 0;
52378556Sobrien   strm->total_in_lo32      = 0;
52478556Sobrien   strm->total_in_hi32      = 0;
52578556Sobrien   strm->total_out_lo32     = 0;
52678556Sobrien   strm->total_out_hi32     = 0;
52778556Sobrien   s->smallDecompress       = (Bool)small;
52878556Sobrien   s->ll4                   = NULL;
52978556Sobrien   s->ll16                  = NULL;
53078556Sobrien   s->tt                    = NULL;
53178556Sobrien   s->currBlockNo           = 0;
53278556Sobrien   s->verbosity             = verbosity;
53378556Sobrien
53478556Sobrien   return BZ_OK;
53578556Sobrien}
53678556Sobrien
53778556Sobrien
53878556Sobrien/*---------------------------------------------------*/
539146293Sobrien/* Return  True iff data corruption is discovered.
540146293Sobrien   Returns False if there is no problem.
541146293Sobrien*/
54278556Sobrienstatic
543146293SobrienBool unRLE_obuf_to_output_FAST ( DState* s )
54478556Sobrien{
54578556Sobrien   UChar k1;
54678556Sobrien
54778556Sobrien   if (s->blockRandomised) {
54878556Sobrien
54978556Sobrien      while (True) {
55078556Sobrien         /* try to finish existing run */
55178556Sobrien         while (True) {
552146293Sobrien            if (s->strm->avail_out == 0) return False;
55378556Sobrien            if (s->state_out_len == 0) break;
55478556Sobrien            *( (UChar*)(s->strm->next_out) ) = s->state_out_ch;
55578556Sobrien            BZ_UPDATE_CRC ( s->calculatedBlockCRC, s->state_out_ch );
55678556Sobrien            s->state_out_len--;
55778556Sobrien            s->strm->next_out++;
55878556Sobrien            s->strm->avail_out--;
55978556Sobrien            s->strm->total_out_lo32++;
56078556Sobrien            if (s->strm->total_out_lo32 == 0) s->strm->total_out_hi32++;
56178556Sobrien         }
562146293Sobrien
56378556Sobrien         /* can a new run be started? */
564146293Sobrien         if (s->nblock_used == s->save_nblock+1) return False;
56578556Sobrien
566146293Sobrien         /* Only caused by corrupt data stream? */
567146293Sobrien         if (s->nblock_used > s->save_nblock+1)
568146293Sobrien            return True;
56978556Sobrien
57078556Sobrien         s->state_out_len = 1;
57178556Sobrien         s->state_out_ch = s->k0;
57278556Sobrien         BZ_GET_FAST(k1); BZ_RAND_UPD_MASK;
57378556Sobrien         k1 ^= BZ_RAND_MASK; s->nblock_used++;
57478556Sobrien         if (s->nblock_used == s->save_nblock+1) continue;
57578556Sobrien         if (k1 != s->k0) { s->k0 = k1; continue; };
57678556Sobrien
57778556Sobrien         s->state_out_len = 2;
57878556Sobrien         BZ_GET_FAST(k1); BZ_RAND_UPD_MASK;
57978556Sobrien         k1 ^= BZ_RAND_MASK; s->nblock_used++;
58078556Sobrien         if (s->nblock_used == s->save_nblock+1) continue;
58178556Sobrien         if (k1 != s->k0) { s->k0 = k1; continue; };
58278556Sobrien
58378556Sobrien         s->state_out_len = 3;
58478556Sobrien         BZ_GET_FAST(k1); BZ_RAND_UPD_MASK;
58578556Sobrien         k1 ^= BZ_RAND_MASK; s->nblock_used++;
58678556Sobrien         if (s->nblock_used == s->save_nblock+1) continue;
58778556Sobrien         if (k1 != s->k0) { s->k0 = k1; continue; };
58878556Sobrien
58978556Sobrien         BZ_GET_FAST(k1); BZ_RAND_UPD_MASK;
59078556Sobrien         k1 ^= BZ_RAND_MASK; s->nblock_used++;
59178556Sobrien         s->state_out_len = ((Int32)k1) + 4;
59278556Sobrien         BZ_GET_FAST(s->k0); BZ_RAND_UPD_MASK;
59378556Sobrien         s->k0 ^= BZ_RAND_MASK; s->nblock_used++;
59478556Sobrien      }
59578556Sobrien
59678556Sobrien   } else {
59778556Sobrien
59878556Sobrien      /* restore */
59978556Sobrien      UInt32        c_calculatedBlockCRC = s->calculatedBlockCRC;
60078556Sobrien      UChar         c_state_out_ch       = s->state_out_ch;
60178556Sobrien      Int32         c_state_out_len      = s->state_out_len;
60278556Sobrien      Int32         c_nblock_used        = s->nblock_used;
60378556Sobrien      Int32         c_k0                 = s->k0;
60478556Sobrien      UInt32*       c_tt                 = s->tt;
60578556Sobrien      UInt32        c_tPos               = s->tPos;
60678556Sobrien      char*         cs_next_out          = s->strm->next_out;
60778556Sobrien      unsigned int  cs_avail_out         = s->strm->avail_out;
608177424Sdelphij      Int32         ro_blockSize100k     = s->blockSize100k;
60978556Sobrien      /* end restore */
61078556Sobrien
61178556Sobrien      UInt32       avail_out_INIT = cs_avail_out;
61278556Sobrien      Int32        s_save_nblockPP = s->save_nblock+1;
61378556Sobrien      unsigned int total_out_lo32_old;
61478556Sobrien
61578556Sobrien      while (True) {
61678556Sobrien
61778556Sobrien         /* try to finish existing run */
61878556Sobrien         if (c_state_out_len > 0) {
61978556Sobrien            while (True) {
62078556Sobrien               if (cs_avail_out == 0) goto return_notr;
62178556Sobrien               if (c_state_out_len == 1) break;
62278556Sobrien               *( (UChar*)(cs_next_out) ) = c_state_out_ch;
62378556Sobrien               BZ_UPDATE_CRC ( c_calculatedBlockCRC, c_state_out_ch );
62478556Sobrien               c_state_out_len--;
62578556Sobrien               cs_next_out++;
62678556Sobrien               cs_avail_out--;
62778556Sobrien            }
62878556Sobrien            s_state_out_len_eq_one:
62978556Sobrien            {
63078556Sobrien               if (cs_avail_out == 0) {
63178556Sobrien                  c_state_out_len = 1; goto return_notr;
63278556Sobrien               };
63378556Sobrien               *( (UChar*)(cs_next_out) ) = c_state_out_ch;
63478556Sobrien               BZ_UPDATE_CRC ( c_calculatedBlockCRC, c_state_out_ch );
63578556Sobrien               cs_next_out++;
63678556Sobrien               cs_avail_out--;
63778556Sobrien            }
63878556Sobrien         }
639146293Sobrien         /* Only caused by corrupt data stream? */
640146293Sobrien         if (c_nblock_used > s_save_nblockPP)
641146293Sobrien            return True;
642146293Sobrien
64378556Sobrien         /* can a new run be started? */
64478556Sobrien         if (c_nblock_used == s_save_nblockPP) {
64578556Sobrien            c_state_out_len = 0; goto return_notr;
64678556Sobrien         };
64778556Sobrien         c_state_out_ch = c_k0;
64878556Sobrien         BZ_GET_FAST_C(k1); c_nblock_used++;
64978556Sobrien         if (k1 != c_k0) {
65078556Sobrien            c_k0 = k1; goto s_state_out_len_eq_one;
65178556Sobrien         };
65278556Sobrien         if (c_nblock_used == s_save_nblockPP)
65378556Sobrien            goto s_state_out_len_eq_one;
65478556Sobrien
65578556Sobrien         c_state_out_len = 2;
65678556Sobrien         BZ_GET_FAST_C(k1); c_nblock_used++;
65778556Sobrien         if (c_nblock_used == s_save_nblockPP) continue;
65878556Sobrien         if (k1 != c_k0) { c_k0 = k1; continue; };
65978556Sobrien
66078556Sobrien         c_state_out_len = 3;
66178556Sobrien         BZ_GET_FAST_C(k1); c_nblock_used++;
66278556Sobrien         if (c_nblock_used == s_save_nblockPP) continue;
66378556Sobrien         if (k1 != c_k0) { c_k0 = k1; continue; };
66478556Sobrien
66578556Sobrien         BZ_GET_FAST_C(k1); c_nblock_used++;
66678556Sobrien         c_state_out_len = ((Int32)k1) + 4;
66778556Sobrien         BZ_GET_FAST_C(c_k0); c_nblock_used++;
66878556Sobrien      }
66978556Sobrien
67078556Sobrien      return_notr:
67178556Sobrien      total_out_lo32_old = s->strm->total_out_lo32;
67278556Sobrien      s->strm->total_out_lo32 += (avail_out_INIT - cs_avail_out);
67378556Sobrien      if (s->strm->total_out_lo32 < total_out_lo32_old)
67478556Sobrien         s->strm->total_out_hi32++;
67578556Sobrien
67678556Sobrien      /* save */
67778556Sobrien      s->calculatedBlockCRC = c_calculatedBlockCRC;
67878556Sobrien      s->state_out_ch       = c_state_out_ch;
67978556Sobrien      s->state_out_len      = c_state_out_len;
68078556Sobrien      s->nblock_used        = c_nblock_used;
68178556Sobrien      s->k0                 = c_k0;
68278556Sobrien      s->tt                 = c_tt;
68378556Sobrien      s->tPos               = c_tPos;
68478556Sobrien      s->strm->next_out     = cs_next_out;
68578556Sobrien      s->strm->avail_out    = cs_avail_out;
68678556Sobrien      /* end save */
68778556Sobrien   }
688146293Sobrien   return False;
68978556Sobrien}
69078556Sobrien
69178556Sobrien
69278556Sobrien
69378556Sobrien/*---------------------------------------------------*/
69478556Sobrien__inline__ Int32 BZ2_indexIntoF ( Int32 indx, Int32 *cftab )
69578556Sobrien{
69678556Sobrien   Int32 nb, na, mid;
69778556Sobrien   nb = 0;
69878556Sobrien   na = 256;
69978556Sobrien   do {
70078556Sobrien      mid = (nb + na) >> 1;
70178556Sobrien      if (indx >= cftab[mid]) nb = mid; else na = mid;
70278556Sobrien   }
70378556Sobrien   while (na - nb != 1);
70478556Sobrien   return nb;
70578556Sobrien}
70678556Sobrien
70778556Sobrien
70878556Sobrien/*---------------------------------------------------*/
709146293Sobrien/* Return  True iff data corruption is discovered.
710146293Sobrien   Returns False if there is no problem.
711146293Sobrien*/
71278556Sobrienstatic
713146293SobrienBool unRLE_obuf_to_output_SMALL ( DState* s )
71478556Sobrien{
71578556Sobrien   UChar k1;
71678556Sobrien
71778556Sobrien   if (s->blockRandomised) {
71878556Sobrien
71978556Sobrien      while (True) {
72078556Sobrien         /* try to finish existing run */
72178556Sobrien         while (True) {
722146293Sobrien            if (s->strm->avail_out == 0) return False;
72378556Sobrien            if (s->state_out_len == 0) break;
72478556Sobrien            *( (UChar*)(s->strm->next_out) ) = s->state_out_ch;
72578556Sobrien            BZ_UPDATE_CRC ( s->calculatedBlockCRC, s->state_out_ch );
72678556Sobrien            s->state_out_len--;
72778556Sobrien            s->strm->next_out++;
72878556Sobrien            s->strm->avail_out--;
72978556Sobrien            s->strm->total_out_lo32++;
73078556Sobrien            if (s->strm->total_out_lo32 == 0) s->strm->total_out_hi32++;
73178556Sobrien         }
73278556Sobrien
73378556Sobrien         /* can a new run be started? */
734146293Sobrien         if (s->nblock_used == s->save_nblock+1) return False;
735146293Sobrien
736146293Sobrien         /* Only caused by corrupt data stream? */
737146293Sobrien         if (s->nblock_used > s->save_nblock+1)
738146293Sobrien            return True;
73978556Sobrien
74078556Sobrien         s->state_out_len = 1;
74178556Sobrien         s->state_out_ch = s->k0;
74278556Sobrien         BZ_GET_SMALL(k1); BZ_RAND_UPD_MASK;
74378556Sobrien         k1 ^= BZ_RAND_MASK; s->nblock_used++;
74478556Sobrien         if (s->nblock_used == s->save_nblock+1) continue;
74578556Sobrien         if (k1 != s->k0) { s->k0 = k1; continue; };
74678556Sobrien
74778556Sobrien         s->state_out_len = 2;
74878556Sobrien         BZ_GET_SMALL(k1); BZ_RAND_UPD_MASK;
74978556Sobrien         k1 ^= BZ_RAND_MASK; s->nblock_used++;
75078556Sobrien         if (s->nblock_used == s->save_nblock+1) continue;
75178556Sobrien         if (k1 != s->k0) { s->k0 = k1; continue; };
75278556Sobrien
75378556Sobrien         s->state_out_len = 3;
75478556Sobrien         BZ_GET_SMALL(k1); BZ_RAND_UPD_MASK;
75578556Sobrien         k1 ^= BZ_RAND_MASK; s->nblock_used++;
75678556Sobrien         if (s->nblock_used == s->save_nblock+1) continue;
75778556Sobrien         if (k1 != s->k0) { s->k0 = k1; continue; };
75878556Sobrien
75978556Sobrien         BZ_GET_SMALL(k1); BZ_RAND_UPD_MASK;
76078556Sobrien         k1 ^= BZ_RAND_MASK; s->nblock_used++;
76178556Sobrien         s->state_out_len = ((Int32)k1) + 4;
76278556Sobrien         BZ_GET_SMALL(s->k0); BZ_RAND_UPD_MASK;
76378556Sobrien         s->k0 ^= BZ_RAND_MASK; s->nblock_used++;
76478556Sobrien      }
76578556Sobrien
76678556Sobrien   } else {
76778556Sobrien
76878556Sobrien      while (True) {
76978556Sobrien         /* try to finish existing run */
77078556Sobrien         while (True) {
771146293Sobrien            if (s->strm->avail_out == 0) return False;
77278556Sobrien            if (s->state_out_len == 0) break;
77378556Sobrien            *( (UChar*)(s->strm->next_out) ) = s->state_out_ch;
77478556Sobrien            BZ_UPDATE_CRC ( s->calculatedBlockCRC, s->state_out_ch );
77578556Sobrien            s->state_out_len--;
77678556Sobrien            s->strm->next_out++;
77778556Sobrien            s->strm->avail_out--;
77878556Sobrien            s->strm->total_out_lo32++;
77978556Sobrien            if (s->strm->total_out_lo32 == 0) s->strm->total_out_hi32++;
78078556Sobrien         }
78178556Sobrien
78278556Sobrien         /* can a new run be started? */
783146293Sobrien         if (s->nblock_used == s->save_nblock+1) return False;
784146293Sobrien
785146293Sobrien         /* Only caused by corrupt data stream? */
786146293Sobrien         if (s->nblock_used > s->save_nblock+1)
787146293Sobrien            return True;
78878556Sobrien
78978556Sobrien         s->state_out_len = 1;
79078556Sobrien         s->state_out_ch = s->k0;
79178556Sobrien         BZ_GET_SMALL(k1); s->nblock_used++;
79278556Sobrien         if (s->nblock_used == s->save_nblock+1) continue;
79378556Sobrien         if (k1 != s->k0) { s->k0 = k1; continue; };
79478556Sobrien
79578556Sobrien         s->state_out_len = 2;
79678556Sobrien         BZ_GET_SMALL(k1); s->nblock_used++;
79778556Sobrien         if (s->nblock_used == s->save_nblock+1) continue;
79878556Sobrien         if (k1 != s->k0) { s->k0 = k1; continue; };
79978556Sobrien
80078556Sobrien         s->state_out_len = 3;
80178556Sobrien         BZ_GET_SMALL(k1); s->nblock_used++;
80278556Sobrien         if (s->nblock_used == s->save_nblock+1) continue;
80378556Sobrien         if (k1 != s->k0) { s->k0 = k1; continue; };
80478556Sobrien
80578556Sobrien         BZ_GET_SMALL(k1); s->nblock_used++;
80678556Sobrien         s->state_out_len = ((Int32)k1) + 4;
80778556Sobrien         BZ_GET_SMALL(s->k0); s->nblock_used++;
80878556Sobrien      }
80978556Sobrien
81078556Sobrien   }
81178556Sobrien}
81278556Sobrien
81378556Sobrien
81478556Sobrien/*---------------------------------------------------*/
81578556Sobrienint BZ_API(BZ2_bzDecompress) ( bz_stream *strm )
81678556Sobrien{
817146293Sobrien   Bool    corrupt;
81878556Sobrien   DState* s;
81978556Sobrien   if (strm == NULL) return BZ_PARAM_ERROR;
82078556Sobrien   s = strm->state;
82178556Sobrien   if (s == NULL) return BZ_PARAM_ERROR;
82278556Sobrien   if (s->strm != strm) return BZ_PARAM_ERROR;
82378556Sobrien
82478556Sobrien   while (True) {
82578556Sobrien      if (s->state == BZ_X_IDLE) return BZ_SEQUENCE_ERROR;
82678556Sobrien      if (s->state == BZ_X_OUTPUT) {
82778556Sobrien         if (s->smallDecompress)
828146293Sobrien            corrupt = unRLE_obuf_to_output_SMALL ( s ); else
829146293Sobrien            corrupt = unRLE_obuf_to_output_FAST  ( s );
830146293Sobrien         if (corrupt) return BZ_DATA_ERROR;
83178556Sobrien         if (s->nblock_used == s->save_nblock+1 && s->state_out_len == 0) {
83278556Sobrien            BZ_FINALISE_CRC ( s->calculatedBlockCRC );
83378556Sobrien            if (s->verbosity >= 3)
834146293Sobrien               VPrintf2 ( " {0x%08x, 0x%08x}", s->storedBlockCRC,
83578556Sobrien                          s->calculatedBlockCRC );
83678556Sobrien            if (s->verbosity >= 2) VPrintf0 ( "]" );
83778556Sobrien            if (s->calculatedBlockCRC != s->storedBlockCRC)
83878556Sobrien               return BZ_DATA_ERROR;
83978556Sobrien            s->calculatedCombinedCRC
84078556Sobrien               = (s->calculatedCombinedCRC << 1) |
84178556Sobrien                    (s->calculatedCombinedCRC >> 31);
84278556Sobrien            s->calculatedCombinedCRC ^= s->calculatedBlockCRC;
84378556Sobrien            s->state = BZ_X_BLKHDR_1;
84478556Sobrien         } else {
84578556Sobrien            return BZ_OK;
84678556Sobrien         }
84778556Sobrien      }
84878556Sobrien      if (s->state >= BZ_X_MAGIC_1) {
84978556Sobrien         Int32 r = BZ2_decompress ( s );
85078556Sobrien         if (r == BZ_STREAM_END) {
85178556Sobrien            if (s->verbosity >= 3)
852146293Sobrien               VPrintf2 ( "\n    combined CRCs: stored = 0x%08x, computed = 0x%08x",
85378556Sobrien                          s->storedCombinedCRC, s->calculatedCombinedCRC );
85478556Sobrien            if (s->calculatedCombinedCRC != s->storedCombinedCRC)
85578556Sobrien               return BZ_DATA_ERROR;
85678556Sobrien            return r;
85778556Sobrien         }
85878556Sobrien         if (s->state != BZ_X_OUTPUT) return r;
85978556Sobrien      }
86078556Sobrien   }
86178556Sobrien
86278556Sobrien   AssertH ( 0, 6001 );
86378556Sobrien
86478556Sobrien   return 0;  /*NOTREACHED*/
86578556Sobrien}
86678556Sobrien
86778556Sobrien
86878556Sobrien/*---------------------------------------------------*/
86978556Sobrienint BZ_API(BZ2_bzDecompressEnd)  ( bz_stream *strm )
87078556Sobrien{
87178556Sobrien   DState* s;
87278556Sobrien   if (strm == NULL) return BZ_PARAM_ERROR;
87378556Sobrien   s = strm->state;
87478556Sobrien   if (s == NULL) return BZ_PARAM_ERROR;
87578556Sobrien   if (s->strm != strm) return BZ_PARAM_ERROR;
87678556Sobrien
87778556Sobrien   if (s->tt   != NULL) BZFREE(s->tt);
87878556Sobrien   if (s->ll16 != NULL) BZFREE(s->ll16);
87978556Sobrien   if (s->ll4  != NULL) BZFREE(s->ll4);
88078556Sobrien
88178556Sobrien   BZFREE(strm->state);
88278556Sobrien   strm->state = NULL;
88378556Sobrien
88478556Sobrien   return BZ_OK;
88578556Sobrien}
88678556Sobrien
887146788Ssobomax#ifndef BZ_NO_COMPRESS
88878556Sobrien
88978556Sobrien#ifndef BZ_NO_STDIO
89078556Sobrien/*---------------------------------------------------*/
89178556Sobrien/*--- File I/O stuff                              ---*/
89278556Sobrien/*---------------------------------------------------*/
89378556Sobrien
89478556Sobrien#define BZ_SETERR(eee)                    \
89578556Sobrien{                                         \
89678556Sobrien   if (bzerror != NULL) *bzerror = eee;   \
89778556Sobrien   if (bzf != NULL) bzf->lastErr = eee;   \
89878556Sobrien}
89978556Sobrien
90078556Sobrientypedef
90178556Sobrien   struct {
90278556Sobrien      FILE*     handle;
90378556Sobrien      Char      buf[BZ_MAX_UNUSED];
90478556Sobrien      Int32     bufN;
90578556Sobrien      Bool      writing;
90678556Sobrien      bz_stream strm;
90778556Sobrien      Int32     lastErr;
90878556Sobrien      Bool      initialisedOk;
90978556Sobrien   }
91078556Sobrien   bzFile;
91178556Sobrien
91278556Sobrien
91378556Sobrien/*---------------------------------------------*/
91478556Sobrienstatic Bool myfeof ( FILE* f )
91578556Sobrien{
91678556Sobrien   Int32 c = fgetc ( f );
91778556Sobrien   if (c == EOF) return True;
91878556Sobrien   ungetc ( c, f );
91978556Sobrien   return False;
92078556Sobrien}
92178556Sobrien
92278556Sobrien
92378556Sobrien/*---------------------------------------------------*/
92478556SobrienBZFILE* BZ_API(BZ2_bzWriteOpen)
92578556Sobrien                    ( int*  bzerror,
92678556Sobrien                      FILE* f,
92778556Sobrien                      int   blockSize100k,
92878556Sobrien                      int   verbosity,
92978556Sobrien                      int   workFactor )
93078556Sobrien{
93178556Sobrien   Int32   ret;
93278556Sobrien   bzFile* bzf = NULL;
93378556Sobrien
93478556Sobrien   BZ_SETERR(BZ_OK);
93578556Sobrien
93678556Sobrien   if (f == NULL ||
93778556Sobrien       (blockSize100k < 1 || blockSize100k > 9) ||
93878556Sobrien       (workFactor < 0 || workFactor > 250) ||
93978556Sobrien       (verbosity < 0 || verbosity > 4))
94078556Sobrien      { BZ_SETERR(BZ_PARAM_ERROR); return NULL; };
94178556Sobrien
94278556Sobrien   if (ferror(f))
94378556Sobrien      { BZ_SETERR(BZ_IO_ERROR); return NULL; };
94478556Sobrien
94578556Sobrien   bzf = malloc ( sizeof(bzFile) );
94678556Sobrien   if (bzf == NULL)
94778556Sobrien      { BZ_SETERR(BZ_MEM_ERROR); return NULL; };
94878556Sobrien
94978556Sobrien   BZ_SETERR(BZ_OK);
95078556Sobrien   bzf->initialisedOk = False;
95178556Sobrien   bzf->bufN          = 0;
95278556Sobrien   bzf->handle        = f;
95378556Sobrien   bzf->writing       = True;
95478556Sobrien   bzf->strm.bzalloc  = NULL;
95578556Sobrien   bzf->strm.bzfree   = NULL;
95678556Sobrien   bzf->strm.opaque   = NULL;
95778556Sobrien
95878556Sobrien   if (workFactor == 0) workFactor = 30;
95978556Sobrien   ret = BZ2_bzCompressInit ( &(bzf->strm), blockSize100k,
96078556Sobrien                              verbosity, workFactor );
96178556Sobrien   if (ret != BZ_OK)
96278556Sobrien      { BZ_SETERR(ret); free(bzf); return NULL; };
96378556Sobrien
96478556Sobrien   bzf->strm.avail_in = 0;
96578556Sobrien   bzf->initialisedOk = True;
96678556Sobrien   return bzf;
96778556Sobrien}
96878556Sobrien
96978556Sobrien
97078556Sobrien
97178556Sobrien/*---------------------------------------------------*/
97278556Sobrienvoid BZ_API(BZ2_bzWrite)
97378556Sobrien             ( int*    bzerror,
97478556Sobrien               BZFILE* b,
97578556Sobrien               void*   buf,
97678556Sobrien               int     len )
97778556Sobrien{
97878556Sobrien   Int32 n, n2, ret;
97978556Sobrien   bzFile* bzf = (bzFile*)b;
98078556Sobrien
98178556Sobrien   BZ_SETERR(BZ_OK);
98278556Sobrien   if (bzf == NULL || buf == NULL || len < 0)
98378556Sobrien      { BZ_SETERR(BZ_PARAM_ERROR); return; };
98478556Sobrien   if (!(bzf->writing))
98578556Sobrien      { BZ_SETERR(BZ_SEQUENCE_ERROR); return; };
98678556Sobrien   if (ferror(bzf->handle))
98778556Sobrien      { BZ_SETERR(BZ_IO_ERROR); return; };
98878556Sobrien
98978556Sobrien   if (len == 0)
99078556Sobrien      { BZ_SETERR(BZ_OK); return; };
99178556Sobrien
99278556Sobrien   bzf->strm.avail_in = len;
99378556Sobrien   bzf->strm.next_in  = buf;
99478556Sobrien
99578556Sobrien   while (True) {
99678556Sobrien      bzf->strm.avail_out = BZ_MAX_UNUSED;
99778556Sobrien      bzf->strm.next_out = bzf->buf;
99878556Sobrien      ret = BZ2_bzCompress ( &(bzf->strm), BZ_RUN );
99978556Sobrien      if (ret != BZ_RUN_OK)
100078556Sobrien         { BZ_SETERR(ret); return; };
100178556Sobrien
100278556Sobrien      if (bzf->strm.avail_out < BZ_MAX_UNUSED) {
100378556Sobrien         n = BZ_MAX_UNUSED - bzf->strm.avail_out;
100478556Sobrien         n2 = fwrite ( (void*)(bzf->buf), sizeof(UChar),
100578556Sobrien                       n, bzf->handle );
100678556Sobrien         if (n != n2 || ferror(bzf->handle))
100778556Sobrien            { BZ_SETERR(BZ_IO_ERROR); return; };
100878556Sobrien      }
100978556Sobrien
101078556Sobrien      if (bzf->strm.avail_in == 0)
101178556Sobrien         { BZ_SETERR(BZ_OK); return; };
101278556Sobrien   }
101378556Sobrien}
101478556Sobrien
101578556Sobrien
101678556Sobrien/*---------------------------------------------------*/
101778556Sobrienvoid BZ_API(BZ2_bzWriteClose)
101878556Sobrien                  ( int*          bzerror,
101978556Sobrien                    BZFILE*       b,
102078556Sobrien                    int           abandon,
102178556Sobrien                    unsigned int* nbytes_in,
102278556Sobrien                    unsigned int* nbytes_out )
102378556Sobrien{
102478556Sobrien   BZ2_bzWriteClose64 ( bzerror, b, abandon,
102578556Sobrien                        nbytes_in, NULL, nbytes_out, NULL );
102678556Sobrien}
102778556Sobrien
102878556Sobrien
102978556Sobrienvoid BZ_API(BZ2_bzWriteClose64)
103078556Sobrien                  ( int*          bzerror,
103178556Sobrien                    BZFILE*       b,
103278556Sobrien                    int           abandon,
103378556Sobrien                    unsigned int* nbytes_in_lo32,
103478556Sobrien                    unsigned int* nbytes_in_hi32,
103578556Sobrien                    unsigned int* nbytes_out_lo32,
103678556Sobrien                    unsigned int* nbytes_out_hi32 )
103778556Sobrien{
103878556Sobrien   Int32   n, n2, ret;
103978556Sobrien   bzFile* bzf = (bzFile*)b;
104078556Sobrien
104178556Sobrien   if (bzf == NULL)
104278556Sobrien      { BZ_SETERR(BZ_OK); return; };
104378556Sobrien   if (!(bzf->writing))
104478556Sobrien      { BZ_SETERR(BZ_SEQUENCE_ERROR); return; };
104578556Sobrien   if (ferror(bzf->handle))
104678556Sobrien      { BZ_SETERR(BZ_IO_ERROR); return; };
104778556Sobrien
104878556Sobrien   if (nbytes_in_lo32 != NULL) *nbytes_in_lo32 = 0;
104978556Sobrien   if (nbytes_in_hi32 != NULL) *nbytes_in_hi32 = 0;
105078556Sobrien   if (nbytes_out_lo32 != NULL) *nbytes_out_lo32 = 0;
105178556Sobrien   if (nbytes_out_hi32 != NULL) *nbytes_out_hi32 = 0;
105278556Sobrien
105378556Sobrien   if ((!abandon) && bzf->lastErr == BZ_OK) {
105478556Sobrien      while (True) {
105578556Sobrien         bzf->strm.avail_out = BZ_MAX_UNUSED;
105678556Sobrien         bzf->strm.next_out = bzf->buf;
105778556Sobrien         ret = BZ2_bzCompress ( &(bzf->strm), BZ_FINISH );
105878556Sobrien         if (ret != BZ_FINISH_OK && ret != BZ_STREAM_END)
105978556Sobrien            { BZ_SETERR(ret); return; };
106078556Sobrien
106178556Sobrien         if (bzf->strm.avail_out < BZ_MAX_UNUSED) {
106278556Sobrien            n = BZ_MAX_UNUSED - bzf->strm.avail_out;
106378556Sobrien            n2 = fwrite ( (void*)(bzf->buf), sizeof(UChar),
106478556Sobrien                          n, bzf->handle );
106578556Sobrien            if (n != n2 || ferror(bzf->handle))
106678556Sobrien               { BZ_SETERR(BZ_IO_ERROR); return; };
106778556Sobrien         }
106878556Sobrien
106978556Sobrien         if (ret == BZ_STREAM_END) break;
107078556Sobrien      }
107178556Sobrien   }
107278556Sobrien
107378556Sobrien   if ( !abandon && !ferror ( bzf->handle ) ) {
107478556Sobrien      fflush ( bzf->handle );
107578556Sobrien      if (ferror(bzf->handle))
107678556Sobrien         { BZ_SETERR(BZ_IO_ERROR); return; };
107778556Sobrien   }
107878556Sobrien
107978556Sobrien   if (nbytes_in_lo32 != NULL)
108078556Sobrien      *nbytes_in_lo32 = bzf->strm.total_in_lo32;
108178556Sobrien   if (nbytes_in_hi32 != NULL)
108278556Sobrien      *nbytes_in_hi32 = bzf->strm.total_in_hi32;
108378556Sobrien   if (nbytes_out_lo32 != NULL)
108478556Sobrien      *nbytes_out_lo32 = bzf->strm.total_out_lo32;
108578556Sobrien   if (nbytes_out_hi32 != NULL)
108678556Sobrien      *nbytes_out_hi32 = bzf->strm.total_out_hi32;
108778556Sobrien
108878556Sobrien   BZ_SETERR(BZ_OK);
108978556Sobrien   BZ2_bzCompressEnd ( &(bzf->strm) );
109078556Sobrien   free ( bzf );
109178556Sobrien}
109278556Sobrien
109378556Sobrien
109478556Sobrien/*---------------------------------------------------*/
109578556SobrienBZFILE* BZ_API(BZ2_bzReadOpen)
109678556Sobrien                   ( int*  bzerror,
109778556Sobrien                     FILE* f,
109878556Sobrien                     int   verbosity,
109978556Sobrien                     int   small,
110078556Sobrien                     void* unused,
110178556Sobrien                     int   nUnused )
110278556Sobrien{
110378556Sobrien   bzFile* bzf = NULL;
110478556Sobrien   int     ret;
110578556Sobrien
110678556Sobrien   BZ_SETERR(BZ_OK);
110778556Sobrien
110878556Sobrien   if (f == NULL ||
110978556Sobrien       (small != 0 && small != 1) ||
111078556Sobrien       (verbosity < 0 || verbosity > 4) ||
111178556Sobrien       (unused == NULL && nUnused != 0) ||
111278556Sobrien       (unused != NULL && (nUnused < 0 || nUnused > BZ_MAX_UNUSED)))
111378556Sobrien      { BZ_SETERR(BZ_PARAM_ERROR); return NULL; };
111478556Sobrien
111578556Sobrien   if (ferror(f))
111678556Sobrien      { BZ_SETERR(BZ_IO_ERROR); return NULL; };
111778556Sobrien
111878556Sobrien   bzf = malloc ( sizeof(bzFile) );
111978556Sobrien   if (bzf == NULL)
112078556Sobrien      { BZ_SETERR(BZ_MEM_ERROR); return NULL; };
112178556Sobrien
112278556Sobrien   BZ_SETERR(BZ_OK);
112378556Sobrien
112478556Sobrien   bzf->initialisedOk = False;
112578556Sobrien   bzf->handle        = f;
112678556Sobrien   bzf->bufN          = 0;
112778556Sobrien   bzf->writing       = False;
112878556Sobrien   bzf->strm.bzalloc  = NULL;
112978556Sobrien   bzf->strm.bzfree   = NULL;
113078556Sobrien   bzf->strm.opaque   = NULL;
113178556Sobrien
113278556Sobrien   while (nUnused > 0) {
113378556Sobrien      bzf->buf[bzf->bufN] = *((UChar*)(unused)); bzf->bufN++;
113478556Sobrien      unused = ((void*)( 1 + ((UChar*)(unused))  ));
113578556Sobrien      nUnused--;
113678556Sobrien   }
113778556Sobrien
113878556Sobrien   ret = BZ2_bzDecompressInit ( &(bzf->strm), verbosity, small );
113978556Sobrien   if (ret != BZ_OK)
114078556Sobrien      { BZ_SETERR(ret); free(bzf); return NULL; };
114178556Sobrien
114278556Sobrien   bzf->strm.avail_in = bzf->bufN;
114378556Sobrien   bzf->strm.next_in  = bzf->buf;
114478556Sobrien
114578556Sobrien   bzf->initialisedOk = True;
114678556Sobrien   return bzf;
114778556Sobrien}
114878556Sobrien
114978556Sobrien
115078556Sobrien/*---------------------------------------------------*/
115178556Sobrienvoid BZ_API(BZ2_bzReadClose) ( int *bzerror, BZFILE *b )
115278556Sobrien{
115378556Sobrien   bzFile* bzf = (bzFile*)b;
115478556Sobrien
115578556Sobrien   BZ_SETERR(BZ_OK);
115678556Sobrien   if (bzf == NULL)
115778556Sobrien      { BZ_SETERR(BZ_OK); return; };
115878556Sobrien
115978556Sobrien   if (bzf->writing)
116078556Sobrien      { BZ_SETERR(BZ_SEQUENCE_ERROR); return; };
116178556Sobrien
116278556Sobrien   if (bzf->initialisedOk)
116378556Sobrien      (void)BZ2_bzDecompressEnd ( &(bzf->strm) );
116478556Sobrien   free ( bzf );
116578556Sobrien}
116678556Sobrien
116778556Sobrien
116878556Sobrien/*---------------------------------------------------*/
116978556Sobrienint BZ_API(BZ2_bzRead)
117078556Sobrien           ( int*    bzerror,
117178556Sobrien             BZFILE* b,
117278556Sobrien             void*   buf,
117378556Sobrien             int     len )
117478556Sobrien{
117578556Sobrien   Int32   n, ret;
117678556Sobrien   bzFile* bzf = (bzFile*)b;
117778556Sobrien
117878556Sobrien   BZ_SETERR(BZ_OK);
117978556Sobrien
118078556Sobrien   if (bzf == NULL || buf == NULL || len < 0)
118178556Sobrien      { BZ_SETERR(BZ_PARAM_ERROR); return 0; };
118278556Sobrien
118378556Sobrien   if (bzf->writing)
118478556Sobrien      { BZ_SETERR(BZ_SEQUENCE_ERROR); return 0; };
118578556Sobrien
118678556Sobrien   if (len == 0)
118778556Sobrien      { BZ_SETERR(BZ_OK); return 0; };
118878556Sobrien
118978556Sobrien   bzf->strm.avail_out = len;
119078556Sobrien   bzf->strm.next_out = buf;
119178556Sobrien
119278556Sobrien   while (True) {
119378556Sobrien
119478556Sobrien      if (ferror(bzf->handle))
119578556Sobrien         { BZ_SETERR(BZ_IO_ERROR); return 0; };
119678556Sobrien
119778556Sobrien      if (bzf->strm.avail_in == 0 && !myfeof(bzf->handle)) {
119878556Sobrien         n = fread ( bzf->buf, sizeof(UChar),
119978556Sobrien                     BZ_MAX_UNUSED, bzf->handle );
120078556Sobrien         if (ferror(bzf->handle))
120178556Sobrien            { BZ_SETERR(BZ_IO_ERROR); return 0; };
120278556Sobrien         bzf->bufN = n;
120378556Sobrien         bzf->strm.avail_in = bzf->bufN;
120478556Sobrien         bzf->strm.next_in = bzf->buf;
120578556Sobrien      }
120678556Sobrien
120778556Sobrien      ret = BZ2_bzDecompress ( &(bzf->strm) );
120878556Sobrien
120978556Sobrien      if (ret != BZ_OK && ret != BZ_STREAM_END)
121078556Sobrien         { BZ_SETERR(ret); return 0; };
121178556Sobrien
121278556Sobrien      if (ret == BZ_OK && myfeof(bzf->handle) &&
121378556Sobrien          bzf->strm.avail_in == 0 && bzf->strm.avail_out > 0)
121478556Sobrien         { BZ_SETERR(BZ_UNEXPECTED_EOF); return 0; };
121578556Sobrien
121678556Sobrien      if (ret == BZ_STREAM_END)
121778556Sobrien         { BZ_SETERR(BZ_STREAM_END);
121878556Sobrien           return len - bzf->strm.avail_out; };
121978556Sobrien      if (bzf->strm.avail_out == 0)
122078556Sobrien         { BZ_SETERR(BZ_OK); return len; };
122178556Sobrien
122278556Sobrien   }
122378556Sobrien
122478556Sobrien   return 0; /*not reached*/
122578556Sobrien}
122678556Sobrien
122778556Sobrien
122878556Sobrien/*---------------------------------------------------*/
122978556Sobrienvoid BZ_API(BZ2_bzReadGetUnused)
123078556Sobrien                     ( int*    bzerror,
123178556Sobrien                       BZFILE* b,
123278556Sobrien                       void**  unused,
123378556Sobrien                       int*    nUnused )
123478556Sobrien{
123578556Sobrien   bzFile* bzf = (bzFile*)b;
123678556Sobrien   if (bzf == NULL)
123778556Sobrien      { BZ_SETERR(BZ_PARAM_ERROR); return; };
123878556Sobrien   if (bzf->lastErr != BZ_STREAM_END)
123978556Sobrien      { BZ_SETERR(BZ_SEQUENCE_ERROR); return; };
124078556Sobrien   if (unused == NULL || nUnused == NULL)
124178556Sobrien      { BZ_SETERR(BZ_PARAM_ERROR); return; };
124278556Sobrien
124378556Sobrien   BZ_SETERR(BZ_OK);
124478556Sobrien   *nUnused = bzf->strm.avail_in;
124578556Sobrien   *unused = bzf->strm.next_in;
124678556Sobrien}
124778556Sobrien#endif
124878556Sobrien
124978556Sobrien
125078556Sobrien/*---------------------------------------------------*/
125178556Sobrien/*--- Misc convenience stuff                      ---*/
125278556Sobrien/*---------------------------------------------------*/
125378556Sobrien
125478556Sobrien/*---------------------------------------------------*/
125578556Sobrienint BZ_API(BZ2_bzBuffToBuffCompress)
125678556Sobrien                         ( char*         dest,
125778556Sobrien                           unsigned int* destLen,
125878556Sobrien                           char*         source,
125978556Sobrien                           unsigned int  sourceLen,
126078556Sobrien                           int           blockSize100k,
126178556Sobrien                           int           verbosity,
126278556Sobrien                           int           workFactor )
126378556Sobrien{
126478556Sobrien   bz_stream strm;
126578556Sobrien   int ret;
126678556Sobrien
126778556Sobrien   if (dest == NULL || destLen == NULL ||
126878556Sobrien       source == NULL ||
126978556Sobrien       blockSize100k < 1 || blockSize100k > 9 ||
127078556Sobrien       verbosity < 0 || verbosity > 4 ||
127178556Sobrien       workFactor < 0 || workFactor > 250)
127278556Sobrien      return BZ_PARAM_ERROR;
127378556Sobrien
127478556Sobrien   if (workFactor == 0) workFactor = 30;
127578556Sobrien   strm.bzalloc = NULL;
127678556Sobrien   strm.bzfree = NULL;
127778556Sobrien   strm.opaque = NULL;
127878556Sobrien   ret = BZ2_bzCompressInit ( &strm, blockSize100k,
127978556Sobrien                              verbosity, workFactor );
128078556Sobrien   if (ret != BZ_OK) return ret;
128178556Sobrien
128278556Sobrien   strm.next_in = source;
128378556Sobrien   strm.next_out = dest;
128478556Sobrien   strm.avail_in = sourceLen;
128578556Sobrien   strm.avail_out = *destLen;
128678556Sobrien
128778556Sobrien   ret = BZ2_bzCompress ( &strm, BZ_FINISH );
128878556Sobrien   if (ret == BZ_FINISH_OK) goto output_overflow;
128978556Sobrien   if (ret != BZ_STREAM_END) goto errhandler;
129078556Sobrien
129178556Sobrien   /* normal termination */
129278556Sobrien   *destLen -= strm.avail_out;
129378556Sobrien   BZ2_bzCompressEnd ( &strm );
129478556Sobrien   return BZ_OK;
129578556Sobrien
129678556Sobrien   output_overflow:
129778556Sobrien   BZ2_bzCompressEnd ( &strm );
129878556Sobrien   return BZ_OUTBUFF_FULL;
129978556Sobrien
130078556Sobrien   errhandler:
130178556Sobrien   BZ2_bzCompressEnd ( &strm );
130278556Sobrien   return ret;
130378556Sobrien}
130478556Sobrien
130578556Sobrien
130678556Sobrien/*---------------------------------------------------*/
130778556Sobrienint BZ_API(BZ2_bzBuffToBuffDecompress)
130878556Sobrien                           ( char*         dest,
130978556Sobrien                             unsigned int* destLen,
131078556Sobrien                             char*         source,
131178556Sobrien                             unsigned int  sourceLen,
131278556Sobrien                             int           small,
131378556Sobrien                             int           verbosity )
131478556Sobrien{
131578556Sobrien   bz_stream strm;
131678556Sobrien   int ret;
131778556Sobrien
131878556Sobrien   if (dest == NULL || destLen == NULL ||
131978556Sobrien       source == NULL ||
132078556Sobrien       (small != 0 && small != 1) ||
132178556Sobrien       verbosity < 0 || verbosity > 4)
132278556Sobrien          return BZ_PARAM_ERROR;
132378556Sobrien
132478556Sobrien   strm.bzalloc = NULL;
132578556Sobrien   strm.bzfree = NULL;
132678556Sobrien   strm.opaque = NULL;
132778556Sobrien   ret = BZ2_bzDecompressInit ( &strm, verbosity, small );
132878556Sobrien   if (ret != BZ_OK) return ret;
132978556Sobrien
133078556Sobrien   strm.next_in = source;
133178556Sobrien   strm.next_out = dest;
133278556Sobrien   strm.avail_in = sourceLen;
133378556Sobrien   strm.avail_out = *destLen;
133478556Sobrien
133578556Sobrien   ret = BZ2_bzDecompress ( &strm );
133678556Sobrien   if (ret == BZ_OK) goto output_overflow_or_eof;
133778556Sobrien   if (ret != BZ_STREAM_END) goto errhandler;
133878556Sobrien
133978556Sobrien   /* normal termination */
134078556Sobrien   *destLen -= strm.avail_out;
134178556Sobrien   BZ2_bzDecompressEnd ( &strm );
134278556Sobrien   return BZ_OK;
134378556Sobrien
134478556Sobrien   output_overflow_or_eof:
134578556Sobrien   if (strm.avail_out > 0) {
134678556Sobrien      BZ2_bzDecompressEnd ( &strm );
134778556Sobrien      return BZ_UNEXPECTED_EOF;
134878556Sobrien   } else {
134978556Sobrien      BZ2_bzDecompressEnd ( &strm );
135078556Sobrien      return BZ_OUTBUFF_FULL;
135178556Sobrien   };
135278556Sobrien
135378556Sobrien   errhandler:
135478556Sobrien   BZ2_bzDecompressEnd ( &strm );
135578556Sobrien   return ret;
135678556Sobrien}
135778556Sobrien
135878556Sobrien
135978556Sobrien/*---------------------------------------------------*/
136078556Sobrien/*--
1361167978Sdelphij   Code contributed by Yoshioka Tsuneo (tsuneo@rr.iij4u.or.jp)
136278556Sobrien   to support better zlib compatibility.
136378556Sobrien   This code is not _officially_ part of libbzip2 (yet);
136478556Sobrien   I haven't tested it, documented it, or considered the
136578556Sobrien   threading-safeness of it.
136678556Sobrien   If this code breaks, please contact both Yoshioka and me.
136778556Sobrien--*/
136878556Sobrien/*---------------------------------------------------*/
136978556Sobrien
137078556Sobrien/*---------------------------------------------------*/
137178556Sobrien/*--
1372167978Sdelphij   return version like "0.9.5d, 4-Sept-1999".
137378556Sobrien--*/
137478556Sobrienconst char * BZ_API(BZ2_bzlibVersion)(void)
137578556Sobrien{
137678556Sobrien   return BZ_VERSION;
137778556Sobrien}
137878556Sobrien
137978556Sobrien
138078556Sobrien#ifndef BZ_NO_STDIO
138178556Sobrien/*---------------------------------------------------*/
138278556Sobrien
138378556Sobrien#if defined(_WIN32) || defined(OS2) || defined(MSDOS)
138478556Sobrien#   include <fcntl.h>
138578556Sobrien#   include <io.h>
138678556Sobrien#   define SET_BINARY_MODE(file) setmode(fileno(file),O_BINARY)
138778556Sobrien#else
138878556Sobrien#   define SET_BINARY_MODE(file)
138978556Sobrien#endif
139078556Sobrienstatic
139178556SobrienBZFILE * bzopen_or_bzdopen
139278556Sobrien               ( const char *path,   /* no use when bzdopen */
139378556Sobrien                 int fd,             /* no use when bzdopen */
139478556Sobrien                 const char *mode,
139578556Sobrien                 int open_mode)      /* bzopen: 0, bzdopen:1 */
139678556Sobrien{
139778556Sobrien   int    bzerr;
139878556Sobrien   char   unused[BZ_MAX_UNUSED];
139978556Sobrien   int    blockSize100k = 9;
140078556Sobrien   int    writing       = 0;
140178556Sobrien   char   mode2[10]     = "";
140278556Sobrien   FILE   *fp           = NULL;
140378556Sobrien   BZFILE *bzfp         = NULL;
140478556Sobrien   int    verbosity     = 0;
140578556Sobrien   int    workFactor    = 30;
140678556Sobrien   int    smallMode     = 0;
140778556Sobrien   int    nUnused       = 0;
140878556Sobrien
140978556Sobrien   if (mode == NULL) return NULL;
141078556Sobrien   while (*mode) {
141178556Sobrien      switch (*mode) {
141278556Sobrien      case 'r':
141378556Sobrien         writing = 0; break;
141478556Sobrien      case 'w':
141578556Sobrien         writing = 1; break;
141678556Sobrien      case 's':
141778556Sobrien         smallMode = 1; break;
141878556Sobrien      default:
141978556Sobrien         if (isdigit((int)(*mode))) {
142090067Ssobomax            blockSize100k = *mode-BZ_HDR_0;
142178556Sobrien         }
142278556Sobrien      }
142378556Sobrien      mode++;
142478556Sobrien   }
142578556Sobrien   strcat(mode2, writing ? "w" : "r" );
142678556Sobrien   strcat(mode2,"b");   /* binary mode */
142778556Sobrien
142878556Sobrien   if (open_mode==0) {
142978556Sobrien      if (path==NULL || strcmp(path,"")==0) {
143078556Sobrien        fp = (writing ? stdout : stdin);
143178556Sobrien        SET_BINARY_MODE(fp);
143278556Sobrien      } else {
143378556Sobrien        fp = fopen(path,mode2);
143478556Sobrien      }
143578556Sobrien   } else {
143678556Sobrien#ifdef BZ_STRICT_ANSI
143778556Sobrien      fp = NULL;
143878556Sobrien#else
143978556Sobrien      fp = fdopen(fd,mode2);
144078556Sobrien#endif
144178556Sobrien   }
144278556Sobrien   if (fp == NULL) return NULL;
144378556Sobrien
144478556Sobrien   if (writing) {
144578556Sobrien      /* Guard against total chaos and anarchy -- JRS */
144678556Sobrien      if (blockSize100k < 1) blockSize100k = 1;
144778556Sobrien      if (blockSize100k > 9) blockSize100k = 9;
144878556Sobrien      bzfp = BZ2_bzWriteOpen(&bzerr,fp,blockSize100k,
144978556Sobrien                             verbosity,workFactor);
145078556Sobrien   } else {
145178556Sobrien      bzfp = BZ2_bzReadOpen(&bzerr,fp,verbosity,smallMode,
145278556Sobrien                            unused,nUnused);
145378556Sobrien   }
145478556Sobrien   if (bzfp == NULL) {
145578556Sobrien      if (fp != stdin && fp != stdout) fclose(fp);
145678556Sobrien      return NULL;
145778556Sobrien   }
145878556Sobrien   return bzfp;
145978556Sobrien}
146078556Sobrien
146178556Sobrien
146278556Sobrien/*---------------------------------------------------*/
146378556Sobrien/*--
146478556Sobrien   open file for read or write.
146578556Sobrien      ex) bzopen("file","w9")
146678556Sobrien      case path="" or NULL => use stdin or stdout.
146778556Sobrien--*/
146878556SobrienBZFILE * BZ_API(BZ2_bzopen)
146978556Sobrien               ( const char *path,
147078556Sobrien                 const char *mode )
147178556Sobrien{
147278556Sobrien   return bzopen_or_bzdopen(path,-1,mode,/*bzopen*/0);
147378556Sobrien}
147478556Sobrien
147578556Sobrien
147678556Sobrien/*---------------------------------------------------*/
147778556SobrienBZFILE * BZ_API(BZ2_bzdopen)
147878556Sobrien               ( int fd,
147978556Sobrien                 const char *mode )
148078556Sobrien{
148178556Sobrien   return bzopen_or_bzdopen(NULL,fd,mode,/*bzdopen*/1);
148278556Sobrien}
148378556Sobrien
148478556Sobrien
148578556Sobrien/*---------------------------------------------------*/
148678556Sobrienint BZ_API(BZ2_bzread) (BZFILE* b, void* buf, int len )
148778556Sobrien{
148878556Sobrien   int bzerr, nread;
148978556Sobrien   if (((bzFile*)b)->lastErr == BZ_STREAM_END) return 0;
149078556Sobrien   nread = BZ2_bzRead(&bzerr,b,buf,len);
149178556Sobrien   if (bzerr == BZ_OK || bzerr == BZ_STREAM_END) {
149278556Sobrien      return nread;
149378556Sobrien   } else {
149478556Sobrien      return -1;
149578556Sobrien   }
149678556Sobrien}
149778556Sobrien
149878556Sobrien
149978556Sobrien/*---------------------------------------------------*/
150078556Sobrienint BZ_API(BZ2_bzwrite) (BZFILE* b, void* buf, int len )
150178556Sobrien{
150278556Sobrien   int bzerr;
150378556Sobrien
150478556Sobrien   BZ2_bzWrite(&bzerr,b,buf,len);
150578556Sobrien   if(bzerr == BZ_OK){
150678556Sobrien      return len;
150778556Sobrien   }else{
150878556Sobrien      return -1;
150978556Sobrien   }
151078556Sobrien}
151178556Sobrien
151278556Sobrien
151378556Sobrien/*---------------------------------------------------*/
151478556Sobrienint BZ_API(BZ2_bzflush) (BZFILE *b)
151578556Sobrien{
151678556Sobrien   /* do nothing now... */
151778556Sobrien   return 0;
151878556Sobrien}
151978556Sobrien
152078556Sobrien
152178556Sobrien/*---------------------------------------------------*/
152278556Sobrienvoid BZ_API(BZ2_bzclose) (BZFILE* b)
152378556Sobrien{
152478556Sobrien   int bzerr;
1525167978Sdelphij   FILE *fp;
152678556Sobrien
152778556Sobrien   if (b==NULL) {return;}
1528167978Sdelphij   fp = ((bzFile *)b)->handle;
152978556Sobrien   if(((bzFile*)b)->writing){
153078556Sobrien      BZ2_bzWriteClose(&bzerr,b,0,NULL,NULL);
153178556Sobrien      if(bzerr != BZ_OK){
153278556Sobrien         BZ2_bzWriteClose(NULL,b,1,NULL,NULL);
153378556Sobrien      }
153478556Sobrien   }else{
153578556Sobrien      BZ2_bzReadClose(&bzerr,b);
153678556Sobrien   }
153778556Sobrien   if(fp!=stdin && fp!=stdout){
153878556Sobrien      fclose(fp);
153978556Sobrien   }
154078556Sobrien}
154178556Sobrien
154278556Sobrien
154378556Sobrien/*---------------------------------------------------*/
154478556Sobrien/*--
154578556Sobrien   return last error code
154678556Sobrien--*/
1547167978Sdelphijstatic const char *bzerrorstrings[] = {
154878556Sobrien       "OK"
154978556Sobrien      ,"SEQUENCE_ERROR"
155078556Sobrien      ,"PARAM_ERROR"
155178556Sobrien      ,"MEM_ERROR"
155278556Sobrien      ,"DATA_ERROR"
155378556Sobrien      ,"DATA_ERROR_MAGIC"
155478556Sobrien      ,"IO_ERROR"
155578556Sobrien      ,"UNEXPECTED_EOF"
155678556Sobrien      ,"OUTBUFF_FULL"
155778556Sobrien      ,"CONFIG_ERROR"
155878556Sobrien      ,"???"   /* for future */
155978556Sobrien      ,"???"   /* for future */
156078556Sobrien      ,"???"   /* for future */
156178556Sobrien      ,"???"   /* for future */
156278556Sobrien      ,"???"   /* for future */
156378556Sobrien      ,"???"   /* for future */
156478556Sobrien};
156578556Sobrien
156678556Sobrien
156778556Sobrienconst char * BZ_API(BZ2_bzerror) (BZFILE *b, int *errnum)
156878556Sobrien{
156978556Sobrien   int err = ((bzFile *)b)->lastErr;
157078556Sobrien
157178556Sobrien   if(err>0) err = 0;
157278556Sobrien   *errnum = err;
157378556Sobrien   return bzerrorstrings[err*-1];
157478556Sobrien}
157578556Sobrien#endif
157678556Sobrien
1577146788Ssobomax#endif /* BZ_NO_COMPRESS */
157878556Sobrien
157978556Sobrien/*-------------------------------------------------------------*/
158078556Sobrien/*--- end                                           bzlib.c ---*/
158178556Sobrien/*-------------------------------------------------------------*/
1582