12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049 |
- /*
- * Copyright (C) 2014 Michael Brown <mbrown@fensystems.co.uk>.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of the
- * License, or any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
- * 02110-1301, USA.
- *
- * You can also choose to distribute this program under the terms of
- * the Unmodified Binary Distribution Licence (as given in the file
- * COPYING.UBDL), provided that you have satisfied its requirements.
- */
-
- FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
-
- #include <string.h>
- #include <strings.h>
- #include <errno.h>
- #include <assert.h>
- #include <ctype.h>
- #include <ipxe/uaccess.h>
- #include <ipxe/deflate.h>
-
- /** @file
- *
- * DEFLATE decompression algorithm
- *
- * This file implements the decompression half of the DEFLATE
- * algorithm specified in RFC 1951.
- *
- * Portions of this code are derived from wimboot's xca.c.
- *
- */
-
- /**
- * Byte reversal table
- *
- * For some insane reason, the DEFLATE format stores some values in
- * bit-reversed order.
- */
- static uint8_t deflate_reverse[256];
-
- /** Literal/length base values
- *
- * We include entries only for literal/length codes 257-284. Code 285
- * does not fit the pattern (it represents a length of 258; following
- * the pattern from the earlier codes would give a length of 259), and
- * has no extra bits. Codes 286-287 are invalid, but can occur. We
- * treat any code greater than 284 as meaning "length 285, no extra
- * bits".
- */
- static uint8_t deflate_litlen_base[28];
-
- /** Distance base values
- *
- * We include entries for all possible codes 0-31, avoiding the need
- * to check for undefined codes 30 and 31 before performing the
- * lookup. Codes 30 and 31 are never initialised, and will therefore
- * be treated as meaning "14 extra bits, base distance 0".
- */
- static uint16_t deflate_distance_base[32];
-
- /** Code length map */
- static uint8_t deflate_codelen_map[19] = {
- 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15
- };
-
- /** Static Huffman alphabet length patterns */
- static struct deflate_static_length_pattern deflate_static_length_patterns[] = {
- /* Literal/length code lengths */
- { 0x88, ( ( ( 143 - 0 ) + 1 ) / 2 ) },
- { 0x99, ( ( ( 255 - 144 ) + 1 ) / 2 ) },
- { 0x77, ( ( ( 279 - 256 ) + 1 ) / 2 ) },
- { 0x88, ( ( ( 287 - 280 ) + 1 ) / 2 ) },
- /* Distance code lengths */
- { 0x55, ( ( ( 31 - 0 ) + 1 ) / 2 ) },
- /* End marker */
- { 0, 0 }
- };
-
- /**
- * Transcribe binary value (for debugging)
- *
- * @v value Value
- * @v bits Length of value (in bits)
- * @ret string Transcribed value
- */
- static const char * deflate_bin ( unsigned long value, unsigned int bits ) {
- static char buf[ ( 8 * sizeof ( value ) ) + 1 /* NUL */ ];
- char *out = buf;
-
- /* Sanity check */
- assert ( bits < sizeof ( buf ) );
-
- /* Transcribe value */
- while ( bits-- )
- *(out++) = ( ( value & ( 1 << bits ) ) ? '1' : '0' );
- *out = '\0';
-
- return buf;
- }
-
- /**
- * Set Huffman symbol length
- *
- * @v deflate Decompressor
- * @v index Index within lengths
- * @v bits Symbol length (in bits)
- */
- static void deflate_set_length ( struct deflate *deflate, unsigned int index,
- unsigned int bits ) {
-
- deflate->lengths[ index / 2 ] |= ( bits << ( 4 * ( index % 2 ) ) );
- }
-
- /**
- * Get Huffman symbol length
- *
- * @v deflate Decompressor
- * @v index Index within lengths
- * @ret bits Symbol length (in bits)
- */
- static unsigned int deflate_length ( struct deflate *deflate,
- unsigned int index ) {
-
- return ( ( deflate->lengths[ index / 2 ] >> ( 4 * ( index % 2 ) ) )
- & 0x0f );
- }
-
- /**
- * Determine Huffman alphabet name (for debugging)
- *
- * @v deflate Decompressor
- * @v alphabet Huffman alphabet
- * @ret name Alphabet name
- */
- static const char * deflate_alphabet_name ( struct deflate *deflate,
- struct deflate_alphabet *alphabet ){
-
- if ( alphabet == &deflate->litlen ) {
- return "litlen";
- } else if ( alphabet == &deflate->distance_codelen ) {
- return "distance/codelen";
- } else {
- return "<UNKNOWN>";
- }
- }
-
- /**
- * Dump Huffman alphabet (for debugging)
- *
- * @v deflate Decompressor
- * @v alphabet Huffman alphabet
- */
- static void deflate_dump_alphabet ( struct deflate *deflate,
- struct deflate_alphabet *alphabet ) {
- struct deflate_huf_symbols *huf_sym;
- unsigned int bits;
- unsigned int huf;
- unsigned int i;
-
- /* Do nothing unless debugging is enabled */
- if ( ! DBG_EXTRA )
- return;
-
- /* Dump symbol table for each utilised length */
- for ( bits = 1 ; bits <= ( sizeof ( alphabet->huf ) /
- sizeof ( alphabet->huf[0] ) ) ; bits++ ) {
- huf_sym = &alphabet->huf[ bits - 1 ];
- if ( huf_sym->freq == 0 )
- continue;
- huf = ( huf_sym->start >> huf_sym->shift );
- DBGC2 ( alphabet, "DEFLATE %p \"%s\" length %d start \"%s\" "
- "freq %d:", deflate,
- deflate_alphabet_name ( deflate, alphabet ), bits,
- deflate_bin ( huf, huf_sym->bits ), huf_sym->freq );
- for ( i = 0 ; i < huf_sym->freq ; i++ ) {
- DBGC2 ( alphabet, " %03x",
- huf_sym->raw[ huf + i ] );
- }
- DBGC2 ( alphabet, "\n" );
- }
-
- /* Dump quick lookup table */
- DBGC2 ( alphabet, "DEFLATE %p \"%s\" quick lookup:", deflate,
- deflate_alphabet_name ( deflate, alphabet ) );
- for ( i = 0 ; i < ( sizeof ( alphabet->lookup ) /
- sizeof ( alphabet->lookup[0] ) ) ; i++ ) {
- DBGC2 ( alphabet, " %d", ( alphabet->lookup[i] + 1 ) );
- }
- DBGC2 ( alphabet, "\n" );
- }
-
- /**
- * Construct Huffman alphabet
- *
- * @v deflate Decompressor
- * @v alphabet Huffman alphabet
- * @v count Number of symbols
- * @v offset Starting offset within length table
- * @ret rc Return status code
- */
- static int deflate_alphabet ( struct deflate *deflate,
- struct deflate_alphabet *alphabet,
- unsigned int count, unsigned int offset ) {
- struct deflate_huf_symbols *huf_sym;
- unsigned int huf;
- unsigned int cum_freq;
- unsigned int bits;
- unsigned int raw;
- unsigned int adjustment;
- unsigned int prefix;
- int complete;
-
- /* Clear symbol table */
- memset ( alphabet->huf, 0, sizeof ( alphabet->huf ) );
-
- /* Count number of symbols with each Huffman-coded length */
- for ( raw = 0 ; raw < count ; raw++ ) {
- bits = deflate_length ( deflate, ( raw + offset ) );
- if ( bits )
- alphabet->huf[ bits - 1 ].freq++;
- }
-
- /* Populate Huffman-coded symbol table */
- huf = 0;
- cum_freq = 0;
- for ( bits = 1 ; bits <= ( sizeof ( alphabet->huf ) /
- sizeof ( alphabet->huf[0] ) ) ; bits++ ) {
- huf_sym = &alphabet->huf[ bits - 1 ];
- huf_sym->bits = bits;
- huf_sym->shift = ( 16 - bits );
- huf_sym->start = ( huf << huf_sym->shift );
- huf_sym->raw = &alphabet->raw[cum_freq];
- huf += huf_sym->freq;
- if ( huf > ( 1U << bits ) ) {
- DBGC ( alphabet, "DEFLATE %p \"%s\" has too many "
- "symbols with lengths <=%d\n", deflate,
- deflate_alphabet_name ( deflate, alphabet ),
- bits );
- return -EINVAL;
- }
- huf <<= 1;
- cum_freq += huf_sym->freq;
- }
- complete = ( huf == ( 1U << bits ) );
-
- /* Populate raw symbol table */
- for ( raw = 0 ; raw < count ; raw++ ) {
- bits = deflate_length ( deflate, ( raw + offset ) );
- if ( bits ) {
- huf_sym = &alphabet->huf[ bits - 1 ];
- *(huf_sym->raw++) = raw;
- }
- }
-
- /* Adjust Huffman-coded symbol table raw pointers and populate
- * quick lookup table.
- */
- for ( bits = 1 ; bits <= ( sizeof ( alphabet->huf ) /
- sizeof ( alphabet->huf[0] ) ) ; bits++ ) {
- huf_sym = &alphabet->huf[ bits - 1 ];
-
- /* Adjust raw pointer */
- huf_sym->raw -= huf_sym->freq; /* Reset to first symbol */
- adjustment = ( huf_sym->start >> huf_sym->shift );
- huf_sym->raw -= adjustment; /* Adjust for quick indexing */
-
- /* Populate quick lookup table */
- for ( prefix = ( huf_sym->start >> DEFLATE_HUFFMAN_QL_SHIFT ) ;
- prefix < ( 1 << DEFLATE_HUFFMAN_QL_BITS ) ; prefix++ ) {
- alphabet->lookup[prefix] = ( bits - 1 );
- }
- }
-
- /* Dump alphabet (for debugging) */
- deflate_dump_alphabet ( deflate, alphabet );
-
- /* Check that there are no invalid codes */
- if ( ! complete ) {
- DBGC ( alphabet, "DEFLATE %p \"%s\" is incomplete\n", deflate,
- deflate_alphabet_name ( deflate, alphabet ) );
- return -EINVAL;
- }
-
- return 0;
- }
-
- /**
- * Attempt to accumulate bits from input stream
- *
- * @v deflate Decompressor
- * @v in Compressed input data
- * @v target Number of bits to accumulate
- * @ret excess Number of excess bits accumulated (may be negative)
- */
- static int deflate_accumulate ( struct deflate *deflate,
- struct deflate_chunk *in,
- unsigned int target ) {
- uint8_t byte;
-
- while ( deflate->bits < target ) {
-
- /* Check for end of input */
- if ( in->offset >= in->len )
- break;
-
- /* Acquire byte from input */
- copy_from_user ( &byte, in->data, in->offset++,
- sizeof ( byte ) );
- deflate->accumulator = ( deflate->accumulator |
- ( byte << deflate->bits ) );
- deflate->rotalumucca = ( deflate->rotalumucca |
- ( deflate_reverse[byte] <<
- ( 24 - deflate->bits ) ) );
- deflate->bits += 8;
-
- /* Sanity check */
- assert ( deflate->bits <=
- ( 8 * sizeof ( deflate->accumulator ) ) );
- }
-
- return ( deflate->bits - target );
- }
-
- /**
- * Consume accumulated bits from the input stream
- *
- * @v deflate Decompressor
- * @v count Number of accumulated bits to consume
- * @ret data Consumed bits
- */
- static int deflate_consume ( struct deflate *deflate, unsigned int count ) {
- int data;
-
- /* Sanity check */
- assert ( count <= deflate->bits );
-
- /* Extract data and consume bits */
- data = ( deflate->accumulator & ( ( 1 << count ) - 1 ) );
- deflate->accumulator >>= count;
- deflate->rotalumucca <<= count;
- deflate->bits -= count;
-
- return data;
- }
-
- /**
- * Attempt to extract a fixed number of bits from input stream
- *
- * @v deflate Decompressor
- * @v in Compressed input data
- * @v target Number of bits to extract
- * @ret data Extracted bits (or negative if not yet accumulated)
- */
- static int deflate_extract ( struct deflate *deflate, struct deflate_chunk *in,
- unsigned int target ) {
- int excess;
- int data;
-
- /* Return immediately if we are attempting to extract zero bits */
- if ( target == 0 )
- return 0;
-
- /* Attempt to accumulate bits */
- excess = deflate_accumulate ( deflate, in, target );
- if ( excess < 0 )
- return excess;
-
- /* Extract data and consume bits */
- data = deflate_consume ( deflate, target );
- DBGCP ( deflate, "DEFLATE %p extracted %s = %#x = %d\n", deflate,
- deflate_bin ( data, target ), data, data );
-
- return data;
- }
-
- /**
- * Attempt to decode a Huffman-coded symbol from input stream
- *
- * @v deflate Decompressor
- * @v in Compressed input data
- * @v alphabet Huffman alphabet
- * @ret code Raw code (or negative if not yet accumulated)
- */
- static int deflate_decode ( struct deflate *deflate,
- struct deflate_chunk *in,
- struct deflate_alphabet *alphabet ) {
- struct deflate_huf_symbols *huf_sym;
- uint16_t huf;
- unsigned int lookup_index;
- int excess;
- unsigned int raw;
-
- /* Attempt to accumulate maximum required number of bits.
- * There may be fewer bits than this remaining in the stream,
- * even if the stream still contains some complete
- * Huffman-coded symbols.
- */
- deflate_accumulate ( deflate, in, DEFLATE_HUFFMAN_BITS );
-
- /* Normalise the bit-reversed accumulated value to 16 bits */
- huf = ( deflate->rotalumucca >> 16 );
-
- /* Find symbol set for this length */
- lookup_index = ( huf >> DEFLATE_HUFFMAN_QL_SHIFT );
- huf_sym = &alphabet->huf[ alphabet->lookup[ lookup_index ] ];
- while ( huf < huf_sym->start )
- huf_sym--;
-
- /* Calculate number of excess bits, and return if not yet complete */
- excess = ( deflate->bits - huf_sym->bits );
- if ( excess < 0 )
- return excess;
-
- /* Consume bits */
- deflate_consume ( deflate, huf_sym->bits );
-
- /* Look up raw symbol */
- raw = huf_sym->raw[ huf >> huf_sym->shift ];
- DBGCP ( deflate, "DEFLATE %p decoded %s = %#x = %d\n", deflate,
- deflate_bin ( ( huf >> huf_sym->shift ), huf_sym->bits ),
- raw, raw );
-
- return raw;
- }
-
- /**
- * Discard bits up to the next byte boundary
- *
- * @v deflate Decompressor
- */
- static void deflate_discard_to_byte ( struct deflate *deflate ) {
-
- deflate_consume ( deflate, ( deflate->bits & 7 ) );
- }
-
- /**
- * Copy data to output buffer (if available)
- *
- * @v out Output data buffer
- * @v start Source data
- * @v offset Starting offset within source data
- * @v len Length to copy
- */
- static void deflate_copy ( struct deflate_chunk *out,
- userptr_t start, size_t offset, size_t len ) {
- size_t out_offset = out->offset;
- size_t copy_len;
-
- /* Copy data one byte at a time, to allow for overlap */
- if ( out_offset < out->len ) {
- copy_len = ( out->len - out_offset );
- if ( copy_len > len )
- copy_len = len;
- while ( copy_len-- ) {
- memcpy_user ( out->data, out_offset++,
- start, offset++, 1 );
- }
- }
- out->offset += len;
- }
-
- /**
- * Inflate compressed data
- *
- * @v deflate Decompressor
- * @v in Compressed input data
- * @v out Output data buffer
- * @ret rc Return status code
- *
- * The caller can use deflate_finished() to determine whether a
- * successful return indicates that the decompressor is merely waiting
- * for more input.
- *
- * Data will not be written beyond the specified end of the output
- * data buffer, but the offset within the output data buffer will be
- * updated to reflect the amount that should have been written. The
- * caller can use this to find the length of the decompressed data
- * before allocating the output data buffer.
- */
- int deflate_inflate ( struct deflate *deflate,
- struct deflate_chunk *in,
- struct deflate_chunk *out ) {
-
- /* This could be implemented more neatly if gcc offered a
- * means for enforcing tail recursion.
- */
- if ( deflate->resume ) {
- goto *(deflate->resume);
- } else switch ( deflate->format ) {
- case DEFLATE_RAW: goto block_header;
- case DEFLATE_ZLIB: goto zlib_header;
- default: assert ( 0 );
- }
-
- zlib_header: {
- int header;
- int cm;
-
- /* Extract header */
- header = deflate_extract ( deflate, in, ZLIB_HEADER_BITS );
- if ( header < 0 ) {
- deflate->resume = &&zlib_header;
- return 0;
- }
-
- /* Parse header */
- cm = ( ( header >> ZLIB_HEADER_CM_LSB ) & ZLIB_HEADER_CM_MASK );
- if ( cm != ZLIB_HEADER_CM_DEFLATE ) {
- DBGC ( deflate, "DEFLATE %p unsupported ZLIB "
- "compression method %d\n", deflate, cm );
- return -ENOTSUP;
- }
- if ( header & ( 1 << ZLIB_HEADER_FDICT_BIT ) ) {
- DBGC ( deflate, "DEFLATE %p unsupported ZLIB preset "
- "dictionary\n", deflate );
- return -ENOTSUP;
- }
-
- /* Process first block header */
- goto block_header;
- }
-
- block_header: {
- int header;
- int bfinal;
- int btype;
-
- /* Extract block header */
- header = deflate_extract ( deflate, in, DEFLATE_HEADER_BITS );
- if ( header < 0 ) {
- deflate->resume = &&block_header;
- return 0;
- }
-
- /* Parse header */
- deflate->header = header;
- bfinal = ( header & ( 1 << DEFLATE_HEADER_BFINAL_BIT ) );
- btype = ( header >> DEFLATE_HEADER_BTYPE_LSB );
- DBGC ( deflate, "DEFLATE %p found %sblock type %#x\n",
- deflate, ( bfinal ? "final " : "" ), btype );
- switch ( btype ) {
- case DEFLATE_HEADER_BTYPE_LITERAL:
- goto literal_block;
- case DEFLATE_HEADER_BTYPE_STATIC:
- goto static_block;
- case DEFLATE_HEADER_BTYPE_DYNAMIC:
- goto dynamic_block;
- default:
- DBGC ( deflate, "DEFLATE %p unsupported block type "
- "%#x\n", deflate, btype );
- return -ENOTSUP;
- }
- }
-
- literal_block: {
-
- /* Discard any bits up to the next byte boundary */
- deflate_discard_to_byte ( deflate );
- }
-
- literal_len: {
- int len;
-
- /* Extract LEN field */
- len = deflate_extract ( deflate, in, DEFLATE_LITERAL_LEN_BITS );
- if ( len < 0 ) {
- deflate->resume = &&literal_len;
- return 0;
- }
-
- /* Record length of literal data */
- deflate->remaining = len;
- DBGC2 ( deflate, "DEFLATE %p literal block length %#04zx\n",
- deflate, deflate->remaining );
- }
-
- literal_nlen: {
- int nlen;
-
- /* Extract NLEN field */
- nlen = deflate_extract ( deflate, in, DEFLATE_LITERAL_LEN_BITS);
- if ( nlen < 0 ) {
- deflate->resume = &&literal_nlen;
- return 0;
- }
-
- /* Verify NLEN */
- if ( ( ( deflate->remaining ^ ~nlen ) &
- ( ( 1 << DEFLATE_LITERAL_LEN_BITS ) - 1 ) ) != 0 ) {
- DBGC ( deflate, "DEFLATE %p invalid len/nlen "
- "%#04zx/%#04x\n", deflate,
- deflate->remaining, nlen );
- return -EINVAL;
- }
- }
-
- literal_data: {
- size_t in_remaining;
- size_t len;
-
- /* Calculate available amount of literal data */
- in_remaining = ( in->len - in->offset );
- len = deflate->remaining;
- if ( len > in_remaining )
- len = in_remaining;
-
- /* Copy data to output buffer */
- deflate_copy ( out, in->data, in->offset, len );
-
- /* Consume data from input buffer */
- in->offset += len;
- deflate->remaining -= len;
-
- /* Finish processing if we are blocked */
- if ( deflate->remaining ) {
- deflate->resume = &&literal_data;
- return 0;
- }
-
- /* Otherwise, finish block */
- goto block_done;
- }
-
- static_block: {
- struct deflate_static_length_pattern *pattern;
- uint8_t *lengths = deflate->lengths;
-
- /* Construct static Huffman lengths as per RFC 1950 */
- for ( pattern = deflate_static_length_patterns ;
- pattern->count ; pattern++ ) {
- memset ( lengths, pattern->fill, pattern->count );
- lengths += pattern->count;
- }
- deflate->litlen_count = 288;
- deflate->distance_count = 32;
- goto construct_alphabets;
- }
-
- dynamic_block:
-
- dynamic_header: {
- int header;
- unsigned int hlit;
- unsigned int hdist;
- unsigned int hclen;
-
- /* Extract block header */
- header = deflate_extract ( deflate, in, DEFLATE_DYNAMIC_BITS );
- if ( header < 0 ) {
- deflate->resume = &&dynamic_header;
- return 0;
- }
-
- /* Parse header */
- hlit = ( ( header >> DEFLATE_DYNAMIC_HLIT_LSB ) &
- DEFLATE_DYNAMIC_HLIT_MASK );
- hdist = ( ( header >> DEFLATE_DYNAMIC_HDIST_LSB ) &
- DEFLATE_DYNAMIC_HDIST_MASK );
- hclen = ( ( header >> DEFLATE_DYNAMIC_HCLEN_LSB ) &
- DEFLATE_DYNAMIC_HCLEN_MASK );
- deflate->litlen_count = ( hlit + 257 );
- deflate->distance_count = ( hdist + 1 );
- deflate->length_index = 0;
- deflate->length_target = ( hclen + 4 );
- DBGC2 ( deflate, "DEFLATE %p dynamic block %d codelen, %d "
- "litlen, %d distance\n", deflate,
- deflate->length_target, deflate->litlen_count,
- deflate->distance_count );
-
- /* Prepare for decoding code length code lengths */
- memset ( &deflate->lengths, 0, sizeof ( deflate->lengths ) );
- }
-
- dynamic_codelen: {
- int len;
- unsigned int index;
- int rc;
-
- /* Extract all code lengths */
- while ( deflate->length_index < deflate->length_target ) {
-
- /* Extract code length length */
- len = deflate_extract ( deflate, in,
- DEFLATE_CODELEN_BITS );
- if ( len < 0 ) {
- deflate->resume = &&dynamic_codelen;
- return 0;
- }
-
- /* Store code length */
- index = deflate_codelen_map[deflate->length_index++];
- deflate_set_length ( deflate, index, len );
- DBGCP ( deflate, "DEFLATE %p codelen for %d is %d\n",
- deflate, index, len );
- }
-
- /* Generate code length alphabet */
- if ( ( rc = deflate_alphabet ( deflate,
- &deflate->distance_codelen,
- ( DEFLATE_CODELEN_MAX_CODE + 1 ),
- 0 ) ) != 0 )
- return rc;
-
- /* Prepare for decoding literal/length/distance code lengths */
- memset ( &deflate->lengths, 0, sizeof ( deflate->lengths ) );
- deflate->length_index = 0;
- deflate->length_target = ( deflate->litlen_count +
- deflate->distance_count );
- deflate->length = 0;
- }
-
- dynamic_litlen_distance: {
- int len;
- int index;
-
- /* Decode literal/length/distance code length */
- len = deflate_decode ( deflate, in, &deflate->distance_codelen);
- if ( len < 0 ) {
- deflate->resume = &&dynamic_litlen_distance;
- return 0;
- }
-
- /* Prepare for extra bits */
- if ( len < 16 ) {
- deflate->length = len;
- deflate->extra_bits = 0;
- deflate->dup_len = 1;
- } else {
- static const uint8_t dup_len[3] = { 3, 3, 11 };
- static const uint8_t extra_bits[3] = { 2, 3, 7 };
- index = ( len - 16 );
- deflate->dup_len = dup_len[index];
- deflate->extra_bits = extra_bits[index];
- if ( index )
- deflate->length = 0;
- }
- }
-
- dynamic_litlen_distance_extra: {
- int extra;
- unsigned int dup_len;
-
- /* Extract extra bits */
- extra = deflate_extract ( deflate, in, deflate->extra_bits );
- if ( extra < 0 ) {
- deflate->resume = &&dynamic_litlen_distance_extra;
- return 0;
- }
-
- /* Store code lengths */
- dup_len = ( deflate->dup_len + extra );
- while ( ( deflate->length_index < deflate->length_target ) &&
- dup_len-- ) {
- deflate_set_length ( deflate, deflate->length_index++,
- deflate->length );
- }
-
- /* Process next literal/length or distance code
- * length, if more are required.
- */
- if ( deflate->length_index < deflate->length_target )
- goto dynamic_litlen_distance;
-
- /* Construct alphabets */
- goto construct_alphabets;
- }
-
- construct_alphabets: {
- unsigned int distance_offset = deflate->litlen_count;
- unsigned int distance_count = deflate->distance_count;
- int rc;
-
- /* Generate literal/length alphabet */
- if ( ( rc = deflate_alphabet ( deflate, &deflate->litlen,
- deflate->litlen_count, 0 ) ) !=0)
- return rc;
-
- /* Handle degenerate case of a single distance code
- * (for which it is impossible to construct a valid,
- * complete Huffman alphabet). RFC 1951 states:
- *
- * If only one distance code is used, it is encoded
- * using one bit, not zero bits; in this case there
- * is a single code length of one, with one unused
- * code. One distance code of zero bits means that
- * there are no distance codes used at all (the data
- * is all literals).
- *
- * If we have only a single distance code, then we
- * instead use two distance codes both with length 1.
- * This results in a valid Huffman alphabet. The code
- * "0" will mean distance code 0 (which is either
- * correct or irrelevant), and the code "1" will mean
- * distance code 1 (which is always irrelevant).
- */
- if ( deflate->distance_count == 1 ) {
-
- deflate->lengths[0] = 0x11;
- distance_offset = 0;
- distance_count = 2;
- }
-
- /* Generate distance alphabet */
- if ( ( rc = deflate_alphabet ( deflate,
- &deflate->distance_codelen,
- distance_count,
- distance_offset ) ) != 0 )
- return rc;
- }
-
- lzhuf_litlen: {
- int code;
- uint8_t byte;
- unsigned int extra;
- unsigned int bits;
-
- /* Decode Huffman codes */
- while ( 1 ) {
-
- /* Decode Huffman code */
- code = deflate_decode ( deflate, in, &deflate->litlen );
- if ( code < 0 ) {
- deflate->resume = &&lzhuf_litlen;
- return 0;
- }
-
- /* Handle according to code type */
- if ( code < DEFLATE_LITLEN_END ) {
-
- /* Literal value: copy to output buffer */
- byte = code;
- DBGCP ( deflate, "DEFLATE %p literal %#02x "
- "('%c')\n", deflate, byte,
- ( isprint ( byte ) ? byte : '.' ) );
- deflate_copy ( out, virt_to_user ( &byte ), 0,
- sizeof ( byte ) );
-
- } else if ( code == DEFLATE_LITLEN_END ) {
-
- /* End of block */
- goto block_done;
-
- } else {
-
- /* Length code: process extra bits */
- extra = ( code - DEFLATE_LITLEN_END - 1 );
- if ( extra < 28 ) {
- bits = ( extra / 4 );
- if ( bits )
- bits--;
- deflate->extra_bits = bits;
- deflate->dup_len =
- deflate_litlen_base[extra];
- } else {
- deflate->extra_bits = 0;
- deflate->dup_len = 258;
- }
- goto lzhuf_litlen_extra;
- }
- }
- }
-
- lzhuf_litlen_extra: {
- int extra;
-
- /* Extract extra bits */
- extra = deflate_extract ( deflate, in, deflate->extra_bits );
- if ( extra < 0 ) {
- deflate->resume = &&lzhuf_litlen_extra;
- return 0;
- }
-
- /* Update duplicate length */
- deflate->dup_len += extra;
- }
-
- lzhuf_distance: {
- int code;
- unsigned int extra;
- unsigned int bits;
-
- /* Decode Huffman code */
- code = deflate_decode ( deflate, in,
- &deflate->distance_codelen );
- if ( code < 0 ) {
- deflate->resume = &&lzhuf_distance;
- return 0;
- }
-
- /* Process extra bits */
- extra = code;
- bits = ( extra / 2 );
- if ( bits )
- bits--;
- deflate->extra_bits = bits;
- deflate->dup_distance = deflate_distance_base[extra];
- }
-
- lzhuf_distance_extra: {
- int extra;
- size_t dup_len;
- size_t dup_distance;
-
- /* Extract extra bits */
- extra = deflate_extract ( deflate, in, deflate->extra_bits );
- if ( extra < 0 ) {
- deflate->resume = &&lzhuf_distance_extra;
- return 0;
- }
-
- /* Update duplicate distance */
- dup_distance = ( deflate->dup_distance + extra );
- dup_len = deflate->dup_len;
- DBGCP ( deflate, "DEFLATE %p duplicate length %zd distance "
- "%zd\n", deflate, dup_len, dup_distance );
-
- /* Sanity check */
- if ( dup_distance > out->offset ) {
- DBGC ( deflate, "DEFLATE %p bad distance %zd (max "
- "%zd)\n", deflate, dup_distance, out->offset );
- return -EINVAL;
- }
-
- /* Copy data, allowing for overlap */
- deflate_copy ( out, out->data, ( out->offset - dup_distance ),
- dup_len );
-
- /* Process next literal/length symbol */
- goto lzhuf_litlen;
- }
-
- block_done: {
-
- DBGCP ( deflate, "DEFLATE %p end of block\n", deflate );
-
- /* If this was not the final block, process next block header */
- if ( ! ( deflate->header & ( 1 << DEFLATE_HEADER_BFINAL_BIT ) ))
- goto block_header;
-
- /* Otherwise, process footer (if any) */
- switch ( deflate->format ) {
- case DEFLATE_RAW: goto finished;
- case DEFLATE_ZLIB: goto zlib_footer;
- default: assert ( 0 );
- }
- }
-
- zlib_footer: {
-
- /* Discard any bits up to the next byte boundary */
- deflate_discard_to_byte ( deflate );
- }
-
- zlib_adler32: {
- int excess;
-
- /* Accumulate the 32 bits of checksum. We don't check
- * the value, stop processing immediately afterwards,
- * and so don't have to worry about the nasty corner
- * cases involved in calling deflate_extract() to
- * obtain a full 32 bits.
- */
- excess = deflate_accumulate ( deflate, in, ZLIB_ADLER32_BITS );
- if ( excess < 0 ) {
- deflate->resume = &&zlib_adler32;
- return 0;
- }
-
- /* Finish processing */
- goto finished;
- }
-
- finished: {
- /* Mark as finished and terminate */
- DBGCP ( deflate, "DEFLATE %p finished\n", deflate );
- deflate->resume = NULL;
- return 0;
- }
- }
-
- /**
- * Initialise decompressor
- *
- * @v deflate Decompressor
- * @v format Compression format code
- */
- void deflate_init ( struct deflate *deflate, enum deflate_format format ) {
- static int global_init_done;
- uint8_t i;
- uint8_t bit;
- uint8_t byte;
- unsigned int base;
- unsigned int bits;
-
- /* Perform global initialisation if required */
- if ( ! global_init_done ) {
-
- /* Initialise byte reversal table */
- for ( i = 255 ; i ; i-- ) {
- for ( bit = 1, byte = 0 ; bit ; bit <<= 1 ) {
- byte <<= 1;
- if ( i & bit )
- byte |= 1;
- }
- deflate_reverse[i] = byte;
- }
-
- /* Initialise literal/length extra bits table */
- base = 3;
- for ( i = 0 ; i < 28 ; i++ ) {
- bits = ( i / 4 );
- if ( bits )
- bits--;
- deflate_litlen_base[i] = base;
- base += ( 1 << bits );
- }
- assert ( base == 259 ); /* sic */
-
- /* Initialise distance extra bits table */
- base = 1;
- for ( i = 0 ; i < 30 ; i++ ) {
- bits = ( i / 2 );
- if ( bits )
- bits--;
- deflate_distance_base[i] = base;
- base += ( 1 << bits );
- }
- assert ( base == 32769 );
-
- /* Record global initialisation as complete */
- global_init_done = 1;
- }
-
- /* Initialise structure */
- memset ( deflate, 0, sizeof ( *deflate ) );
- deflate->format = format;
- }
|