⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 infdyna.c

📁 windows gzip source code
💻 C
📖 第 1 页 / 共 2 页
字号:
//
// infdyna.c
//
// Decompress a dynamically compressed block
//
#include <stdio.h>
#include <crtdbg.h>
#include "inflate.h"
#include "infmacro.h"
#include "maketbl.h"


#define OUTPUT_EOF() (output_curpos >= context->end_output_buffer)

//
// This is the slow version, which worries about the input running out or the output
// running out.  The trick here is to not read any more bytes than we need to; theoretically
// the "end of block" code could be 1 bit, so we cannot always assume that it is ok to fill
// the bit buffer with 16 bits right before a table decode.
//
BOOL DecodeDynamicBlock(t_decoder_context *context, BOOL *end_of_block_code_seen) 
{
	const byte *	input_ptr;
	const byte *	end_input_buffer;
	byte *			output_curpos;
	byte *			window;
	unsigned long	bufpos;
	unsigned long	bitbuf;
	int				bitcount;
	int				length;
	long			dist_code;
	unsigned long	offset;
    t_decoder_state old_state;
    BYTE            fCanTryFastEncoder = TRUE;

	*end_of_block_code_seen = FALSE;

	//
	// Store these variables locally for speed
	//
top:
	output_curpos	= context->output_curpos;

	window = context->window;
	bufpos = context->bufpos;

	end_input_buffer = context->end_input_buffer;

	LOAD_BITBUF_VARS();

	_ASSERT(bitcount >= -16);

    old_state = context->state;
    context->state = STATE_DECODE_TOP; // reset state

	switch (old_state)
	{
		case STATE_DECODE_TOP:
			break;

		case STATE_HAVE_INITIAL_LENGTH:
			length = context->length;
			goto reenter_state_have_initial_length;

		case STATE_HAVE_FULL_LENGTH:
			length = context->length;
			goto reenter_state_have_full_length;

		case STATE_HAVE_DIST_CODE:
			length = context->length;
			dist_code = context->dist_code;
			goto reenter_state_have_dist_code;

		case STATE_INTERRUPTED_MATCH:
			length = context->length;
			offset = context->offset;
			goto reenter_state_interrupted_match;

        default:
            _ASSERT(0); // error, invalid state!
	}

	do
	{
        //
        // The first time we're at the top of this loop, check whether we can use the
        // fast encoder; we will do this if the input and output buffers are nowhere
        // near the end, which allows the fast encoder to be a little more relaxed
        // about checking for these conditions
        //
        // If we cannot enter the fast encoder when we first check, then we will not
        // be able to enter it again while we're in this function (the amount of
        // input/output available is not going to get any larger), so don't check
        // again.
        //
        if (fCanTryFastEncoder)
        {
    		if (context->output_curpos + MAX_MATCH < context->end_output_buffer &&
	    		context->input_curpos + 12 < context->end_input_buffer)
    		{
	    		SAVE_BITBUF_VARS();
		    	context->output_curpos = output_curpos;
    			context->bufpos = bufpos;

    			if (FastDecodeDynamicBlock(context, end_of_block_code_seen) == FALSE)
	    			return FALSE;

    			if (*end_of_block_code_seen)
	    			return TRUE;

    			goto top;
	    	}
            else
            {
                // don't check again
                fCanTryFastEncoder = FALSE;
            }
        }

		//
		// decode an element from the main tree
		//

		// we must have at least 1 bit available
		_ASSERT(bitcount >= -16);

		if (bitcount == -16)
		{
			if (input_ptr >= end_input_buffer)
				break;

			bitbuf |= ((*input_ptr++) << (bitcount+16)); 
			bitcount += 8; 
		}

retry_decode_literal:

		// assert that at least 1 bit is present
		_ASSERT(bitcount > -16);

		// decode an element from the literal tree
		length = context->literal_table[bitbuf & LITERAL_TABLE_MASK]; 
		
		while (length < 0) 
		{ 
			unsigned long mask = 1 << LITERAL_TABLE_BITS; 
			do 
			{ 
				length = -length; 
				if ((bitbuf & mask) == 0) 
					length = context->literal_left[length]; 
				else 
					length = context->literal_right[length]; 
				mask <<= 1; 
			} while (length < 0); 
		}

		//
		// If this code is longer than the # bits we had in the bit buffer (i.e.
		// we read only part of the code - but enough to know that it's too long),
		// read more bits and retry
		//
		if (context->literal_tree_code_length[length] > (bitcount+16))
		{
			// if we run out of bits, break
			if (input_ptr >= end_input_buffer)
				break;

			bitbuf |= ((*input_ptr++) << (bitcount+16)); 
			bitcount += 8; 
			goto retry_decode_literal;		
		}

		DUMPBITS(context->literal_tree_code_length[length]);
		_ASSERT(bitcount >= -16);

		//
		// Is it a character or a match?
		//
		if (length < 256)
		{
			// it's an unmatched symbol
			window[bufpos] = *output_curpos++ = (byte) length;
			bufpos = (bufpos + 1) & WINDOW_MASK;
		}
		else
		{
			// it's a match
			int extra_bits;

			length -= 257;

			// if value was 256, that was the end-of-block code
			if (length < 0)
			{
				*end_of_block_code_seen = TRUE;
				break;
			}


			//
			// Get match length
			//

			//
			// These matches are by far the most common case.
			//
			if (length < 8)
			{
				// no extra bits

				// match length = 3,4,5,6,7,8,9,10
				length += 3;
			}
			else
			{
				int extra_bits;

reenter_state_have_initial_length:

				extra_bits = g_ExtraLengthBits[length];

				if (extra_bits > 0)
				{
					// make sure we have this many bits in the bit buffer
					if (extra_bits > bitcount + 16)
					{
						// if we run out of bits, break
						if (input_ptr >= end_input_buffer)
						{
							context->state = STATE_HAVE_INITIAL_LENGTH;
							context->length = length;
							break;
						}

						bitbuf |= ((*input_ptr++) << (bitcount+16)); 
						bitcount += 8;
						
						// extra_length_bits will be no more than 5, so we need to read at
						// most one byte of input to satisfy this request
					}

					length = g_LengthBase[length] + (bitbuf & g_BitMask[extra_bits]);

					DUMPBITS(extra_bits);
					_ASSERT(bitcount >= -16);
				}
				else
				{
					/*
					 * we know length > 8 and extra_bits == 0, there the length must be 258
					 */
					length = 258; /* g_LengthBase[length]; */
				}
			}

			//
			// Get match distance
			//

			// decode distance code
reenter_state_have_full_length:

			// we must have at least 1 bit available
			if (bitcount == -16)
			{
				if (input_ptr >= end_input_buffer)
				{
					context->state = STATE_HAVE_FULL_LENGTH;
					context->length = length;
					break;
				}

				bitbuf |= ((*input_ptr++) << (bitcount+16)); 
				bitcount += 8; 
			}


retry_decode_distance:

			// assert that at least 1 bit is present
			_ASSERT(bitcount > -16);

			dist_code = context->distance_table[bitbuf & DISTANCE_TABLE_MASK]; 
			
			while (dist_code < 0) 
			{ 
				unsigned long mask = 1 << DISTANCE_TABLE_BITS; 
			
				do 
				{ 
					dist_code = -dist_code; 
				
					if ((bitbuf & mask) == 0) 
						dist_code = context->distance_left[dist_code]; 
					else 
						dist_code = context->distance_right[dist_code]; 
					
					mask <<= 1; 
				} while (dist_code < 0); 
			}

			//
			// If this code is longer than the # bits we had in the bit buffer (i.e.
			// we read only part of the code - but enough to know that it's too long),
			// read more bits and retry
			//
			if (context->distance_tree_code_length[dist_code] > (bitcount+16))
			{
				// if we run out of bits, break
				if (input_ptr >= end_input_buffer)
				{
					context->state = STATE_HAVE_FULL_LENGTH;
					context->length = length;
					break;
				}

				bitbuf |= ((*input_ptr++) << (bitcount+16)); 
				bitcount += 8; 

				_ASSERT(bitcount >= -16);
				goto retry_decode_distance;		
			}


			DUMPBITS(context->distance_tree_code_length[dist_code]);

			// To avoid a table lookup we note that for dist_code >= 2,
			// extra_bits = (dist_code-2) >> 1
			//
			// Old (intuitive) way of doing this:
			//    offset = distance_base_position[dist_code] + 
			//	   		   getBits(extra_distance_bits[dist_code]);

reenter_state_have_dist_code:

			_ASSERT(bitcount >= -16);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -