/* vi: set sw=4 ts=4: */
-/* Small bzip2 deflate implementation, by Rob Landley (rob@landley.net).
+/* Small bzip2 deflate implementation, by Rob Landley (rob@landley.net).
- Based on bzip2 decompression code by Julian R Seward (jseward@acm.org),
- which also acknowledges contributions by Mike Burrows, David Wheeler,
- Peter Fenwick, Alistair Moffat, Radford Neal, Ian H. Witten,
- Robert Sedgewick, and Jon L. Bentley.
+ Based on bzip2 decompression code by Julian R Seward (jseward@acm.org),
+ which also acknowledges contributions by Mike Burrows, David Wheeler,
+ Peter Fenwick, Alistair Moffat, Radford Neal, Ian H. Witten,
+ Robert Sedgewick, and Jon L. Bentley.
- This code is licensed under the LGPLv2:
- LGPL http://www.gnu.org/copyleft/lgpl.html
+ Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
*/
/*
I would ask that anyone benefiting from this work, especially those
using it in commercial products, consider making a donation to my local
non-profit hospice organization (www.hospiceacadiana.com) in the name of
- the woman I loved, Toni W. Hagan, who passed away Feb. 12, 2003.
+ the woman I loved, Toni W. Hagan, who passed away Feb. 12, 2003.
Manuel
*/
-#include <setjmp.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <limits.h>
-
#include "libbb.h"
+#include "unarchive.h"
/* Constants for Huffman coding */
-#define MAX_GROUPS 6
-#define GROUP_SIZE 50 /* 64 would have been more efficient */
-#define MAX_HUFCODE_BITS 20 /* Longest Huffman code allowed */
-#define MAX_SYMBOLS 258 /* 256 literals + RUNA + RUNB */
-#define SYMBOL_RUNA 0
-#define SYMBOL_RUNB 1
+#define MAX_GROUPS 6
+#define GROUP_SIZE 50 /* 64 would have been more efficient */
+#define MAX_HUFCODE_BITS 20 /* Longest Huffman code allowed */
+#define MAX_SYMBOLS 258 /* 256 literals + RUNA + RUNB */
+#define SYMBOL_RUNA 0
+#define SYMBOL_RUNB 1
/* Status return values */
-#define RETVAL_OK 0
-#define RETVAL_LAST_BLOCK (-1)
-#define RETVAL_NOT_BZIP_DATA (-2)
-#define RETVAL_UNEXPECTED_INPUT_EOF (-3)
-#define RETVAL_UNEXPECTED_OUTPUT_EOF (-4)
-#define RETVAL_DATA_ERROR (-5)
-#define RETVAL_OUT_OF_MEMORY (-6)
-#define RETVAL_OBSOLETE_INPUT (-7)
+#define RETVAL_OK 0
+#define RETVAL_LAST_BLOCK (-1)
+#define RETVAL_NOT_BZIP_DATA (-2)
+#define RETVAL_UNEXPECTED_INPUT_EOF (-3)
+#define RETVAL_UNEXPECTED_OUTPUT_EOF (-4)
+#define RETVAL_DATA_ERROR (-5)
+#define RETVAL_OUT_OF_MEMORY (-6)
+#define RETVAL_OBSOLETE_INPUT (-7)
/* Other housekeeping constants */
-#define IOBUF_SIZE 4096
+#define IOBUF_SIZE 4096
/* This is what we know about each Huffman coding group */
struct group_data {
/* The CRC values stored in the block header and calculated from the data */
- unsigned int crc32Table[256],headerCRC, totalCRC, writeCRC;
-
+ uint32_t headerCRC, totalCRC, writeCRC;
+ uint32_t *crc32Table;
/* Intermediate buffer and its size (in bytes) */
unsigned int *dbuf, dbufSize;
/* Reset longjmp I/O error handling */
i=setjmp(bd->jmpbuf);
- if(i) return i;
+ if (i) return i;
/* Read in header signature and CRC, then validate signature.
(last block signature means CRC is for whole file, return now) */
some code for this in busybox 1.0.0-pre3, but nobody ever noticed that
it didn't actually work. */
- if(get_bits(bd,1)) return RETVAL_OBSOLETE_INPUT;
- if((origPtr=get_bits(bd,24)) > dbufSize) return RETVAL_DATA_ERROR;
+ if (get_bits(bd,1)) return RETVAL_OBSOLETE_INPUT;
+ if ((origPtr=get_bits(bd,24)) > dbufSize) return RETVAL_DATA_ERROR;
/* mapping table: if some byte values are never used (encoding things
like ascii text), the compression code removes the gaps to have fewer
for (i=0;i<16;i++) {
if(t&(1<<(15-i))) {
k=get_bits(bd,16);
- for(j=0;j<16;j++)
+ for (j=0;j<16;j++)
if(k&(1<<(15-j))) symToByte[symTotal++]=(16*i)+j;
}
}
start of the list.) */
if(!(nSelectors=get_bits(bd, 15))) return RETVAL_DATA_ERROR;
- for(i=0; i<groupCount; i++) mtfSymbol[i] = i;
- for(i=0; i<nSelectors; i++) {
+ for (i=0; i<groupCount; i++) mtfSymbol[i] = i;
+ for (i=0; i<nSelectors; i++) {
/* Get next value */
- for(j=0;get_bits(bd,1);j++) if (j>=groupCount) return RETVAL_DATA_ERROR;
+ for (j=0;get_bits(bd,1);j++) if (j>=groupCount) return RETVAL_DATA_ERROR;
/* Decode MTF to get the next selector */
uc = mtfSymbol[j];
- for(;j;j--) mtfSymbol[j] = mtfSymbol[j-1];
+ for (;j;j--) mtfSymbol[j] = mtfSymbol[j-1];
mtfSymbol[0]=selectors[i]=uc;
}
t=get_bits(bd, 5)-1;
for (i = 0; i < symCount; i++) {
- for(;;) {
+ for (;;) {
if (((unsigned)t) > (MAX_HUFCODE_BITS-1))
return RETVAL_DATA_ERROR;
/* Find largest and smallest lengths in this group */
minLen=maxLen=length[0];
- for(i = 1; i < symCount; i++) {
+ for (i = 1; i < symCount; i++) {
if(length[i] > maxLen) maxLen = length[i];
else if(length[i] < minLen) minLen = length[i];
}
/* Calculate permute[]. Concurently, initialize temp[] and limit[]. */
pp=0;
- for(i=minLen;i<=maxLen;i++) {
+ for (i=minLen;i<=maxLen;i++) {
temp[i]=limit[i]=0;
- for(t=0;t<symCount;t++)
+ for (t=0;t<symCount;t++)
if(length[t]==i) hufGroup->permute[pp++] = t;
}
/* Initialize symbol occurrence counters and symbol Move To Front table */
- for(i=0;i<256;i++) {
+ for (i=0;i<256;i++) {
byteCount[i] = 0;
mtfSymbol[i]=(unsigned char)i;
}
/* Loop through compressed symbols. */
runPos=dbufCount=selector=0;
- for(;;) {
+ for (;;) {
/* fetch next Huffman coding group from list. */
/* Figure how how many bits are in next symbol and unget extras */
i=hufGroup->minLen;
- while(j>limit[i]) ++i;
+ while (j>limit[i]) ++i;
bd->inbufBitCount += (hufGroup->maxLen - i);
/* Huffman decode value to get nextSym (with bounds checking) */
context). Thus space is saved. */
t += (runPos << nextSym); /* +runPos if RUNA; +2*runPos if RUNB */
- runPos <<= 1;
+ if(runPos < dbufSize) runPos <<= 1;
goto end_of_huffman_loop;
}
uc = symToByte[mtfSymbol[0]];
byteCount[uc] += t;
- while(t--) dbuf[dbufCount++]=uc;
+ while (t--) dbuf[dbufCount++]=uc;
}
/* Is this the terminating symbol? */
/* Turn byteCount into cumulative occurrence counts of 0 to n-1. */
j=0;
- for(i=0;i<256;i++) {
+ for (i=0;i<256;i++) {
k=j+byteCount[i];
byteCount[i] = j;
j=k;
/* Loop outputting bytes */
- for(;;) {
+ for (;;) {
/* If the output buffer is full, snapshot state and return */
bd->writeCount=previous;
return (previous!=RETVAL_LAST_BLOCK) ? previous : gotcount;
}
- bd->writeCRC=0xffffffffUL;
+ bd->writeCRC=~0;
pos=bd->writePos;
current=bd->writeCurrent;
goto decode_next_byte;
int len)
{
bunzip_data *bd;
- unsigned int i,j,c;
+ unsigned int i;
const unsigned int BZh0=(((unsigned int)'B')<<24)+(((unsigned int)'Z')<<16)
+(((unsigned int)'h')<<8)+(unsigned int)'0';
/* Allocate bunzip_data. Most fields initialize to zero. */
- bd=*bdp=xmalloc(i);
- memset(bd,0,sizeof(bunzip_data));
+ bd=*bdp=xzalloc(i);
/* Setup input buffer */
/* Init the CRC32 table (big endian) */
- for(i=0;i<256;i++) {
- c=i<<24;
- for(j=8;j;j--)
- c=c&0x80000000 ? (c<<1)^0x04c11db7 : (c<<1);
- bd->crc32Table[i]=c;
- }
+ bd->crc32Table = crc32_filltable(1);
/* Setup for I/O error handling via longjmp */
/* Example usage: decompress src_fd to dst_fd. (Stops at end of bzip data,
not end of file.) */
-extern int uncompressStream(int src_fd, int dst_fd)
+USE_DESKTOP(long long) int
+uncompressStream(int src_fd, int dst_fd)
{
+ USE_DESKTOP(long long total_written = 0;)
char *outbuf;
bunzip_data *bd;
int i;
outbuf=xmalloc(IOBUF_SIZE);
- if(!(i=start_bunzip(&bd,src_fd,0,0))) {
- for(;;) {
+ i=start_bunzip(&bd,src_fd,0,0);
+ if(!i) {
+ for (;;) {
if((i=read_bunzip(bd,outbuf,IOBUF_SIZE)) <= 0) break;
if(i!=write(dst_fd,outbuf,i)) {
i=RETVAL_UNEXPECTED_OUTPUT_EOF;
break;
}
+ USE_DESKTOP(total_written += i;)
}
}
if(i==RETVAL_LAST_BLOCK) {
if (bd->headerCRC!=bd->totalCRC) {
- bb_error_msg("Data integrity error when decompressing.");
+ bb_error_msg("data integrity error when decompressing");
} else {
i=RETVAL_OK;
}
} else if (i==RETVAL_UNEXPECTED_OUTPUT_EOF) {
- bb_error_msg("Compressed file ends unexpectedly");
+ bb_error_msg("compressed file ends unexpectedly");
} else {
- bb_error_msg("Decompression failed");
+ bb_error_msg("decompression failed");
}
- if(bd->dbuf) free(bd->dbuf);
+ free(bd->dbuf);
free(bd);
free(outbuf);
- return i;
+ return i ? i : USE_DESKTOP(total_written) + 0;
}
#ifdef TESTING
static char * const bunzip_errors[]={NULL,"Bad file checksum","Not bzip data",
"Unexpected input EOF","Unexpected output EOF","Data error",
- "Out of memory","Obsolete (pre 0.9.5) bzip format not supported."};
+ "Out of memory","Obsolete (pre 0.9.5) bzip format not supported."};
/* Dumb little test thing, decompress stdin to stdout */
int main(int argc, char *argv[])
int i=uncompressStream(0,1);
char c;
- if(i) fprintf(stderr,"%s\n", bunzip_errors[-i]);
- else if(read(0,&c,1)) fprintf(stderr,"Trailing garbage ignored\n");
+ if(i<0) fprintf(stderr,"%s\n", bunzip_errors[-i]);
+ else if(read(0,&c,1)) fprintf(stderr,"Trailing garbage ignored\n");
return -i;
}
#endif