| /* vi: set sw=4 ts=4: */ |
| /* micro-bunzip, a small, simple bzip2 decompression implementation. |
| |
| Copyright 2003, 2006 by Rob Landley (rob@landley.net). |
| |
| Based on a close reading (but not the actual code) of the original 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. |
| */ |
| |
| #include "toys.h" |
| |
| #define THREADS 1 |
| |
| // 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 |
| |
| // Other housekeeping constants |
| #define IOBUF_SIZE 4096 |
| |
| // Status return values |
| #define RETVAL_LAST_BLOCK (-100) |
| #define RETVAL_NOT_BZIP_DATA (-1) |
| #define RETVAL_DATA_ERROR (-2) |
| #define RETVAL_OBSOLETE_INPUT (-3) |
| |
| char *bunzip_errors[]={ |
| NULL, |
| "Not bzip data", |
| "Data error", |
| "Obsolete (pre 0.9.5) bzip format not supported." |
| }; |
| |
| // This is what we know about each huffman coding group |
| struct group_data { |
| int limit[MAX_HUFCODE_BITS+1], base[MAX_HUFCODE_BITS], permute[MAX_SYMBOLS]; |
| char minLen, maxLen; |
| }; |
| |
| // Data for burrows wheeler transform |
| |
| struct bwdata { |
| unsigned int origPtr; |
| int byteCount[256]; |
| // State saved when interrupting output |
| int writePos, writeRun, writeCount, writeCurrent; |
| unsigned int dataCRC, headerCRC; |
| unsigned int *dbuf; |
| }; |
| |
| // Structure holding all the housekeeping data, including IO buffers and |
| // memory that persists between calls to bunzip |
| struct bunzip_data { |
| |
| // Input stream, input buffer, input bit buffer |
| int in_fd, inbufCount, inbufPos; |
| char *inbuf; |
| unsigned int inbufBitCount, inbufBits; |
| |
| // Output buffer |
| char outbuf[IOBUF_SIZE]; |
| int outbufPos; |
| |
| unsigned int totalCRC; |
| |
| // First pass decompression data (Huffman and MTF decoding) |
| char selectors[32768]; // nSelectors=15 bits |
| struct group_data groups[MAX_GROUPS]; // huffman coding tables |
| int symTotal, groupCount, nSelectors; |
| unsigned char symToByte[256], mtfSymbol[256]; |
| |
| // The CRC values stored in the block header and calculated from the data |
| unsigned int crc32Table[256]; |
| |
| // Second pass decompression data (burrows-wheeler transform) |
| unsigned int dbufSize; |
| struct bwdata bwdata[THREADS]; |
| }; |
| |
| // Return the next nnn bits of input. All reads from the compressed input |
| // are done through this function. All reads are big endian. |
| static unsigned int get_bits(struct bunzip_data *bd, char bits_wanted) |
| { |
| unsigned int bits = 0; |
| |
| // If we need to get more data from the byte buffer, do so. (Loop getting |
| // one byte at a time to enforce endianness and avoid unaligned access.) |
| while (bd->inbufBitCount < bits_wanted) { |
| |
| // If we need to read more data from file into byte buffer, do so |
| if (bd->inbufPos == bd->inbufCount) { |
| if (0 >= (bd->inbufCount = read(bd->in_fd, bd->inbuf, IOBUF_SIZE))) |
| error_exit("Unexpected input EOF"); |
| bd->inbufPos = 0; |
| } |
| |
| // Avoid 32-bit overflow (dump bit buffer to top of output) |
| if (bd->inbufBitCount>=24) { |
| bits = bd->inbufBits&((1<<bd->inbufBitCount)-1); |
| bits_wanted -= bd->inbufBitCount; |
| bits <<= bits_wanted; |
| bd->inbufBitCount = 0; |
| } |
| |
| // Grab next 8 bits of input from buffer. |
| bd->inbufBits = (bd->inbufBits<<8) | bd->inbuf[bd->inbufPos++]; |
| bd->inbufBitCount += 8; |
| } |
| |
| // Calculate result |
| bd->inbufBitCount -= bits_wanted; |
| bits |= (bd->inbufBits>>bd->inbufBitCount) & ((1<<bits_wanted)-1); |
| |
| return bits; |
| } |
| |
| /* Read block header at start of a new compressed data block. Consists of: |
| * |
| * 48 bits : Block signature, either pi (data block) or e (EOF block). |
| * 32 bits : bw->headerCRC |
| * 1 bit : obsolete feature flag. |
| * 24 bits : origPtr (Burrows-wheeler unwind index, only 20 bits ever used) |
| * 16 bits : Mapping table index. |
| *[16 bits]: symToByte[symTotal] (Mapping table. For each bit set in mapping |
| * table index above, read another 16 bits of mapping table data. |
| * If correspondig bit is unset, all bits in that mapping table |
| * section are 0.) |
| * 3 bits : groupCount (how many huffman tables used to encode, anywhere |
| * from 2 to MAX_GROUPS) |
| * variable: hufGroup[groupCount] (MTF encoded huffman table data.) |
| */ |
| |
| static int read_block_header(struct bunzip_data *bd, struct bwdata *bw) |
| { |
| struct group_data *hufGroup; |
| int hh, ii, jj, kk, symCount, *base, *limit; |
| unsigned char uc; |
| |
| // Read in header signature and CRC (which is stored big endian) |
| ii = get_bits(bd, 24); |
| jj = get_bits(bd, 24); |
| bw->headerCRC = get_bits(bd,32); |
| |
| // Is this the EOF block with CRC for whole file? (Constant is "e") |
| if (ii==0x177245 && jj==0x385090) return RETVAL_LAST_BLOCK; |
| |
| // Is this a valid data block? (Constant is "pi".) |
| if (ii!=0x314159 || jj!=0x265359) return RETVAL_NOT_BZIP_DATA; |
| |
| // We can add support for blockRandomised if anybody complains. |
| if (get_bits(bd,1)) return RETVAL_OBSOLETE_INPUT; |
| if ((bw->origPtr = get_bits(bd,24)) > bd->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 |
| // symbols to deal with, and writes a sparse bitfield indicating which |
| // values were present. We make a translation table to convert the symbols |
| // back to the corresponding bytes. |
| hh = get_bits(bd, 16); |
| bd->symTotal = 0; |
| for (ii=0; ii<16; ii++) { |
| if (hh & (1 << (15 - ii))) { |
| kk = get_bits(bd, 16); |
| for (jj=0; jj<16; jj++) |
| if (kk & (1 << (15 - jj))) |
| bd->symToByte[bd->symTotal++] = (16 * ii) + jj; |
| } |
| } |
| |
| // How many different huffman coding groups does this block use? |
| bd->groupCount = get_bits(bd,3); |
| if (bd->groupCount<2 || bd->groupCount>MAX_GROUPS) return RETVAL_DATA_ERROR; |
| |
| // nSelectors: Every GROUP_SIZE many symbols we switch huffman coding |
| // tables. Each group has a selector, which is an index into the huffman |
| // coding table arrays. |
| // |
| // Read in the group selector array, which is stored as MTF encoded |
| // bit runs. (MTF = Move To Front. Every time a symbol occurs it's moved |
| // to the front of the table, so it has a shorter encoding next time.) |
| if (!(bd->nSelectors = get_bits(bd, 15))) return RETVAL_DATA_ERROR; |
| for (ii=0; ii<bd->groupCount; ii++) bd->mtfSymbol[ii] = ii; |
| for (ii=0; ii<bd->nSelectors; ii++) { |
| |
| // Get next value |
| for(jj=0;get_bits(bd,1);jj++) |
| if (jj>=bd->groupCount) return RETVAL_DATA_ERROR; |
| |
| // Decode MTF to get the next selector, and move it to the front. |
| uc = bd->mtfSymbol[jj]; |
| memmove(bd->mtfSymbol+1, bd->mtfSymbol, jj); |
| bd->mtfSymbol[0] = bd->selectors[ii] = uc; |
| } |
| |
| // Read the huffman coding tables for each group, which code for symTotal |
| // literal symbols, plus two run symbols (RUNA, RUNB) |
| symCount = bd->symTotal+2; |
| for (jj=0; jj<bd->groupCount; jj++) { |
| unsigned char length[MAX_SYMBOLS]; |
| unsigned temp[MAX_HUFCODE_BITS+1]; |
| int minLen, maxLen, pp; |
| |
| // Read lengths |
| hh = get_bits(bd, 5); |
| for (ii = 0; ii < symCount; ii++) { |
| for(;;) { |
| // !hh || hh > MAX_HUFCODE_BITS in one test. |
| if (MAX_HUFCODE_BITS-1 < (unsigned)hh-1) |
| return RETVAL_DATA_ERROR; |
| // Grab 2 bits instead of 1 (slightly smaller/faster). Stop if |
| // first bit is 0, otherwise second bit says whether to |
| // increment or decrement. |
| kk = get_bits(bd, 2); |
| if (kk & 2) hh += 1 - ((kk&1)<<1); |
| else { |
| bd->inbufBitCount++; |
| break; |
| } |
| } |
| length[ii] = hh; |
| } |
| |
| // Find largest and smallest lengths in this group |
| minLen = maxLen = length[0]; |
| for (ii = 1; ii < symCount; ii++) { |
| if(length[ii] > maxLen) maxLen = length[ii]; |
| else if(length[ii] < minLen) minLen = length[ii]; |
| } |
| |
| /* Calculate permute[], base[], and limit[] tables from length[]. |
| * |
| * permute[] is the lookup table for converting huffman coded symbols |
| * into decoded symbols. It contains symbol values sorted by length. |
| * |
| * base[] is the amount to subtract from the value of a huffman symbol |
| * of a given length when using permute[]. |
| * |
| * limit[] indicates the largest numerical value a symbol with a given |
| * number of bits can have. It lets us know when to stop reading. |
| * |
| * To use these, keep reading bits until value <= limit[bitcount] or |
| * you've read over 20 bits (error). Then the decoded symbol |
| * equals permute[hufcode_value - base[hufcode_bitcount]]. |
| */ |
| hufGroup = bd->groups+jj; |
| hufGroup->minLen = minLen; |
| hufGroup->maxLen = maxLen; |
| |
| // Note that minLen can't be smaller than 1, so we adjust the base |
| // and limit array pointers so we're not always wasting the first |
| // entry. We do this again when using them (during symbol decoding). |
| base = hufGroup->base-1; |
| limit = hufGroup->limit-1; |
| |
| // zero temp[] and limit[], and calculate permute[] |
| pp = 0; |
| for (ii = minLen; ii <= maxLen; ii++) { |
| temp[ii] = limit[ii] = 0; |
| for (hh = 0; hh < symCount; hh++) |
| if (length[hh] == ii) |
| hufGroup->permute[pp++] = hh; |
| } |
| |
| // Count symbols coded for at each bit length |
| for (ii = 0; ii < symCount; ii++) temp[length[ii]]++; |
| |
| /* Calculate limit[] (the largest symbol-coding value at each bit |
| * length, which is (previous limit<<1)+symbols at this level), and |
| * base[] (number of symbols to ignore at each bit length, which is |
| * limit minus the cumulative count of symbols coded for already). */ |
| pp = hh = 0; |
| for (ii = minLen; ii < maxLen; ii++) { |
| pp += temp[ii]; |
| limit[ii] = pp-1; |
| pp <<= 1; |
| base[ii+1] = pp-(hh+=temp[ii]); |
| } |
| limit[maxLen] = pp+temp[maxLen]-1; |
| limit[maxLen+1] = INT_MAX; |
| base[minLen] = 0; |
| } |
| |
| return 0; |
| } |
| |
| /* First pass, read block's symbols into dbuf[dbufCount]. |
| * |
| * This undoes three types of compression: huffman coding, run length encoding, |
| * and move to front encoding. We have to undo all those to know when we've |
| * read enough input. |
| */ |
| |
| static int read_huffman_data(struct bunzip_data *bd, struct bwdata *bw) |
| { |
| struct group_data *hufGroup; |
| int hh, ii, jj, kk, runPos, dbufCount, symCount, selector, nextSym, |
| *byteCount, *base, *limit; |
| unsigned int *dbuf = bw->dbuf; |
| unsigned char uc; |
| |
| // We've finished reading and digesting the block header. Now read this |
| // block's huffman coded symbols from the file and undo the huffman coding |
| // and run length encoding, saving the result into dbuf[dbufCount++] = uc |
| |
| // Initialize symbol occurrence counters and symbol mtf table |
| byteCount = bw->byteCount; |
| for(ii=0; ii<256; ii++) { |
| byteCount[ii] = 0; |
| bd->mtfSymbol[ii] = ii; |
| } |
| |
| // Loop through compressed symbols. This is the first "tight inner loop" |
| // that needs to be micro-optimized for speed. (This one fills out dbuf[] |
| // linearly, staying in cache more, so isn't as limited by DRAM access.) |
| runPos = dbufCount = symCount = selector = 0; |
| // Some unnecessary initializations to shut gcc up. |
| base = limit = 0; |
| hufGroup = 0; |
| hh = 0; |
| |
| for (;;) { |
| |
| // Have we reached the end of this huffman group? |
| if (!(symCount--)) { |
| // Determine which huffman coding group to use. |
| symCount = GROUP_SIZE-1; |
| if (selector >= bd->nSelectors) return RETVAL_DATA_ERROR; |
| hufGroup = bd->groups + bd->selectors[selector++]; |
| base = hufGroup->base-1; |
| limit = hufGroup->limit-1; |
| } |
| |
| // Read next huffman-coded symbol (into jj). |
| ii = hufGroup->minLen; |
| jj = get_bits(bd, ii); |
| while (jj > limit[ii]) { |
| // if (ii > hufGroup->maxLen) return RETVAL_DATA_ERROR; |
| ii++; |
| |
| // Unroll get_bits() to avoid a function call when the data's in |
| // the buffer already. |
| kk = bd->inbufBitCount |
| ? (bd->inbufBits >> --(bd->inbufBitCount)) & 1 |
| : get_bits(bd, 1); |
| jj = (jj << 1) | kk; |
| } |
| // Huffman decode jj into nextSym (with bounds checking) |
| jj-=base[ii]; |
| |
| if (ii > hufGroup->maxLen || (unsigned)jj >= MAX_SYMBOLS) |
| return RETVAL_DATA_ERROR; |
| nextSym = hufGroup->permute[jj]; |
| |
| // If this is a repeated run, loop collecting data |
| if ((unsigned)nextSym <= SYMBOL_RUNB) { |
| |
| // If this is the start of a new run, zero out counter |
| if(!runPos) { |
| runPos = 1; |
| hh = 0; |
| } |
| |
| /* Neat trick that saves 1 symbol: instead of or-ing 0 or 1 at |
| each bit position, add 1 or 2 instead. For example, |
| 1011 is 1<<0 + 1<<1 + 2<<2. 1010 is 2<<0 + 2<<1 + 1<<2. |
| You can make any bit pattern that way using 1 less symbol than |
| the basic or 0/1 method (except all bits 0, which would use no |
| symbols, but a run of length 0 doesn't mean anything in this |
| context). Thus space is saved. */ |
| hh += (runPos << nextSym); // +runPos if RUNA; +2*runPos if RUNB |
| runPos <<= 1; |
| continue; |
| } |
| |
| /* When we hit the first non-run symbol after a run, we now know |
| how many times to repeat the last literal, so append that many |
| copies to our buffer of decoded symbols (dbuf) now. (The last |
| literal used is the one at the head of the mtfSymbol array.) */ |
| if (runPos) { |
| runPos = 0; |
| if (dbufCount+hh >= bd->dbufSize) return RETVAL_DATA_ERROR; |
| |
| uc = bd->symToByte[bd->mtfSymbol[0]]; |
| byteCount[uc] += hh; |
| while (hh--) dbuf[dbufCount++] = uc; |
| } |
| |
| // Is this the terminating symbol? |
| if (nextSym>bd->symTotal) break; |
| |
| /* At this point, the symbol we just decoded indicates a new literal |
| character. Subtract one to get the position in the MTF array |
| at which this literal is currently to be found. (Note that the |
| result can't be -1 or 0, because 0 and 1 are RUNA and RUNB. |
| Another instance of the first symbol in the mtf array, position 0, |
| would have been handled as part of a run.) */ |
| if (dbufCount>=bd->dbufSize) return RETVAL_DATA_ERROR; |
| ii = nextSym - 1; |
| uc = bd->mtfSymbol[ii]; |
| // On my laptop, unrolling this memmove() into a loop shaves 3.5% off |
| // the total running time. |
| while(ii--) bd->mtfSymbol[ii+1] = bd->mtfSymbol[ii]; |
| bd->mtfSymbol[0] = uc; |
| uc = bd->symToByte[uc]; |
| |
| // We have our literal byte. Save it into dbuf. |
| byteCount[uc]++; |
| dbuf[dbufCount++] = (unsigned int)uc; |
| } |
| |
| // Now we know what dbufCount is, do a better sanity check on origPtr. |
| if (bw->origPtr >= (bw->writeCount = dbufCount)) return RETVAL_DATA_ERROR; |
| |
| return 0; |
| } |
| |
| // Flush output buffer to disk |
| void flush_bunzip_outbuf(struct bunzip_data *bd, int out_fd) |
| { |
| if (bd->outbufPos) { |
| if (write(out_fd, bd->outbuf, bd->outbufPos) != bd->outbufPos) |
| error_exit("Unexpected output EOF"); |
| bd->outbufPos = 0; |
| } |
| } |
| |
| void burrows_wheeler_prep(struct bunzip_data *bd, struct bwdata *bw) |
| { |
| int ii, jj; |
| unsigned int *dbuf = bw->dbuf; |
| int *byteCount = bw->byteCount; |
| |
| // Technically this part is preparation for the burrows-wheeler |
| // transform, but it's quick and convenient to do here. |
| |
| // Turn byteCount into cumulative occurrence counts of 0 to n-1. |
| jj = 0; |
| for (ii=0; ii<256; ii++) { |
| int kk = jj + byteCount[ii]; |
| byteCount[ii] = jj; |
| jj = kk; |
| } |
| |
| // Use occurrence counts to quickly figure out what order dbuf would be in |
| // if we sorted it. |
| for (ii=0; ii < bw->writeCount; ii++) { |
| unsigned char uc = dbuf[ii]; |
| dbuf[byteCount[uc]] |= (ii << 8); |
| byteCount[uc]++; |
| } |
| |
| // blockRandomised support would go here. |
| |
| // Using ii as position, jj as previous character, hh as current character, |
| // and uc as run count. |
| bw->dataCRC = 0xffffffffL; |
| |
| /* Decode first byte by hand to initialize "previous" byte. Note that it |
| doesn't get output, and if the first three characters are identical |
| it doesn't qualify as a run (hence uc=255, which will either wrap |
| to 1 or get reset). */ |
| if (bw->writeCount) { |
| bw->writePos = dbuf[bw->origPtr]; |
| bw->writeCurrent = (unsigned char)bw->writePos; |
| bw->writePos >>= 8; |
| bw->writeRun = -1; |
| } |
| } |
| |
| // Decompress a block of text to intermediate buffer |
| int read_bunzip_data(struct bunzip_data *bd) |
| { |
| int rc = read_block_header(bd, bd->bwdata); |
| if (!rc) rc=read_huffman_data(bd, bd->bwdata); |
| |
| // First thing that can be done by a background thread. |
| burrows_wheeler_prep(bd, bd->bwdata); |
| |
| return rc; |
| } |
| |
| // Undo burrows-wheeler transform on intermediate buffer to produce output. |
| // If !len, write up to len bytes of data to buf. Otherwise write to out_fd. |
| // Returns len ? bytes written : 0. Notice all errors are negative #'s. |
| // |
| // Burrows-wheeler transform is described at: |
| // http://dogma.net/markn/articles/bwt/bwt.htm |
| // http://marknelson.us/1996/09/01/bwt/ |
| |
| int write_bunzip_data(struct bunzip_data *bd, struct bwdata *bw, int out_fd, char *outbuf, int len) |
| { |
| unsigned int *dbuf = bw->dbuf; |
| int count, pos, current, run, copies, outbyte, previous, gotcount = 0; |
| |
| for (;;) { |
| |
| // If last read was short due to end of file, return last block now |
| if (bw->writeCount < 0) return bw->writeCount; |
| |
| // If we need to refill dbuf, do it. |
| if (!bw->writeCount) { |
| int i = read_bunzip_data(bd); |
| if (i) { |
| if (i == RETVAL_LAST_BLOCK) { |
| bw->writeCount = i; |
| return gotcount; |
| } else return i; |
| } |
| } |
| |
| // loop generating output |
| count = bw->writeCount; |
| pos = bw->writePos; |
| current = bw->writeCurrent; |
| run = bw->writeRun; |
| while (count) { |
| |
| // If somebody (like tar) wants a certain number of bytes of |
| // data from memory instead of written to a file, humor them. |
| if (len && bd->outbufPos>=len) goto dataus_interruptus; |
| count--; |
| |
| // Follow sequence vector to undo Burrows-Wheeler transform. |
| previous = current; |
| pos = dbuf[pos]; |
| current = pos&0xff; |
| pos >>= 8; |
| |
| // Whenever we see 3 consecutive copies of the same byte, |
| // the 4th is a repeat count |
| if (run++ == 3) { |
| copies = current; |
| outbyte = previous; |
| current = -1; |
| } else { |
| copies = 1; |
| outbyte = current; |
| } |
| |
| // Output bytes to buffer, flushing to file if necessary |
| while (copies--) { |
| if (bd->outbufPos == IOBUF_SIZE) flush_bunzip_outbuf(bd,out_fd); |
| bd->outbuf[bd->outbufPos++] = outbyte; |
| bw->dataCRC = (bw->dataCRC << 8) |
| ^ bd->crc32Table[(bw->dataCRC >> 24) ^ outbyte]; |
| } |
| if (current!=previous) run=0; |
| } |
| |
| // decompression of this block completed successfully |
| bw->dataCRC = ~(bw->dataCRC); |
| bd->totalCRC = ((bd->totalCRC << 1) | (bd->totalCRC >> 31)) |
| ^ bw->dataCRC; |
| |
| // if this block had a crc error, force file level crc error. |
| if (bw->dataCRC != bw->headerCRC) { |
| bd->totalCRC = bw->headerCRC+1; |
| |
| return RETVAL_LAST_BLOCK; |
| } |
| dataus_interruptus: |
| bw->writeCount = count; |
| if (len) { |
| gotcount += bd->outbufPos; |
| memcpy(outbuf, bd->outbuf, len); |
| |
| // If we got enough data, checkpoint loop state and return |
| if ((len-=bd->outbufPos)<1) { |
| bd->outbufPos -= len; |
| if (bd->outbufPos) |
| memmove(bd->outbuf, bd->outbuf+len, bd->outbufPos); |
| bw->writePos = pos; |
| bw->writeCurrent = current; |
| bw->writeRun = run; |
| |
| return gotcount; |
| } |
| } |
| } |
| } |
| |
| // Allocate the structure, read file header. If !len, src_fd contains |
| // filehandle to read from. Else inbuf contains data. |
| int start_bunzip(struct bunzip_data **bdp, int src_fd, char *inbuf, int len) |
| { |
| struct bunzip_data *bd; |
| unsigned int i, j, c; |
| |
| // Figure out how much data to allocate. |
| i = sizeof(struct bunzip_data); |
| if (!len) i += IOBUF_SIZE; |
| |
| // Allocate bunzip_data. Most fields initialize to zero. |
| bd = *bdp = xzalloc(i); |
| if (len) { |
| bd->inbuf = inbuf; |
| bd->inbufCount = len; |
| bd->in_fd = -1; |
| } else { |
| bd->inbuf = (char *)(bd+1); |
| bd->in_fd = src_fd; |
| } |
| |
| // 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; |
| } |
| |
| // Ensure that file starts with "BZh". |
| for (i=0;i<3;i++) |
| if (get_bits(bd,8)!="BZh"[i]) return RETVAL_NOT_BZIP_DATA; |
| |
| // Next byte ascii '1'-'9', indicates block size in units of 100k of |
| // uncompressed data. Allocate intermediate buffer for block. |
| i = get_bits(bd, 8); |
| if (i<'1' || i>'9') return RETVAL_NOT_BZIP_DATA; |
| bd->dbufSize = 100000*(i-'0')*THREADS; |
| for (i=0; i<THREADS; i++) |
| bd->bwdata[i].dbuf = xmalloc(bd->dbufSize * sizeof(int)); |
| |
| return 0; |
| } |
| |
| // Example usage: decompress src_fd to dst_fd. (Stops at end of bzip data, |
| // not end of file.) |
| void bunzipStream(int src_fd, int dst_fd) |
| { |
| struct bunzip_data *bd; |
| int i, j; |
| |
| if (!(i = start_bunzip(&bd,src_fd,0,0))) { |
| i = write_bunzip_data(bd,bd->bwdata,dst_fd,0,0); |
| if (i==RETVAL_LAST_BLOCK && bd->bwdata[0].headerCRC==bd->totalCRC) |
| i = 0; |
| } |
| flush_bunzip_outbuf(bd,dst_fd); |
| for (j=0; j<THREADS; j++) free(bd->bwdata[j].dbuf); |
| free(bd); |
| if (i) error_exit(bunzip_errors[-i]); |
| } |