split inflate_xx_setup() subroutines from inflate_xx()

This commit is contained in:
Denis Vlasenko 2007-01-05 23:58:45 +00:00
parent cd42cb8df0
commit d1a19affeb

View File

@ -45,22 +45,25 @@ typedef struct huft_s {
} v; } v;
} huft_t; } huft_t;
enum {
/* gunzip_window size--must be a power of two, and
* at least 32K for zip's deflate method */
GUNZIP_WSIZE = 0x8000,
/* If BMAX needs to be larger than 16, then h and x[] should be ulg. */
BMAX = 16, /* maximum bit length of any code (16 for explode) */
N_MAX = 288, /* maximum number of codes in any set */
};
static off_t gunzip_bytes_out; /* number of output bytes */ static off_t gunzip_bytes_out; /* number of output bytes */
static uint32_t gunzip_crc; static uint32_t gunzip_crc;
static int gunzip_src_fd; static int gunzip_src_fd;
static unsigned gunzip_outbuf_count; /* bytes in output buffer */ static unsigned gunzip_outbuf_count; /* bytes in output buffer */
/* gunzip_window size--must be a power of two, and
* at least 32K for zip's deflate method */
enum { gunzip_wsize = 0x8000 };
static unsigned char *gunzip_window; static unsigned char *gunzip_window;
static uint32_t *gunzip_crc_table; static uint32_t *gunzip_crc_table;
/* If BMAX needs to be larger than 16, then h and x[] should be ulg. */
#define BMAX 16 /* maximum bit length of any code (16 for explode) */
#define N_MAX 288 /* maximum number of codes in any set */
/* bitbuffer */ /* bitbuffer */
static unsigned gunzip_bb; /* bit buffer */ static unsigned gunzip_bb; /* bit buffer */
@ -135,19 +138,16 @@ static unsigned fill_bitbuffer(unsigned bitbuffer, unsigned *current, const unsi
* each table. * each table.
* t: table to free * t: table to free
*/ */
static int huft_free(huft_t * t) static void huft_free(huft_t * p)
{ {
huft_t *p;
huft_t *q; huft_t *q;
/* Go through linked list, freeing from the malloced (t[-1]) address. */ /* Go through linked list, freeing from the malloced (t[-1]) address. */
p = t; while (p) {
while (p != (huft_t *) NULL) {
q = (--p)->v.t; q = (--p)->v.t;
free((char *) p); free(p);
p = q; p = q;
} }
return 0;
} }
/* Given a list of code lengths and a maximum table size, make a set of /* Given a list of code lengths and a maximum table size, make a set of
@ -339,6 +339,7 @@ static int huft_build(unsigned *b, const unsigned n,
return y != 0 && g != 1; return y != 0 && g != 1;
} }
/* /*
* inflate (decompress) the codes in a deflated (compressed) block. * inflate (decompress) the codes in a deflated (compressed) block.
* Return an error code or zero if it all goes ok. * Return an error code or zero if it all goes ok.
@ -346,106 +347,116 @@ static int huft_build(unsigned *b, const unsigned n,
* tl, td: literal/length and distance decoder tables * tl, td: literal/length and distance decoder tables
* bl, bd: number of bits decoded by tl[] and td[] * bl, bd: number of bits decoded by tl[] and td[]
*/ */
/* called with setup==1 once from inflate_block */ /* called once from inflate_block */
/* called once with setup==0 from inflate_get_next_window */ #define ml inflate_codes_ml
static int inflate_codes(huft_t * my_tl, huft_t * my_td, const unsigned my_bl, const unsigned my_bd, int setup) #define md inflate_codes_md
{ #define bb inflate_codes_bb
static unsigned e; /* table entry flag/number of extra bits */ #define k inflate_codes_k
static unsigned n, d; /* length and index for copy */ #define w inflate_codes_w
static unsigned w; /* current gunzip_window position */ #define tl inflate_codes_tl
static huft_t *t; /* pointer to table entry */ #define td inflate_codes_td
#define bl inflate_codes_bl
#define bd inflate_codes_bd
static unsigned ml, md; /* masks for bl and bd bits */ static unsigned ml, md; /* masks for bl and bd bits */
static unsigned b; /* bit buffer */ static unsigned bb; /* bit buffer */
static unsigned k; /* number of bits in bit buffer */ static unsigned k; /* number of bits in bit buffer */
static unsigned w; /* current gunzip_window position */
static huft_t *tl, *td; static huft_t *tl, *td;
static unsigned bl, bd; static unsigned bl, bd;
static int resumeCopy = 0; static int resumeCopy; /* = 0; */
static void inflate_codes_setup(huft_t * my_tl, huft_t * my_td, const unsigned my_bl, const unsigned my_bd)
if (setup) { // 1st time we are called, copy in variables {
tl = my_tl; tl = my_tl;
td = my_td; td = my_td;
bl = my_bl; bl = my_bl;
bd = my_bd; bd = my_bd;
/* make local copies of globals */ /* make local copies of globals */
b = gunzip_bb; /* initialize bit buffer */ bb = gunzip_bb; /* initialize bit buffer */
k = gunzip_bk; k = gunzip_bk;
w = gunzip_outbuf_count; /* initialize gunzip_window position */ w = gunzip_outbuf_count; /* initialize gunzip_window position */
/* inflate the coded data */ /* inflate the coded data */
ml = mask_bits[bl]; /* precompute masks for speed */ ml = mask_bits[bl]; /* precompute masks for speed */
md = mask_bits[bd]; md = mask_bits[bd];
return 0; // Don't actually do anything the first time
} }
/* called once from inflate_get_next_window */
static int inflate_codes(void)
{
unsigned e; /* table entry flag/number of extra bits */
huft_t *t; /* pointer to table entry */
if (resumeCopy) goto do_copy; if (resumeCopy) goto do_copy;
while (1) { /* do until end of block */ while (1) { /* do until end of block */
b = fill_bitbuffer(b, &k, bl); bb = fill_bitbuffer(bb, &k, bl);
t = tl + ((unsigned) b & ml); t = tl + ((unsigned) bb & ml);
e = t->e; e = t->e;
if (e > 16) if (e > 16)
do { do {
if (e == 99) { if (e == 99) {
bb_error_msg_and_die("inflate_codes error 1"); bb_error_msg_and_die("inflate_codes error 1");
} }
b >>= t->b; bb >>= t->b;
k -= t->b; k -= t->b;
e -= 16; e -= 16;
b = fill_bitbuffer(b, &k, e); bb = fill_bitbuffer(bb, &k, e);
t = t->v.t + ((unsigned) b & mask_bits[e]); t = t->v.t + ((unsigned) bb & mask_bits[e]);
e = t->e; e = t->e;
} while (e > 16); } while (e > 16);
b >>= t->b; bb >>= t->b;
k -= t->b; k -= t->b;
if (e == 16) { /* then it's a literal */ if (e == 16) { /* then it's a literal */
gunzip_window[w++] = (unsigned char) t->v.n; gunzip_window[w++] = (unsigned char) t->v.n;
if (w == gunzip_wsize) { if (w == GUNZIP_WSIZE) {
gunzip_outbuf_count = (w); gunzip_outbuf_count = w;
//flush_gunzip_window(); //flush_gunzip_window();
w = 0; w = 0;
return 1; // We have a block to read return 1; // We have a block to read
} }
} else { /* it's an EOB or a length */ } else { /* it's an EOB or a length */
/* length and index for copy */
unsigned n = n; /* for gcc */
unsigned d = d; /* for gcc */
/* exit if end of block */ /* exit if end of block */
if (e == 15) { if (e == 15) {
break; break;
} }
/* get length of block to copy */ /* get length of block to copy */
b = fill_bitbuffer(b, &k, e); bb = fill_bitbuffer(bb, &k, e);
n = t->v.n + ((unsigned) b & mask_bits[e]); n = t->v.n + ((unsigned) bb & mask_bits[e]);
b >>= e; bb >>= e;
k -= e; k -= e;
/* decode distance of block to copy */ /* decode distance of block to copy */
b = fill_bitbuffer(b, &k, bd); bb = fill_bitbuffer(bb, &k, bd);
t = td + ((unsigned) b & md); t = td + ((unsigned) bb & md);
e = t->e; e = t->e;
if (e > 16) if (e > 16)
do { do {
if (e == 99) if (e == 99)
bb_error_msg_and_die("inflate_codes error 2"); bb_error_msg_and_die("inflate_codes error 2");
b >>= t->b; bb >>= t->b;
k -= t->b; k -= t->b;
e -= 16; e -= 16;
b = fill_bitbuffer(b, &k, e); bb = fill_bitbuffer(bb, &k, e);
t = t->v.t + ((unsigned) b & mask_bits[e]); t = t->v.t + ((unsigned) bb & mask_bits[e]);
e = t->e; e = t->e;
} while (e > 16); } while (e > 16);
b >>= t->b; bb >>= t->b;
k -= t->b; k -= t->b;
b = fill_bitbuffer(b, &k, e); bb = fill_bitbuffer(bb, &k, e);
d = w - t->v.n - ((unsigned) b & mask_bits[e]); d = w - t->v.n - ((unsigned) bb & mask_bits[e]);
b >>= e; bb >>= e;
k -= e; k -= e;
/* do the copy */ /* do the copy */
do_copy: do_copy:
do { do {
/* Was: n -= (e = (e = gunzip_wsize - ((d &= gunzip_wsize - 1) > w ? d : w)) > n ? n : e); */ /* Was: n -= (e = (e = GUNZIP_WSIZE - ((d &= GUNZIP_WSIZE - 1) > w ? d : w)) > n ? n : e); */
/* Who wrote THAT?? rewritten as: */ /* Who wrote THAT?? rewritten as: */
d &= gunzip_wsize - 1; d &= GUNZIP_WSIZE - 1;
e = gunzip_wsize - (d > w ? d : w); e = GUNZIP_WSIZE - (d > w ? d : w);
if (e > n) e = n; if (e > n) e = n;
n -= e; n -= e;
@ -461,8 +472,8 @@ static int inflate_codes(huft_t * my_tl, huft_t * my_td, const unsigned my_bl, c
gunzip_window[w++] = gunzip_window[d++]; gunzip_window[w++] = gunzip_window[d++];
} while (--e); } while (--e);
} }
if (w == gunzip_wsize) { if (w == GUNZIP_WSIZE) {
gunzip_outbuf_count = (w); gunzip_outbuf_count = w;
resumeCopy = (n != 0); resumeCopy = (n != 0);
//flush_gunzip_window(); //flush_gunzip_window();
w = 0; w = 0;
@ -475,7 +486,7 @@ static int inflate_codes(huft_t * my_tl, huft_t * my_td, const unsigned my_bl, c
/* restore the globals from the locals */ /* restore the globals from the locals */
gunzip_outbuf_count = w; /* restore global gunzip_window pointer */ gunzip_outbuf_count = w; /* restore global gunzip_window pointer */
gunzip_bb = b; /* restore global bit buffer */ gunzip_bb = bb; /* restore global bit buffer */
gunzip_bk = k; gunzip_bk = k;
/* normally just after call to inflate_codes, but save code by putting it here */ /* normally just after call to inflate_codes, but save code by putting it here */
@ -486,44 +497,54 @@ static int inflate_codes(huft_t * my_tl, huft_t * my_td, const unsigned my_bl, c
/* done */ /* done */
return 0; return 0;
} }
#undef ml
#undef md
#undef bb
#undef k
#undef w
#undef tl
#undef td
#undef bl
#undef bd
/* called once (setup==1) from inflate_block */
/* and once (setup==0) from inflate_get_next_window */ static unsigned inflate_stored_n, inflate_stored_b, inflate_stored_k, inflate_stored_w;
static int inflate_stored(int my_n, int my_b_stored, int my_k_stored, int setup) /* called once from inflate_block */
static void inflate_stored_setup(int my_n, int my_b, int my_k)
{ {
static unsigned n, b_stored, k_stored, w; inflate_stored_n = my_n;
inflate_stored_b = my_b;
if (setup) { inflate_stored_k = my_k;
n = my_n; /* initialize gunzip_window position */
b_stored = my_b_stored; inflate_stored_w = gunzip_outbuf_count;
k_stored = my_k_stored;
w = gunzip_outbuf_count; /* initialize gunzip_window position */
return 0; // Don't do anything first time
} }
/* called once from inflate_get_next_window */
static int inflate_stored(void)
{
/* read and output the compressed data */ /* read and output the compressed data */
while (n--) { while (inflate_stored_n--) {
b_stored = fill_bitbuffer(b_stored, &k_stored, 8); inflate_stored_b = fill_bitbuffer(inflate_stored_b, &inflate_stored_k, 8);
gunzip_window[w++] = (unsigned char) b_stored; gunzip_window[inflate_stored_w++] = (unsigned char) inflate_stored_b;
if (w == gunzip_wsize) { if (inflate_stored_w == GUNZIP_WSIZE) {
gunzip_outbuf_count = (w); gunzip_outbuf_count = inflate_stored_w;
//flush_gunzip_window(); //flush_gunzip_window();
w = 0; inflate_stored_w = 0;
b_stored >>= 8; inflate_stored_b >>= 8;
k_stored -= 8; inflate_stored_k -= 8;
return 1; // We have a block return 1; // We have a block
} }
b_stored >>= 8; inflate_stored_b >>= 8;
k_stored -= 8; inflate_stored_k -= 8;
} }
/* restore the globals from the locals */ /* restore the globals from the locals */
gunzip_outbuf_count = w; /* restore global gunzip_window pointer */ gunzip_outbuf_count = inflate_stored_w; /* restore global gunzip_window pointer */
gunzip_bb = b_stored; /* restore global bit buffer */ gunzip_bb = inflate_stored_b; /* restore global bit buffer */
gunzip_bk = k_stored; gunzip_bk = inflate_stored_k;
return 0; // Finished return 0; // Finished
} }
/* /*
* decompress an inflated block * decompress an inflated block
* e: last block flag * e: last block flag
@ -589,7 +610,8 @@ static int inflate_block(int *e)
b_stored >>= 16; b_stored >>= 16;
k_stored -= 16; k_stored -= 16;
inflate_stored(n, b_stored, k_stored, 1); // Setup inflate_stored inflate_stored_setup(n, b_stored, k_stored); // Setup inflate_stored
return -1; return -1;
} }
case 1: case 1:
@ -636,7 +658,7 @@ static int inflate_block(int *e)
} }
/* decompress until an end-of-block code */ /* decompress until an end-of-block code */
inflate_codes(tl, td, bl, bd, 1); // Setup inflate_codes inflate_codes_setup(tl, td, bl, bd); // Setup inflate_codes
/* huft_free code moved into inflate_codes */ /* huft_free code moved into inflate_codes */
@ -790,7 +812,7 @@ static int inflate_block(int *e)
} }
/* decompress until an end-of-block code */ /* decompress until an end-of-block code */
inflate_codes(tl, td, bl, bd, 1); // Setup inflate_codes inflate_codes_setup(tl, td, bl, bd); // Setup inflate_codes
/* huft_free code moved into inflate_codes */ /* huft_free code moved into inflate_codes */
@ -812,7 +834,7 @@ static void calculate_gunzip_crc(void)
gunzip_bytes_out += gunzip_outbuf_count; gunzip_bytes_out += gunzip_outbuf_count;
} }
/* One callsite in inflate_unzip */ /* One callsite in inflate_unzip_internal */
static int inflate_get_next_window(void) static int inflate_get_next_window(void)
{ {
static int method = -1; // Method == -1 for stored, -2 for codes static int method = -1; // Method == -1 for stored, -2 for codes
@ -836,32 +858,36 @@ static int inflate_get_next_window(void)
} }
switch (method) { switch (method) {
case -1: ret = inflate_stored(0,0,0,0); case -1:
ret = inflate_stored();
break; break;
case -2: ret = inflate_codes(0,0,0,0,0); case -2:
ret = inflate_codes();
break; break;
default: bb_error_msg_and_die("inflate error %d", method); default:
bb_error_msg_and_die("inflate error %d", method);
} }
if (ret == 1) { if (ret == 1) {
calculate_gunzip_crc(); calculate_gunzip_crc();
return 1; // More data left return 1; // More data left
} else needAnotherBlock = 1; // End of that block } else
needAnotherBlock = 1; // End of that block
} }
/* Doesnt get here */ /* Doesnt get here */
} }
/* Called from inflate_gunzip() and archival/unzip.c */ /* Called from inflate_gunzip() and inflate_unzip() */
/* NB: bytebuffer is allocated here but freeing it is left to the caller! */
static USE_DESKTOP(long long) int static USE_DESKTOP(long long) int
inflate_unzip_internal(int in, int out) inflate_unzip_internal(int in, int out)
{ {
USE_DESKTOP(long long total = 0;) USE_DESKTOP(long long) int n = 0;
ssize_t nwrote; ssize_t nwrote;
typedef void (*sig_type) (int);
/* Allocate all global buffers (for DYN_ALLOC option) */ /* Allocate all global buffers (for DYN_ALLOC option) */
gunzip_window = xmalloc(gunzip_wsize); gunzip_window = xmalloc(GUNZIP_WSIZE);
gunzip_outbuf_count = 0; gunzip_outbuf_count = 0;
gunzip_bytes_out = 0; gunzip_bytes_out = 0;
gunzip_src_fd = in; gunzip_src_fd = in;
@ -878,20 +904,17 @@ inflate_unzip_internal(int in, int out)
bytebuffer = xmalloc(bytebuffer_max); bytebuffer = xmalloc(bytebuffer_max);
while (1) { while (1) {
int ret = inflate_get_next_window(); int r = inflate_get_next_window();
nwrote = full_write(out, gunzip_window, gunzip_outbuf_count); nwrote = full_write(out, gunzip_window, gunzip_outbuf_count);
if (nwrote != gunzip_outbuf_count) { if (nwrote != gunzip_outbuf_count) {
bb_perror_msg("write"); bb_perror_msg("write");
return -1; n = -1;
goto ret;
} }
USE_DESKTOP(total += nwrote;) USE_DESKTOP(n += nwrote;)
if (ret == 0) break; if (r == 0) break;
} }
/* Cleanup */
free(gunzip_window);
free(gunzip_crc_table);
/* Store unused bytes in a global buffer so calling applets can access it */ /* Store unused bytes in a global buffer so calling applets can access it */
if (gunzip_bk >= 8) { if (gunzip_bk >= 8) {
/* Undo too much lookahead. The next read will be byte aligned /* Undo too much lookahead. The next read will be byte aligned
@ -901,7 +924,11 @@ inflate_unzip_internal(int in, int out)
gunzip_bb >>= 8; gunzip_bb >>= 8;
gunzip_bk -= 8; gunzip_bk -= 8;
} }
return USE_DESKTOP(total) + 0; ret:
/* Cleanup */
free(gunzip_window);
free(gunzip_crc_table);
return n;
} }