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

📄 output.c

📁 windows gzip source code
💻 C
字号:
/*
 * output.c
 *
 * General outputting routines
 */
#include "deflate.h"
#include <string.h>
#include <stdio.h>
#include <crtdbg.h>


//
// Output an element from the pre-tree
//
#define OUTPUT_PRETREE_ELEMENT(element) \
	_ASSERT(pretree_len[element] != 0); \
	outputBits(context, pretree_len[element], pretree_code[element]);


//
// Output the tree structure for a dynamic block
//
void outputTreeStructure(t_encoder_context *context, const BYTE *literal_tree_len, const BYTE *dist_tree_len)
{
	int		hdist, hlit, combined_tree_elements, i, pass;
	USHORT	pretree_freq[NUM_PRETREE_ELEMENTS*2];
	USHORT	pretree_code[NUM_PRETREE_ELEMENTS];
	byte	pretree_len[NUM_PRETREE_ELEMENTS];

	//
	// combined literal + distance length code array for outputting the trees
	// in compressed form
	//
	// +3 is so we can overflow the array when performing run length encoding
	// (dummy values are inserted at the end so that run length encoding fails
	// before falling off the end of the array)
	//
	BYTE	lens[MAX_LITERAL_TREE_ELEMENTS + MAX_DIST_TREE_ELEMENTS + 3];

	//
	// Calculate HDIST
	//
	for (hdist = MAX_DIST_TREE_ELEMENTS - 1; hdist >= 1; hdist--)
	{
		if (dist_tree_len[hdist] != 0)
			break;
	}

	hdist++;

	//
	// Calculate HLIT
	//
	for (hlit = MAX_LITERAL_TREE_ELEMENTS - 1; hlit >= 257; hlit--)
	{
		if (literal_tree_len[hlit] != 0)
			break;
	}

	hlit++;

	//
	// Now initialise the array to have all of the hlit and hdist codes
	// in it
	//
	combined_tree_elements = hdist + hlit;

	memcpy(lens, literal_tree_len, hlit);
	memcpy(&lens[hlit], dist_tree_len, hdist);

	//
	// Stick in some dummy values at the end so that we don't overflow the 
	// array when comparing
	//
	for (i = combined_tree_elements; i < sizeof(lens); i++)
		lens[i] = -1;

	for (i = 0; i < NUM_PRETREE_ELEMENTS; i++)
		pretree_freq[i] = 0;

	//
	// Output the bitlengths in compressed (run length encoded) form.
	//
	// Make two passes; on the first pass count the various codes, create
	// the tree and output it, on the second pass output the codes using
	// the tree.
	//
	for (pass = 0; pass < 2; pass++)
	{
		int		cur_element;

		// are we outputting during this pass?
		BOOL	outputting = (pass == 1); 

		cur_element = 0;

		while (cur_element < combined_tree_elements)
		{
			int curlen = lens[cur_element];
			int run_length;

			//
			// See how many consecutive elements have the same value
			//
			// This won't run off the end of the array; it will hit the -1's
			// we stored there
			//
			for (run_length = cur_element+1; lens[run_length] == curlen; run_length++)
				;

			run_length -= cur_element;

			//
			// For non-zero codes need 4 identical in a row (original code
			// plus 3 repeats).  We decrement the run_length by one if the
			// code is not zero, since we don't count the first (original)
			// code in this case.
			//
			// For zero codes, need 3 zeroes in a row.
			//
			if (curlen != 0)
				run_length--;

			if (run_length < 3)
			{
				if (outputting)
				{
					OUTPUT_PRETREE_ELEMENT(curlen);
				}
				else
					pretree_freq[curlen]++;

				cur_element++;
			}
			else 
			{
				//
				// Elements with zero values are encoded specially
				//
				if (curlen == 0)
				{
					//
					// Do we use code 17 (3-10 repeated zeroes) or 
					// code 18 (11-138 repeated zeroes)?
					//
					if (run_length <= 10)
					{
						// code 17
						if (outputting)
						{
							OUTPUT_PRETREE_ELEMENT(17);
							outputBits(context, 3, run_length - 3);
						}
						else
						{
							pretree_freq[17]++;
						}
					}
					else
					{
						// code 18
						if (run_length > 138)
							run_length = 138;

						if (outputting)
						{
							OUTPUT_PRETREE_ELEMENT(18);
							outputBits(context, 7, run_length - 11);
						}
						else
						{
							pretree_freq[18]++;
						}
					}  

					cur_element += run_length;
				}
				else
				{
					//
					// Number of lengths actually encoded.  This may end up 
					// being less than run_length if we have a run length of
					// 7 (6 + 1 [which cannot be encoded with a code 16])
					//
					int run_length_encoded = 0;

					// curlen != 0

					// can output 3...6 repeats of a non-zero code, so split
					// longer runs into short ones (if possible)

					// remember to output the code itself first!
					if (outputting)
					{
						OUTPUT_PRETREE_ELEMENT(curlen);

						while (run_length >= 3)
						{
							int this_run = (run_length <= 6) ? run_length : 6;

							OUTPUT_PRETREE_ELEMENT(16);
							outputBits(context, 2, this_run - 3);

							run_length_encoded += this_run;
							run_length -= this_run;
						}
					}
					else
					{
						pretree_freq[curlen]++;

						while (run_length >= 3)
						{
							int this_run = (run_length <= 6) ? run_length : 6;

							pretree_freq[16]++;

							run_length_encoded += this_run;
							run_length -= this_run;
						}
					}

					// +1 for the original code itself
					cur_element += (run_length_encoded+1);
				}
			}
		}

		//
		// If this is the first pass, create the pretree from the
		// frequency data and output it, as well as the values of
		// HLIT, HDIST, HDCLEN (# pretree codes used)
		//
		if (pass == 0)
		{
			int hclen, i;

			makeTree(
				NUM_PRETREE_ELEMENTS,
				7, 
				pretree_freq, 
				pretree_code,
				pretree_len
			);

			//
			// Calculate HCLEN
			//
			for (hclen = NUM_PRETREE_ELEMENTS-1; hclen >= 4; hclen--)
			{
				if (pretree_len[ g_CodeOrder[hclen] ] != 0)
					break;
			}
			
			hclen++;

			//
			// Dynamic block header
			//
			outputBits(context, 5, hlit - 257);
			outputBits(context, 5, hdist - 1);
			outputBits(context, 4, hclen - 4);

			for (i = 0; i < hclen; i++)
			{
				outputBits(context, 3, pretree_len[g_CodeOrder[i]]);
			}
		}
	}
}


//
// bitwise i/o
//
void flushOutputBitBuffer(t_encoder_context *context)
{
	if (context->bitcount > 0)
	{
		int prev_bitcount = context->bitcount;
			
		outputBits(context, 16 - context->bitcount, 0);

		// backtrack if we have to; ZIP is byte aligned, not 16-bit word aligned
		if (prev_bitcount <= 8)
			context->output_curpos--;
	}
}


//
// Does not check for output overflow, so make sure to call checkOutputOverflow()
// often enough!
//
void outputBits(t_encoder_context *context, int n, int x)
{
	_ASSERT(context->output_curpos < context->output_endpos-1);
    _ASSERT(n > 0 && n <= 16);

	context->bitbuf |= (x << context->bitcount);
	context->bitcount += n;

	if (context->bitcount >= 16)                     
	{   
		*context->output_curpos++ = (BYTE) context->bitbuf;
		*context->output_curpos++ = (BYTE) (context->bitbuf >> 8);

		context->bitbuf >>= 16;
		context->bitcount -= 16;                         
	} 
}


// initialise the bit buffer
void InitBitBuffer(t_encoder_context *context)
{
	context->bitbuf		= 0;
	context->bitcount	= 0;
}


void OutputBlock(t_encoder_context *context)
{
    _ASSERT(context->std_encoder != NULL || context->optimal_encoder != NULL);
    
    // we never call OutputBlock() with the fast encoder
    _ASSERT(context->fast_encoder == NULL);

    if (context->std_encoder != NULL)
	    StdEncoderOutputBlock(context);
    else if (context->optimal_encoder != NULL)
        OptimalEncoderOutputBlock(context);
}


void FlushRecordingBuffer(t_encoder_context *context)
{
    _ASSERT(context->std_encoder != NULL || context->optimal_encoder != NULL);
    _ASSERT(context->fast_encoder == NULL); // fast encoder does not record

    if (context->std_encoder != NULL)
    {
        *context->std_encoder->recording_bufptr++ = (BYTE) context->std_encoder->recording_bitbuf; 
		*context->std_encoder->recording_bufptr++ = (BYTE) (context->std_encoder->recording_bitbuf >> 8); 
    }
    else if (context->optimal_encoder != NULL)
    {
        *context->optimal_encoder->recording_bufptr++ = (BYTE) context->optimal_encoder->recording_bitbuf; 
	    *context->optimal_encoder->recording_bufptr++ = (BYTE) (context->optimal_encoder->recording_bitbuf >> 8); 
    }
}

⌨️ 快捷键说明

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