Blame libfreerdp/codec/xcrush.c

Packit 1fb8d4
/**
Packit 1fb8d4
 * FreeRDP: A Remote Desktop Protocol Implementation
Packit 1fb8d4
 * XCrush (RDP6.1) Bulk Data Compression
Packit 1fb8d4
 *
Packit 1fb8d4
 * Copyright 2014 Marc-Andre Moreau <marcandre.moreau@gmail.com>
Packit 1fb8d4
 * Copyright 2017 Armin Novak <armin.novak@thincast.com>
Packit 1fb8d4
 * Copyright 2017 Thincast Technologies GmbH
Packit 1fb8d4
 *
Packit 1fb8d4
 * Licensed under the Apache License, Version 2.0 (the "License");
Packit 1fb8d4
 * you may not use this file except in compliance with the License.
Packit 1fb8d4
 * You may obtain a copy of the License at
Packit 1fb8d4
 *
Packit 1fb8d4
 *     http://www.apache.org/licenses/LICENSE-2.0
Packit 1fb8d4
 *
Packit 1fb8d4
 * Unless required by applicable law or agreed to in writing, software
Packit 1fb8d4
 * distributed under the License is distributed on an "AS IS" BASIS,
Packit 1fb8d4
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
Packit 1fb8d4
 * See the License for the specific language governing permissions and
Packit 1fb8d4
 * limitations under the License.
Packit 1fb8d4
 */
Packit 1fb8d4
Packit 1fb8d4
#ifdef HAVE_CONFIG_H
Packit 1fb8d4
#include "config.h"
Packit 1fb8d4
#endif
Packit 1fb8d4
Packit 1fb8d4
#include <winpr/crt.h>
Packit 1fb8d4
#include <winpr/print.h>
Packit 1fb8d4
#include <winpr/bitstream.h>
Packit 1fb8d4
Packit 1fb8d4
#include <freerdp/log.h>
Packit 1fb8d4
#include <freerdp/codec/xcrush.h>
Packit 1fb8d4
Packit 1fb8d4
#define TAG FREERDP_TAG("codec")
Packit 1fb8d4
Packit 1fb8d4
#ifdef DEBUG_XCRUSH
Packit 1fb8d4
static const char* xcrush_get_level_2_compression_flags_string(UINT32 flags)
Packit 1fb8d4
{
Packit 1fb8d4
	flags &= 0xE0;
Packit 1fb8d4
Packit 1fb8d4
	if (flags == 0)
Packit 1fb8d4
		return "PACKET_UNCOMPRESSED";
Packit 1fb8d4
	else if (flags == PACKET_COMPRESSED)
Packit 1fb8d4
		return "PACKET_COMPRESSED";
Packit 1fb8d4
	else if (flags == PACKET_AT_FRONT)
Packit 1fb8d4
		return "PACKET_AT_FRONT";
Packit 1fb8d4
	else if (flags == PACKET_FLUSHED)
Packit 1fb8d4
		return "PACKET_FLUSHED";
Packit 1fb8d4
	else if (flags == (PACKET_COMPRESSED | PACKET_AT_FRONT))
Packit 1fb8d4
		return "PACKET_COMPRESSED | PACKET_AT_FRONT";
Packit 1fb8d4
	else if (flags == (PACKET_COMPRESSED | PACKET_FLUSHED))
Packit 1fb8d4
		return "PACKET_COMPRESSED | PACKET_FLUSHED";
Packit 1fb8d4
	else if (flags == (PACKET_AT_FRONT | PACKET_FLUSHED))
Packit 1fb8d4
		return "PACKET_AT_FRONT | PACKET_FLUSHED";
Packit 1fb8d4
	else if (flags == (PACKET_COMPRESSED | PACKET_AT_FRONT | PACKET_FLUSHED))
Packit 1fb8d4
		return "PACKET_COMPRESSED | PACKET_AT_FRONT | PACKET_FLUSHED";
Packit 1fb8d4
Packit 1fb8d4
	return "PACKET_UNKNOWN";
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
static const char* xcrush_get_level_1_compression_flags_string(UINT32 flags)
Packit 1fb8d4
{
Packit 1fb8d4
	flags &= 0x17;
Packit 1fb8d4
Packit 1fb8d4
	if (flags == 0)
Packit 1fb8d4
		return "L1_UNKNOWN";
Packit 1fb8d4
	else if (flags == L1_PACKET_AT_FRONT)
Packit 1fb8d4
		return "L1_PACKET_AT_FRONT";
Packit 1fb8d4
	else if (flags == L1_NO_COMPRESSION)
Packit 1fb8d4
		return "L1_NO_COMPRESSION";
Packit 1fb8d4
	else if (flags == L1_COMPRESSED)
Packit 1fb8d4
		return "L1_COMPRESSED";
Packit 1fb8d4
	else if (flags == L1_INNER_COMPRESSION)
Packit 1fb8d4
		return "L1_INNER_COMPRESSION";
Packit 1fb8d4
	else if (flags == (L1_PACKET_AT_FRONT | L1_NO_COMPRESSION))
Packit 1fb8d4
		return "L1_PACKET_AT_FRONT | L1_NO_COMPRESSION";
Packit 1fb8d4
	else if (flags == (L1_PACKET_AT_FRONT | L1_COMPRESSED))
Packit 1fb8d4
		return "L1_PACKET_AT_FRONT | L1_COMPRESSED";
Packit 1fb8d4
	else if (flags == (L1_PACKET_AT_FRONT | L1_INNER_COMPRESSION))
Packit 1fb8d4
		return "L1_PACKET_AT_FRONT | L1_INNER_COMPRESSION";
Packit 1fb8d4
	else if (flags == (L1_NO_COMPRESSION | L1_COMPRESSED))
Packit 1fb8d4
		return "L1_NO_COMPRESSION | L1_COMPRESSED";
Packit 1fb8d4
	else if (flags == (L1_NO_COMPRESSION | L1_INNER_COMPRESSION))
Packit 1fb8d4
		return "L1_NO_COMPRESSION | L1_INNER_COMPRESSION";
Packit 1fb8d4
	else if (flags == (L1_COMPRESSED | L1_INNER_COMPRESSION))
Packit 1fb8d4
		return "L1_COMPRESSED | L1_INNER_COMPRESSION";
Packit 1fb8d4
	else if (flags == (L1_NO_COMPRESSION | L1_COMPRESSED | L1_INNER_COMPRESSION))
Packit 1fb8d4
		return "L1_NO_COMPRESSION | L1_COMPRESSED | L1_INNER_COMPRESSION";
Packit 1fb8d4
	else if (flags == (L1_PACKET_AT_FRONT | L1_COMPRESSED | L1_INNER_COMPRESSION))
Packit 1fb8d4
		return "L1_PACKET_AT_FRONT | L1_COMPRESSED | L1_INNER_COMPRESSION";
Packit 1fb8d4
	else if (flags == (L1_PACKET_AT_FRONT | L1_NO_COMPRESSION | L1_INNER_COMPRESSION))
Packit 1fb8d4
		return "L1_PACKET_AT_FRONT | L1_NO_COMPRESSION | L1_INNER_COMPRESSION";
Packit 1fb8d4
	else if (flags == (L1_PACKET_AT_FRONT | L1_NO_COMPRESSION | L1_COMPRESSED))
Packit 1fb8d4
		return "L1_PACKET_AT_FRONT | L1_NO_COMPRESSION | L1_COMPRESSED";
Packit 1fb8d4
	else if (flags == (L1_PACKET_AT_FRONT | L1_NO_COMPRESSION | L1_COMPRESSED | L1_INNER_COMPRESSION))
Packit 1fb8d4
		return "L1_PACKET_AT_FRONT | L1_NO_COMPRESSION | L1_COMPRESSED | L1_INNER_COMPRESSION";
Packit 1fb8d4
Packit 1fb8d4
	return "L1_UNKNOWN";
Packit 1fb8d4
}
Packit 1fb8d4
#endif
Packit 1fb8d4
Packit 1fb8d4
static UINT32 xcrush_update_hash(BYTE* data, UINT32 size)
Packit 1fb8d4
{
Packit 1fb8d4
	BYTE* end;
Packit 1fb8d4
	UINT32 seed = 5381; /* same value as in djb2 */
Packit 1fb8d4
Packit 1fb8d4
	if (size > 32)
Packit 1fb8d4
	{
Packit 1fb8d4
		size = 32;
Packit 1fb8d4
		seed = 5413;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	end = &data[size - 4];
Packit 1fb8d4
Packit 1fb8d4
	while (data < end)
Packit 1fb8d4
	{
Packit 1fb8d4
		seed += (data[3] ^ data[0]) + (data[1] << 8);
Packit 1fb8d4
		data += 4;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	return (UINT16) seed;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
static int xcrush_append_chunk(XCRUSH_CONTEXT* xcrush, BYTE* data, UINT32* beg, UINT32 end)
Packit 1fb8d4
{
Packit 1fb8d4
	UINT16 seed;
Packit 1fb8d4
	UINT32 size;
Packit 1fb8d4
Packit 1fb8d4
	if (xcrush->SignatureIndex >= xcrush->SignatureCount)
Packit 1fb8d4
		return 0;
Packit 1fb8d4
Packit 1fb8d4
	size = end - *beg;
Packit 1fb8d4
Packit 1fb8d4
	if (size > 65535)
Packit 1fb8d4
		return 0;
Packit 1fb8d4
Packit 1fb8d4
	if (size >= 15)
Packit 1fb8d4
	{
Packit 1fb8d4
		seed = xcrush_update_hash(&data[*beg], (UINT16) size);
Packit 1fb8d4
		xcrush->Signatures[xcrush->SignatureIndex].size = size;
Packit 1fb8d4
		xcrush->Signatures[xcrush->SignatureIndex].seed = seed;
Packit 1fb8d4
		xcrush->SignatureIndex++;
Packit 1fb8d4
		*beg = end;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	return 1;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
static int xcrush_compute_chunks(XCRUSH_CONTEXT* xcrush, BYTE* data, UINT32 size, UINT32* pIndex)
Packit 1fb8d4
{
Packit 1fb8d4
	UINT32 i = 0;
Packit 1fb8d4
	UINT32 offset = 0;
Packit 1fb8d4
	UINT32 rotation = 0;
Packit 1fb8d4
	UINT32 accumulator = 0;
Packit 1fb8d4
	*pIndex = 0;
Packit 1fb8d4
	xcrush->SignatureIndex = 0;
Packit 1fb8d4
Packit 1fb8d4
	if (size < 128)
Packit 1fb8d4
		return 0;
Packit 1fb8d4
Packit 1fb8d4
	for (i = 0; i < 32; i++)
Packit 1fb8d4
	{
Packit 1fb8d4
		rotation = _rotl(accumulator, 1);
Packit 1fb8d4
		accumulator = data[i] ^ rotation;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	for (i = 0; i < size - 64; i++)
Packit 1fb8d4
	{
Packit 1fb8d4
		rotation = _rotl(accumulator, 1);
Packit 1fb8d4
		accumulator = data[i + 32] ^ data[i] ^ rotation;
Packit 1fb8d4
Packit 1fb8d4
		if (!(accumulator & 0x7F))
Packit 1fb8d4
		{
Packit 1fb8d4
			if (!xcrush_append_chunk(xcrush, data, &offset, i + 32))
Packit 1fb8d4
				return 0;
Packit 1fb8d4
		}
Packit 1fb8d4
Packit 1fb8d4
		i++;
Packit 1fb8d4
		rotation = _rotl(accumulator, 1);
Packit 1fb8d4
		accumulator = data[i + 32] ^ data[i] ^ rotation;
Packit 1fb8d4
Packit 1fb8d4
		if (!(accumulator & 0x7F))
Packit 1fb8d4
		{
Packit 1fb8d4
			if (!xcrush_append_chunk(xcrush, data, &offset, i + 32))
Packit 1fb8d4
				return 0;
Packit 1fb8d4
		}
Packit 1fb8d4
Packit 1fb8d4
		i++;
Packit 1fb8d4
		rotation = _rotl(accumulator, 1);
Packit 1fb8d4
		accumulator = data[i + 32] ^ data[i] ^ rotation;
Packit 1fb8d4
Packit 1fb8d4
		if (!(accumulator & 0x7F))
Packit 1fb8d4
		{
Packit 1fb8d4
			if (!xcrush_append_chunk(xcrush, data, &offset, i + 32))
Packit 1fb8d4
				return 0;
Packit 1fb8d4
		}
Packit 1fb8d4
Packit 1fb8d4
		i++;
Packit 1fb8d4
		rotation = _rotl(accumulator, 1);
Packit 1fb8d4
		accumulator = data[i + 32] ^ data[i] ^ rotation;
Packit 1fb8d4
Packit 1fb8d4
		if (!(accumulator & 0x7F))
Packit 1fb8d4
		{
Packit 1fb8d4
			if (!xcrush_append_chunk(xcrush, data, &offset, i + 32))
Packit 1fb8d4
				return 0;
Packit 1fb8d4
		}
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	if ((size == offset) || xcrush_append_chunk(xcrush, data, &offset, size))
Packit 1fb8d4
	{
Packit 1fb8d4
		*pIndex = xcrush->SignatureIndex;
Packit 1fb8d4
		return 1;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	return 0;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
static UINT32 xcrush_compute_signatures(XCRUSH_CONTEXT* xcrush, BYTE* data, UINT32 size)
Packit 1fb8d4
{
Packit 1fb8d4
	UINT32 index = 0;
Packit 1fb8d4
Packit 1fb8d4
	if (xcrush_compute_chunks(xcrush, data, size, &index))
Packit 1fb8d4
		return index;
Packit 1fb8d4
Packit 1fb8d4
	return 0;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
static void xcrush_clear_hash_table_range(XCRUSH_CONTEXT* xcrush, UINT32 beg, UINT32 end)
Packit 1fb8d4
{
Packit 1fb8d4
	UINT32 index;
Packit 1fb8d4
Packit 1fb8d4
	for (index = 0; index < 65536; index++)
Packit 1fb8d4
	{
Packit 1fb8d4
		if (xcrush->NextChunks[index] >= beg)
Packit 1fb8d4
		{
Packit 1fb8d4
			if (xcrush->NextChunks[index] <= end)
Packit 1fb8d4
			{
Packit 1fb8d4
				xcrush->NextChunks[index] = 0;
Packit 1fb8d4
			}
Packit 1fb8d4
		}
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	for (index = 0; index < 65534; index++)
Packit 1fb8d4
	{
Packit 1fb8d4
		if (xcrush->Chunks[index].next >= beg)
Packit 1fb8d4
		{
Packit 1fb8d4
			if (xcrush->Chunks[index].next <= end)
Packit 1fb8d4
			{
Packit 1fb8d4
				xcrush->Chunks[index].next = 0;
Packit 1fb8d4
			}
Packit 1fb8d4
		}
Packit 1fb8d4
	}
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
static int xcrush_find_next_matching_chunk(XCRUSH_CONTEXT* xcrush, XCRUSH_CHUNK* chunk,
Packit 1fb8d4
        XCRUSH_CHUNK** pNextChunk)
Packit 1fb8d4
{
Packit 1fb8d4
	UINT32 index;
Packit 1fb8d4
	XCRUSH_CHUNK* next = NULL;
Packit 1fb8d4
Packit 1fb8d4
	if (!chunk)
Packit 1fb8d4
		return -4001; /* error */
Packit 1fb8d4
Packit 1fb8d4
	if (chunk->next)
Packit 1fb8d4
	{
Packit 1fb8d4
		index = (chunk - xcrush->Chunks) / sizeof(XCRUSH_CHUNK);
Packit 1fb8d4
Packit 1fb8d4
		if (index >= 65534)
Packit 1fb8d4
			return -4002; /* error */
Packit 1fb8d4
Packit 1fb8d4
		if ((index < xcrush->ChunkHead) || (chunk->next >= xcrush->ChunkHead))
Packit 1fb8d4
		{
Packit 1fb8d4
			if (chunk->next >= 65534)
Packit 1fb8d4
				return -4003; /* error */
Packit 1fb8d4
Packit 1fb8d4
			next = &xcrush->Chunks[chunk->next];
Packit 1fb8d4
		}
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	*pNextChunk = next;
Packit 1fb8d4
	return 1;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
static int xcrush_insert_chunk(XCRUSH_CONTEXT* xcrush, XCRUSH_SIGNATURE* signature, UINT32 offset,
Packit 1fb8d4
                               XCRUSH_CHUNK** pPrevChunk)
Packit 1fb8d4
{
Packit 1fb8d4
	UINT32 seed;
Packit 1fb8d4
	UINT32 index;
Packit 1fb8d4
Packit 1fb8d4
	if (xcrush->ChunkHead >= 65530)
Packit 1fb8d4
	{
Packit 1fb8d4
		xcrush->ChunkHead = 1;
Packit 1fb8d4
		xcrush->ChunkTail = 1;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	if (xcrush->ChunkHead >= xcrush->ChunkTail)
Packit 1fb8d4
	{
Packit 1fb8d4
		xcrush_clear_hash_table_range(xcrush, xcrush->ChunkTail, xcrush->ChunkTail + 10000);
Packit 1fb8d4
		xcrush->ChunkTail += 10000;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	index = xcrush->ChunkHead++;
Packit 1fb8d4
Packit 1fb8d4
	if (xcrush->ChunkHead >= 65534)
Packit 1fb8d4
		return -3001; /* error */
Packit 1fb8d4
Packit 1fb8d4
	xcrush->Chunks[index].offset = offset;
Packit 1fb8d4
	seed = signature->seed;
Packit 1fb8d4
Packit 1fb8d4
	if (seed >= 65536)
Packit 1fb8d4
		return -3002; /* error */
Packit 1fb8d4
Packit 1fb8d4
	if (xcrush->NextChunks[seed])
Packit 1fb8d4
	{
Packit 1fb8d4
		if (xcrush->NextChunks[seed] >= 65534)
Packit 1fb8d4
			return -3003; /* error */
Packit 1fb8d4
Packit 1fb8d4
		*pPrevChunk = &xcrush->Chunks[xcrush->NextChunks[seed]];
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	xcrush->Chunks[index].next = xcrush->NextChunks[seed] & 0xFFFF;
Packit 1fb8d4
	xcrush->NextChunks[seed] = index;
Packit 1fb8d4
	return 1;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
static int xcrush_find_match_length(XCRUSH_CONTEXT* xcrush, UINT32 MatchOffset, UINT32 ChunkOffset,
Packit 1fb8d4
                                    UINT32 HistoryOffset, UINT32 SrcSize, UINT32 MaxMatchLength, XCRUSH_MATCH_INFO* MatchInfo)
Packit 1fb8d4
{
Packit 1fb8d4
	UINT32 MatchSymbol;
Packit 1fb8d4
	UINT32 ChunkSymbol;
Packit 1fb8d4
	BYTE* ChunkBuffer;
Packit 1fb8d4
	BYTE* MatchBuffer;
Packit 1fb8d4
	BYTE* MatchStartPtr;
Packit 1fb8d4
	BYTE* ForwardChunkPtr;
Packit 1fb8d4
	BYTE* ReverseChunkPtr;
Packit 1fb8d4
	BYTE* ForwardMatchPtr;
Packit 1fb8d4
	BYTE* ReverseMatchPtr;
Packit 1fb8d4
	BYTE* HistoryBufferEnd;
Packit 1fb8d4
	UINT32 ReverseMatchLength;
Packit 1fb8d4
	UINT32 ForwardMatchLength;
Packit 1fb8d4
	UINT32 TotalMatchLength;
Packit 1fb8d4
	BYTE* HistoryBuffer;
Packit 1fb8d4
	UINT32 HistoryBufferSize;
Packit 1fb8d4
	ForwardMatchLength = 0;
Packit 1fb8d4
	ReverseMatchLength = 0;
Packit 1fb8d4
	HistoryBuffer = xcrush->HistoryBuffer;
Packit 1fb8d4
	HistoryBufferSize = xcrush->HistoryBufferSize;
Packit 1fb8d4
	HistoryBufferEnd = &HistoryBuffer[HistoryOffset + SrcSize];
Packit 1fb8d4
Packit 1fb8d4
	if (MatchOffset > HistoryBufferSize)
Packit 1fb8d4
		return -2001; /* error */
Packit 1fb8d4
Packit 1fb8d4
	MatchBuffer = &HistoryBuffer[MatchOffset];
Packit 1fb8d4
Packit 1fb8d4
	if (ChunkOffset > HistoryBufferSize)
Packit 1fb8d4
		return -2002; /* error */
Packit 1fb8d4
Packit 1fb8d4
	ChunkBuffer = &HistoryBuffer[ChunkOffset];
Packit 1fb8d4
Packit 1fb8d4
	if (MatchOffset == ChunkOffset)
Packit 1fb8d4
		return -2003; /* error */
Packit 1fb8d4
Packit 1fb8d4
	if (MatchBuffer < HistoryBuffer)
Packit 1fb8d4
		return -2004; /* error */
Packit 1fb8d4
Packit 1fb8d4
	if (ChunkBuffer < HistoryBuffer)
Packit 1fb8d4
		return -2005; /* error */
Packit 1fb8d4
Packit 1fb8d4
	ForwardMatchPtr = &HistoryBuffer[MatchOffset];
Packit 1fb8d4
	ForwardChunkPtr = &HistoryBuffer[ChunkOffset];
Packit 1fb8d4
Packit 1fb8d4
	if ((&MatchBuffer[MaxMatchLength + 1] < HistoryBufferEnd)
Packit 1fb8d4
	    && (MatchBuffer[MaxMatchLength + 1] != ChunkBuffer[MaxMatchLength + 1]))
Packit 1fb8d4
	{
Packit 1fb8d4
		return 0;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	while (1)
Packit 1fb8d4
	{
Packit 1fb8d4
		MatchSymbol = *ForwardMatchPtr++;
Packit 1fb8d4
		ChunkSymbol = *ForwardChunkPtr++;
Packit 1fb8d4
Packit 1fb8d4
		if (MatchSymbol != ChunkSymbol)
Packit 1fb8d4
			break;
Packit 1fb8d4
Packit 1fb8d4
		if (ForwardMatchPtr > HistoryBufferEnd)
Packit 1fb8d4
			break;
Packit 1fb8d4
Packit 1fb8d4
		ForwardMatchLength++;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	ReverseMatchPtr = MatchBuffer - 1;
Packit 1fb8d4
	ReverseChunkPtr = ChunkBuffer - 1;
Packit 1fb8d4
Packit 1fb8d4
	while ((ReverseMatchPtr > &HistoryBuffer[HistoryOffset])
Packit 1fb8d4
	       && (ReverseChunkPtr > HistoryBuffer)
Packit 1fb8d4
	       && (*ReverseMatchPtr == *ReverseChunkPtr))
Packit 1fb8d4
	{
Packit 1fb8d4
		ReverseMatchLength++;
Packit 1fb8d4
		ReverseMatchPtr--;
Packit 1fb8d4
		ReverseChunkPtr--;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	MatchStartPtr = MatchBuffer - ReverseMatchLength;
Packit 1fb8d4
	TotalMatchLength = ReverseMatchLength + ForwardMatchLength;
Packit 1fb8d4
Packit 1fb8d4
	if (TotalMatchLength < 11)
Packit 1fb8d4
		return 0;
Packit 1fb8d4
Packit 1fb8d4
	if (MatchStartPtr < HistoryBuffer)
Packit 1fb8d4
		return -2006; /* error */
Packit 1fb8d4
Packit 1fb8d4
	MatchInfo->MatchOffset = MatchStartPtr - HistoryBuffer;
Packit 1fb8d4
	MatchInfo->ChunkOffset = ChunkBuffer - ReverseMatchLength - HistoryBuffer;
Packit 1fb8d4
	MatchInfo->MatchLength = TotalMatchLength;
Packit 1fb8d4
	return (int) TotalMatchLength;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
static int xcrush_find_all_matches(XCRUSH_CONTEXT* xcrush, UINT32 SignatureIndex,
Packit 1fb8d4
                                   UINT32 HistoryOffset, UINT32 SrcOffset, UINT32 SrcSize)
Packit 1fb8d4
{
Packit 1fb8d4
	UINT32 i = 0;
Packit 1fb8d4
	UINT32 j = 0;
Packit 1fb8d4
	int status = 0;
Packit 1fb8d4
	UINT32 offset = 0;
Packit 1fb8d4
	UINT32 ChunkIndex = 0;
Packit 1fb8d4
	UINT32 ChunkCount = 0;
Packit 1fb8d4
	XCRUSH_CHUNK* chunk = NULL;
Packit 1fb8d4
	UINT32 MatchLength = 0;
Packit 1fb8d4
	UINT32 MaxMatchLength = 0;
Packit 1fb8d4
	UINT32 PrevMatchEnd = 0;
Packit 1fb8d4
	XCRUSH_MATCH_INFO MatchInfo = { 0 };
Packit 1fb8d4
	XCRUSH_MATCH_INFO MaxMatchInfo = { 0 };
Packit 1fb8d4
	XCRUSH_SIGNATURE* Signatures = NULL;
Packit 1fb8d4
	Signatures = xcrush->Signatures;
Packit 1fb8d4
Packit 1fb8d4
	for (i = 0; i < SignatureIndex; i++)
Packit 1fb8d4
	{
Packit 1fb8d4
		offset = SrcOffset + HistoryOffset;
Packit 1fb8d4
Packit 1fb8d4
		if (!Signatures[i].size)
Packit 1fb8d4
			return -1001; /* error */
Packit 1fb8d4
Packit 1fb8d4
		status = xcrush_insert_chunk(xcrush, &Signatures[i], offset, &chunk);
Packit 1fb8d4
Packit 1fb8d4
		if (status < 0)
Packit 1fb8d4
			return status;
Packit 1fb8d4
Packit 1fb8d4
		if (chunk && (SrcOffset + HistoryOffset + Signatures[i].size >= PrevMatchEnd))
Packit 1fb8d4
		{
Packit 1fb8d4
			ChunkCount = 0;
Packit 1fb8d4
			MaxMatchLength = 0;
Packit 1fb8d4
			ZeroMemory(&MaxMatchInfo, sizeof(XCRUSH_MATCH_INFO));
Packit 1fb8d4
Packit 1fb8d4
			while (chunk)
Packit 1fb8d4
			{
Packit 1fb8d4
				if ((chunk->offset < HistoryOffset) || (chunk->offset < offset)
Packit 1fb8d4
				    || (chunk->offset > SrcSize + HistoryOffset))
Packit 1fb8d4
				{
Packit 1fb8d4
					status = xcrush_find_match_length(xcrush, offset, chunk->offset,
Packit 1fb8d4
					                                  HistoryOffset, SrcSize, MaxMatchLength, &MatchInfo);
Packit 1fb8d4
Packit 1fb8d4
					if (status < 0)
Packit 1fb8d4
						return status; /* error */
Packit 1fb8d4
Packit 1fb8d4
					MatchLength = (UINT32) status;
Packit 1fb8d4
Packit 1fb8d4
					if (MatchLength > MaxMatchLength)
Packit 1fb8d4
					{
Packit 1fb8d4
						MaxMatchLength = MatchLength;
Packit 1fb8d4
						MaxMatchInfo.MatchOffset = MatchInfo.MatchOffset;
Packit 1fb8d4
						MaxMatchInfo.ChunkOffset = MatchInfo.ChunkOffset;
Packit 1fb8d4
						MaxMatchInfo.MatchLength = MatchInfo.MatchLength;
Packit 1fb8d4
Packit 1fb8d4
						if (MatchLength > 256)
Packit 1fb8d4
							break;
Packit 1fb8d4
					}
Packit 1fb8d4
				}
Packit 1fb8d4
Packit 1fb8d4
				ChunkIndex = ChunkCount++;
Packit 1fb8d4
Packit 1fb8d4
				if (ChunkIndex > 4)
Packit 1fb8d4
					break;
Packit 1fb8d4
Packit 1fb8d4
				status = xcrush_find_next_matching_chunk(xcrush, chunk, &chunk);
Packit 1fb8d4
Packit 1fb8d4
				if (status < 0)
Packit 1fb8d4
					return status; /* error */
Packit 1fb8d4
			}
Packit 1fb8d4
Packit 1fb8d4
			if (MaxMatchLength)
Packit 1fb8d4
			{
Packit 1fb8d4
				xcrush->OriginalMatches[j].MatchOffset = MaxMatchInfo.MatchOffset;
Packit 1fb8d4
				xcrush->OriginalMatches[j].ChunkOffset = MaxMatchInfo.ChunkOffset;
Packit 1fb8d4
				xcrush->OriginalMatches[j].MatchLength = MaxMatchInfo.MatchLength;
Packit 1fb8d4
Packit 1fb8d4
				if (xcrush->OriginalMatches[j].MatchOffset < HistoryOffset)
Packit 1fb8d4
					return -1002; /* error */
Packit 1fb8d4
Packit 1fb8d4
				PrevMatchEnd = xcrush->OriginalMatches[j].MatchLength + xcrush->OriginalMatches[j].MatchOffset;
Packit 1fb8d4
				j++;
Packit 1fb8d4
Packit 1fb8d4
				if (j >= 1000)
Packit 1fb8d4
					return -1003; /* error */
Packit 1fb8d4
			}
Packit 1fb8d4
		}
Packit 1fb8d4
Packit 1fb8d4
		SrcOffset += Signatures[i].size;
Packit 1fb8d4
Packit 1fb8d4
		if (SrcOffset > SrcSize)
Packit 1fb8d4
			return -1004; /* error */
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	if (SrcOffset > SrcSize)
Packit 1fb8d4
		return -1005; /* error */
Packit 1fb8d4
Packit 1fb8d4
	return (int) j;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
static int xcrush_optimize_matches(XCRUSH_CONTEXT* xcrush)
Packit 1fb8d4
{
Packit 1fb8d4
	UINT32 i, j;
Packit 1fb8d4
	UINT32 MatchDiff;
Packit 1fb8d4
	UINT32 PrevMatchEnd;
Packit 1fb8d4
	UINT32 TotalMatchLength;
Packit 1fb8d4
	UINT32 OriginalMatchCount;
Packit 1fb8d4
	UINT32 OptimizedMatchCount;
Packit 1fb8d4
	XCRUSH_MATCH_INFO* OriginalMatch;
Packit 1fb8d4
	XCRUSH_MATCH_INFO* OptimizedMatch;
Packit 1fb8d4
	XCRUSH_MATCH_INFO* OriginalMatches;
Packit 1fb8d4
	XCRUSH_MATCH_INFO* OptimizedMatches;
Packit 1fb8d4
	j = 0;
Packit 1fb8d4
	PrevMatchEnd = 0;
Packit 1fb8d4
	TotalMatchLength = 0;
Packit 1fb8d4
	OriginalMatches = xcrush->OriginalMatches;
Packit 1fb8d4
	OriginalMatchCount = xcrush->OriginalMatchCount;
Packit 1fb8d4
	OptimizedMatches = xcrush->OptimizedMatches;
Packit 1fb8d4
Packit 1fb8d4
	for (i = 0; i < OriginalMatchCount; i++)
Packit 1fb8d4
	{
Packit 1fb8d4
		if (OriginalMatches[i].MatchOffset <= PrevMatchEnd)
Packit 1fb8d4
		{
Packit 1fb8d4
			if ((OriginalMatches[i].MatchOffset < PrevMatchEnd)
Packit 1fb8d4
			    && (OriginalMatches[i].MatchLength + OriginalMatches[i].MatchOffset > PrevMatchEnd + 6))
Packit 1fb8d4
			{
Packit 1fb8d4
				MatchDiff = PrevMatchEnd - OriginalMatches[i].MatchOffset;
Packit 1fb8d4
				OriginalMatch = &OriginalMatches[i];
Packit 1fb8d4
				OptimizedMatch = &OptimizedMatches[j];
Packit 1fb8d4
				OptimizedMatch->MatchOffset = OriginalMatch->MatchOffset;
Packit 1fb8d4
				OptimizedMatch->ChunkOffset = OriginalMatch->ChunkOffset;
Packit 1fb8d4
				OptimizedMatch->MatchLength = OriginalMatch->MatchLength;
Packit 1fb8d4
Packit 1fb8d4
				if (OptimizedMatches[j].MatchLength <= MatchDiff)
Packit 1fb8d4
					return -5001; /* error */
Packit 1fb8d4
Packit 1fb8d4
				if (MatchDiff >= 20000)
Packit 1fb8d4
					return -5002; /* error */
Packit 1fb8d4
Packit 1fb8d4
				OptimizedMatches[j].MatchLength -= MatchDiff;
Packit 1fb8d4
				OptimizedMatches[j].MatchOffset += MatchDiff;
Packit 1fb8d4
				OptimizedMatches[j].ChunkOffset += MatchDiff;
Packit 1fb8d4
				PrevMatchEnd = OptimizedMatches[j].MatchLength + OptimizedMatches[j].MatchOffset;
Packit 1fb8d4
				TotalMatchLength += OptimizedMatches[j].MatchLength;
Packit 1fb8d4
				j++;
Packit 1fb8d4
			}
Packit 1fb8d4
		}
Packit 1fb8d4
		else
Packit 1fb8d4
		{
Packit 1fb8d4
			OriginalMatch = &OriginalMatches[i];
Packit 1fb8d4
			OptimizedMatch = &OptimizedMatches[j];
Packit 1fb8d4
			OptimizedMatch->MatchOffset = OriginalMatch->MatchOffset;
Packit 1fb8d4
			OptimizedMatch->ChunkOffset = OriginalMatch->ChunkOffset;
Packit 1fb8d4
			OptimizedMatch->MatchLength = OriginalMatch->MatchLength;
Packit 1fb8d4
			PrevMatchEnd = OptimizedMatches[j].MatchLength + OptimizedMatches[j].MatchOffset;
Packit 1fb8d4
			TotalMatchLength += OptimizedMatches[j].MatchLength;
Packit 1fb8d4
			j++;
Packit 1fb8d4
		}
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	OptimizedMatchCount = j;
Packit 1fb8d4
	xcrush->OptimizedMatchCount = OptimizedMatchCount;
Packit 1fb8d4
	return (int) TotalMatchLength;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
static int xcrush_generate_output(XCRUSH_CONTEXT* xcrush, BYTE* OutputBuffer, UINT32 OutputSize,
Packit 1fb8d4
                                  UINT32 HistoryOffset, UINT32* pDstSize)
Packit 1fb8d4
{
Packit 1fb8d4
	BYTE* Literals;
Packit 1fb8d4
	BYTE* OutputEnd;
Packit 1fb8d4
	UINT32 MatchIndex;
Packit 1fb8d4
	UINT32 MatchOffset;
Packit 1fb8d4
	UINT16 MatchLength;
Packit 1fb8d4
	UINT32 MatchCount;
Packit 1fb8d4
	UINT32 CurrentOffset;
Packit 1fb8d4
	UINT32 MatchOffsetDiff;
Packit 1fb8d4
	UINT32 HistoryOffsetDiff;
Packit 1fb8d4
	RDP61_MATCH_DETAILS* MatchDetails;
Packit 1fb8d4
	MatchCount = xcrush->OptimizedMatchCount;
Packit 1fb8d4
	OutputEnd = &OutputBuffer[OutputSize];
Packit 1fb8d4
Packit 1fb8d4
	if (&OutputBuffer[2] >= &OutputBuffer[OutputSize])
Packit 1fb8d4
		return -6001; /* error */
Packit 1fb8d4
Packit 1fb8d4
	*((UINT16*) OutputBuffer) = MatchCount;
Packit 1fb8d4
	MatchDetails = (RDP61_MATCH_DETAILS*) &OutputBuffer[2];
Packit 1fb8d4
	Literals = (BYTE*) &MatchDetails[MatchCount];
Packit 1fb8d4
Packit 1fb8d4
	if (Literals > OutputEnd)
Packit 1fb8d4
		return -6002; /* error */
Packit 1fb8d4
Packit 1fb8d4
	for (MatchIndex = 0; MatchIndex < MatchCount; MatchIndex++)
Packit 1fb8d4
	{
Packit 1fb8d4
		MatchDetails[MatchIndex].MatchLength = (UINT16)(xcrush->OptimizedMatches[MatchIndex].MatchLength);
Packit 1fb8d4
		MatchDetails[MatchIndex].MatchOutputOffset = (UINT16)(
Packit 1fb8d4
		            xcrush->OptimizedMatches[MatchIndex].MatchOffset - HistoryOffset);
Packit 1fb8d4
		MatchDetails[MatchIndex].MatchHistoryOffset = xcrush->OptimizedMatches[MatchIndex].ChunkOffset;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	CurrentOffset = HistoryOffset;
Packit 1fb8d4
Packit 1fb8d4
	for (MatchIndex = 0; MatchIndex < MatchCount; MatchIndex++)
Packit 1fb8d4
	{
Packit 1fb8d4
		MatchLength = (UINT16)(xcrush->OptimizedMatches[MatchIndex].MatchLength);
Packit 1fb8d4
		MatchOffset = xcrush->OptimizedMatches[MatchIndex].MatchOffset;
Packit 1fb8d4
Packit 1fb8d4
		if (MatchOffset <= CurrentOffset)
Packit 1fb8d4
		{
Packit 1fb8d4
			if (MatchOffset != CurrentOffset)
Packit 1fb8d4
				return -6003; /* error */
Packit 1fb8d4
Packit 1fb8d4
			CurrentOffset = MatchOffset + MatchLength;
Packit 1fb8d4
		}
Packit 1fb8d4
		else
Packit 1fb8d4
		{
Packit 1fb8d4
			MatchOffsetDiff = MatchOffset - CurrentOffset;
Packit 1fb8d4
Packit 1fb8d4
			if (Literals + MatchOffset - CurrentOffset >= OutputEnd)
Packit 1fb8d4
				return -6004; /* error */
Packit 1fb8d4
Packit 1fb8d4
			CopyMemory(Literals, &xcrush->HistoryBuffer[CurrentOffset], MatchOffsetDiff);
Packit 1fb8d4
Packit 1fb8d4
			if (Literals >= OutputEnd)
Packit 1fb8d4
				return -6005; /* error */
Packit 1fb8d4
Packit 1fb8d4
			Literals += MatchOffsetDiff;
Packit 1fb8d4
			CurrentOffset = MatchOffset + MatchLength;
Packit 1fb8d4
		}
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	HistoryOffsetDiff = xcrush->HistoryOffset - CurrentOffset;
Packit 1fb8d4
Packit 1fb8d4
	if (Literals + HistoryOffsetDiff >= OutputEnd)
Packit 1fb8d4
		return -6006; /* error */
Packit 1fb8d4
Packit 1fb8d4
	CopyMemory(Literals, &xcrush->HistoryBuffer[CurrentOffset], HistoryOffsetDiff);
Packit 1fb8d4
	*pDstSize = Literals + HistoryOffsetDiff - OutputBuffer;
Packit 1fb8d4
	return 1;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
static int xcrush_copy_bytes(BYTE* dst, BYTE* src, int num)
Packit 1fb8d4
{
Packit 1fb8d4
	int index;
Packit 1fb8d4
Packit 1fb8d4
	for (index = 0; index < num; index++)
Packit 1fb8d4
	{
Packit 1fb8d4
		dst[index] = src[index];
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	return num;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
static int xcrush_decompress_l1(XCRUSH_CONTEXT* xcrush, BYTE* pSrcData, UINT32 SrcSize,
Packit 1fb8d4
                                BYTE** ppDstData, UINT32* pDstSize, UINT32 flags)
Packit 1fb8d4
{
Packit 1fb8d4
	BYTE* pSrcEnd = NULL;
Packit 1fb8d4
	BYTE* Literals = NULL;
Packit 1fb8d4
	UINT16 MatchCount = 0;
Packit 1fb8d4
	UINT16 MatchIndex = 0;
Packit 1fb8d4
	BYTE* OutputPtr = NULL;
Packit 1fb8d4
	int OutputLength = 0;
Packit 1fb8d4
	UINT32 OutputOffset = 0;
Packit 1fb8d4
	BYTE* HistoryPtr = NULL;
Packit 1fb8d4
	BYTE* HistoryBuffer = NULL;
Packit 1fb8d4
	BYTE* HistoryBufferEnd = NULL;
Packit 1fb8d4
	UINT32 HistoryBufferSize = 0;
Packit 1fb8d4
	UINT16 MatchLength = 0;
Packit 1fb8d4
	UINT16 MatchOutputOffset = 0;
Packit 1fb8d4
	UINT32 MatchHistoryOffset = 0;
Packit 1fb8d4
	RDP61_MATCH_DETAILS* MatchDetails = NULL;
Packit 1fb8d4
Packit 1fb8d4
	if (SrcSize < 1)
Packit 1fb8d4
		return -1001;
Packit 1fb8d4
Packit 1fb8d4
	if (flags & L1_PACKET_AT_FRONT)
Packit 1fb8d4
		xcrush->HistoryOffset = 0;
Packit 1fb8d4
Packit 1fb8d4
	pSrcEnd = &pSrcData[SrcSize];
Packit 1fb8d4
	HistoryBuffer = xcrush->HistoryBuffer;
Packit 1fb8d4
	HistoryBufferSize = xcrush->HistoryBufferSize;
Packit 1fb8d4
	HistoryBufferEnd = &(HistoryBuffer[HistoryBufferSize]);
Packit 1fb8d4
	xcrush->HistoryPtr = HistoryPtr = &(HistoryBuffer[xcrush->HistoryOffset]);
Packit 1fb8d4
Packit 1fb8d4
	if (flags & L1_NO_COMPRESSION)
Packit 1fb8d4
	{
Packit 1fb8d4
		Literals = pSrcData;
Packit 1fb8d4
	}
Packit 1fb8d4
	else
Packit 1fb8d4
	{
Packit 1fb8d4
		if (!(flags & L1_COMPRESSED))
Packit 1fb8d4
			return -1002;
Packit 1fb8d4
Packit 1fb8d4
		if ((pSrcData + 2) > pSrcEnd)
Packit 1fb8d4
			return -1003;
Packit 1fb8d4
Packit 1fb8d4
		Data_Read_UINT16(pSrcData, MatchCount);
Packit 1fb8d4
		MatchDetails = (RDP61_MATCH_DETAILS*) &pSrcData[2];
Packit 1fb8d4
		Literals = (BYTE*) &MatchDetails[MatchCount];
Packit 1fb8d4
		OutputOffset = 0;
Packit 1fb8d4
Packit 1fb8d4
		if (Literals > pSrcEnd)
Packit 1fb8d4
			return -1004;
Packit 1fb8d4
Packit 1fb8d4
		for (MatchIndex = 0; MatchIndex < MatchCount; MatchIndex++)
Packit 1fb8d4
		{
Packit 1fb8d4
			Data_Read_UINT16(&MatchDetails[MatchIndex].MatchLength, MatchLength);
Packit 1fb8d4
			Data_Read_UINT16(&MatchDetails[MatchIndex].MatchOutputOffset, MatchOutputOffset);
Packit 1fb8d4
			Data_Read_UINT32(&MatchDetails[MatchIndex].MatchHistoryOffset, MatchHistoryOffset);
Packit 1fb8d4
Packit 1fb8d4
			if (MatchOutputOffset < OutputOffset)
Packit 1fb8d4
				return -1005;
Packit 1fb8d4
Packit 1fb8d4
			if (MatchLength > HistoryBufferSize)
Packit 1fb8d4
				return -1006;
Packit 1fb8d4
Packit 1fb8d4
			if (MatchHistoryOffset > HistoryBufferSize)
Packit 1fb8d4
				return -1007;
Packit 1fb8d4
Packit 1fb8d4
			OutputLength = MatchOutputOffset - OutputOffset;
Packit 1fb8d4
Packit 1fb8d4
			if ((MatchOutputOffset - OutputOffset) > HistoryBufferSize)
Packit 1fb8d4
				return -1008;
Packit 1fb8d4
Packit 1fb8d4
			if (OutputLength > 0)
Packit 1fb8d4
			{
Packit 1fb8d4
				if ((&HistoryPtr[OutputLength] >= HistoryBufferEnd) || (Literals >= pSrcEnd) ||
Packit 1fb8d4
				    (&Literals[OutputLength] > pSrcEnd))
Packit 1fb8d4
					return -1009;
Packit 1fb8d4
Packit 1fb8d4
				xcrush_copy_bytes(HistoryPtr, Literals, OutputLength);
Packit 1fb8d4
				HistoryPtr += OutputLength;
Packit 1fb8d4
				Literals += OutputLength;
Packit 1fb8d4
				OutputOffset += OutputLength;
Packit 1fb8d4
Packit 1fb8d4
				if (Literals > pSrcEnd)
Packit 1fb8d4
					return -1010;
Packit 1fb8d4
			}
Packit 1fb8d4
Packit 1fb8d4
			OutputPtr = &xcrush->HistoryBuffer[MatchHistoryOffset];
Packit 1fb8d4
Packit 1fb8d4
			if ((&HistoryPtr[MatchLength] >= HistoryBufferEnd) || (&OutputPtr[MatchLength] >= HistoryBufferEnd))
Packit 1fb8d4
				return -1011;
Packit 1fb8d4
Packit 1fb8d4
			xcrush_copy_bytes(HistoryPtr, OutputPtr, MatchLength);
Packit 1fb8d4
			OutputOffset += MatchLength;
Packit 1fb8d4
			HistoryPtr += MatchLength;
Packit 1fb8d4
		}
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	if (Literals < pSrcEnd)
Packit 1fb8d4
	{
Packit 1fb8d4
		OutputLength = pSrcEnd - Literals;
Packit 1fb8d4
Packit 1fb8d4
		if ((&HistoryPtr[OutputLength] >= HistoryBufferEnd) || (&Literals[OutputLength] > pSrcEnd))
Packit 1fb8d4
			return -1012;
Packit 1fb8d4
Packit 1fb8d4
		xcrush_copy_bytes(HistoryPtr, Literals, OutputLength);
Packit 1fb8d4
		HistoryPtr += OutputLength;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	xcrush->HistoryOffset = HistoryPtr - HistoryBuffer;
Packit 1fb8d4
	*pDstSize = HistoryPtr - xcrush->HistoryPtr;
Packit 1fb8d4
	*ppDstData = xcrush->HistoryPtr;
Packit 1fb8d4
	return 1;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
int xcrush_decompress(XCRUSH_CONTEXT* xcrush, BYTE* pSrcData, UINT32 SrcSize, BYTE** ppDstData,
Packit 1fb8d4
                      UINT32* pDstSize, UINT32 flags)
Packit 1fb8d4
{
Packit 1fb8d4
	int status = 0;
Packit 1fb8d4
	UINT32 DstSize = 0;
Packit 1fb8d4
	BYTE* pDstData = NULL;
Packit 1fb8d4
	BYTE Level1ComprFlags;
Packit 1fb8d4
	BYTE Level2ComprFlags;
Packit 1fb8d4
Packit 1fb8d4
	if (SrcSize < 2)
Packit 1fb8d4
		return -1;
Packit 1fb8d4
Packit 1fb8d4
	Level1ComprFlags = pSrcData[0];
Packit 1fb8d4
	Level2ComprFlags = pSrcData[1];
Packit 1fb8d4
	pSrcData += 2;
Packit 1fb8d4
	SrcSize -= 2;
Packit 1fb8d4
Packit 1fb8d4
	if (flags & PACKET_FLUSHED)
Packit 1fb8d4
	{
Packit 1fb8d4
		ZeroMemory(xcrush->HistoryBuffer, xcrush->HistoryBufferSize);
Packit 1fb8d4
		xcrush->HistoryOffset = 0;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	if (!(Level2ComprFlags & PACKET_COMPRESSED))
Packit 1fb8d4
	{
Packit 1fb8d4
		pDstData = pSrcData;
Packit 1fb8d4
		DstSize = SrcSize;
Packit 1fb8d4
		status = xcrush_decompress_l1(xcrush, pDstData, DstSize, ppDstData, pDstSize, Level1ComprFlags);
Packit 1fb8d4
		return status;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	status = mppc_decompress(xcrush->mppc, pSrcData, SrcSize, &pDstData, &DstSize, Level2ComprFlags);
Packit 1fb8d4
Packit 1fb8d4
	if (status < 0)
Packit 1fb8d4
		return status;
Packit 1fb8d4
Packit 1fb8d4
	status = xcrush_decompress_l1(xcrush, pDstData, DstSize, ppDstData, pDstSize, Level1ComprFlags);
Packit 1fb8d4
	return status;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
static int xcrush_compress_l1(XCRUSH_CONTEXT* xcrush, BYTE* pSrcData, UINT32 SrcSize,
Packit 1fb8d4
                              BYTE** ppDstData, UINT32* pDstSize, UINT32* pFlags)
Packit 1fb8d4
{
Packit 1fb8d4
	int status = 0;
Packit 1fb8d4
	UINT32 Flags = 0;
Packit 1fb8d4
	UINT32 HistoryOffset = 0;
Packit 1fb8d4
	BYTE* HistoryPtr = NULL;
Packit 1fb8d4
	BYTE* HistoryBuffer = NULL;
Packit 1fb8d4
	UINT32 SignatureIndex = 0;
Packit 1fb8d4
Packit 1fb8d4
	if (xcrush->HistoryOffset + SrcSize + 8 > xcrush->HistoryBufferSize)
Packit 1fb8d4
	{
Packit 1fb8d4
		xcrush->HistoryOffset = 0;
Packit 1fb8d4
		Flags |= L1_PACKET_AT_FRONT;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	HistoryOffset = xcrush->HistoryOffset;
Packit 1fb8d4
	HistoryBuffer = xcrush->HistoryBuffer;
Packit 1fb8d4
	HistoryPtr = &HistoryBuffer[HistoryOffset];
Packit 1fb8d4
	MoveMemory(HistoryPtr, pSrcData, SrcSize);
Packit 1fb8d4
	xcrush->HistoryOffset += SrcSize;
Packit 1fb8d4
Packit 1fb8d4
	if (SrcSize > 50)
Packit 1fb8d4
	{
Packit 1fb8d4
		SignatureIndex = xcrush_compute_signatures(xcrush, pSrcData, SrcSize);
Packit 1fb8d4
Packit 1fb8d4
		if (SignatureIndex)
Packit 1fb8d4
		{
Packit 1fb8d4
			status = xcrush_find_all_matches(xcrush,
Packit 1fb8d4
			                                 SignatureIndex, HistoryOffset, 0, SrcSize);
Packit 1fb8d4
Packit 1fb8d4
			if (status < 0)
Packit 1fb8d4
				return status;
Packit 1fb8d4
Packit 1fb8d4
			xcrush->OriginalMatchCount = (UINT32) status;
Packit 1fb8d4
			xcrush->OptimizedMatchCount = 0;
Packit 1fb8d4
Packit 1fb8d4
			if (xcrush->OriginalMatchCount)
Packit 1fb8d4
			{
Packit 1fb8d4
				status = xcrush_optimize_matches(xcrush);
Packit 1fb8d4
Packit 1fb8d4
				if (status < 0)
Packit 1fb8d4
					return status;
Packit 1fb8d4
			}
Packit 1fb8d4
Packit 1fb8d4
			if (xcrush->OptimizedMatchCount)
Packit 1fb8d4
			{
Packit 1fb8d4
				status = xcrush_generate_output(xcrush, *ppDstData, SrcSize, HistoryOffset, pDstSize);
Packit 1fb8d4
Packit 1fb8d4
				if (status < 0)
Packit 1fb8d4
					return status;
Packit 1fb8d4
Packit 1fb8d4
				if (status > 0)
Packit 1fb8d4
					Flags |= L1_COMPRESSED;
Packit 1fb8d4
			}
Packit 1fb8d4
		}
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	if (!(Flags & L1_COMPRESSED))
Packit 1fb8d4
	{
Packit 1fb8d4
		Flags |= L1_NO_COMPRESSION;
Packit 1fb8d4
		*pDstSize = SrcSize;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	*pFlags = Flags;
Packit 1fb8d4
	return 1;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
int xcrush_compress(XCRUSH_CONTEXT* xcrush, BYTE* pSrcData, UINT32 SrcSize, BYTE** ppDstData,
Packit 1fb8d4
                    UINT32* pDstSize, UINT32* pFlags)
Packit 1fb8d4
{
Packit 1fb8d4
	int status = 0;
Packit 1fb8d4
	UINT32 DstSize = 0;
Packit 1fb8d4
	BYTE* pDstData = NULL;
Packit 1fb8d4
	BYTE* CompressedData = NULL;
Packit 1fb8d4
	UINT32 CompressedDataSize = 0;
Packit 1fb8d4
	BYTE* OriginalData = NULL;
Packit 1fb8d4
	UINT32 OriginalDataSize = 0;
Packit 1fb8d4
	UINT32 Level1ComprFlags = 0;
Packit 1fb8d4
	UINT32 Level2ComprFlags = 0;
Packit 1fb8d4
	UINT32 CompressionLevel = 3;
Packit 1fb8d4
Packit 1fb8d4
	if (SrcSize > 16384)
Packit 1fb8d4
		return -1001;
Packit 1fb8d4
Packit 1fb8d4
	if ((SrcSize + 2) > *pDstSize)
Packit 1fb8d4
		return -1002;
Packit 1fb8d4
Packit 1fb8d4
	OriginalData = *ppDstData;
Packit 1fb8d4
	OriginalDataSize = SrcSize;
Packit 1fb8d4
	pDstData = xcrush->BlockBuffer;
Packit 1fb8d4
	CompressedDataSize = SrcSize;
Packit 1fb8d4
	status = xcrush_compress_l1(xcrush, pSrcData, SrcSize, &pDstData, &CompressedDataSize,
Packit 1fb8d4
	                            &Level1ComprFlags);
Packit 1fb8d4
Packit 1fb8d4
	if (status < 0)
Packit 1fb8d4
		return status;
Packit 1fb8d4
Packit 1fb8d4
	if (Level1ComprFlags & L1_COMPRESSED)
Packit 1fb8d4
	{
Packit 1fb8d4
		CompressedData = pDstData;
Packit 1fb8d4
Packit 1fb8d4
		if (CompressedDataSize > SrcSize)
Packit 1fb8d4
			return -1003;
Packit 1fb8d4
	}
Packit 1fb8d4
	else
Packit 1fb8d4
	{
Packit 1fb8d4
		CompressedData = pSrcData;
Packit 1fb8d4
Packit 1fb8d4
		if (CompressedDataSize != SrcSize)
Packit 1fb8d4
			return -1004;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	status = 0;
Packit 1fb8d4
	pDstData = &OriginalData[2];
Packit 1fb8d4
	DstSize = OriginalDataSize - 2;
Packit 1fb8d4
Packit 1fb8d4
	if (CompressedDataSize > 50)
Packit 1fb8d4
	{
Packit 1fb8d4
		status = mppc_compress(xcrush->mppc, CompressedData, CompressedDataSize, &pDstData, &DstSize,
Packit 1fb8d4
		                       &Level2ComprFlags);
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	if (status < 0)
Packit 1fb8d4
		return status;
Packit 1fb8d4
Packit 1fb8d4
	if (!status || (Level2ComprFlags & PACKET_FLUSHED))
Packit 1fb8d4
	{
Packit 1fb8d4
		if (CompressedDataSize > DstSize)
Packit 1fb8d4
		{
Packit 1fb8d4
			xcrush_context_reset(xcrush, TRUE);
Packit 1fb8d4
			*ppDstData = pSrcData;
Packit 1fb8d4
			*pDstSize = SrcSize;
Packit 1fb8d4
			*pFlags = 0;
Packit 1fb8d4
			return 1;
Packit 1fb8d4
		}
Packit 1fb8d4
Packit 1fb8d4
		DstSize = CompressedDataSize;
Packit 1fb8d4
		CopyMemory(&OriginalData[2], CompressedData, CompressedDataSize);
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	if (Level2ComprFlags & PACKET_COMPRESSED)
Packit 1fb8d4
	{
Packit 1fb8d4
		Level2ComprFlags |= xcrush->CompressionFlags;
Packit 1fb8d4
		xcrush->CompressionFlags = 0;
Packit 1fb8d4
	}
Packit 1fb8d4
	else if (Level2ComprFlags & PACKET_FLUSHED)
Packit 1fb8d4
	{
Packit 1fb8d4
		xcrush->CompressionFlags = PACKET_FLUSHED;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	Level1ComprFlags |= L1_INNER_COMPRESSION;
Packit 1fb8d4
	OriginalData[0] = (BYTE) Level1ComprFlags;
Packit 1fb8d4
	OriginalData[1] = (BYTE) Level2ComprFlags;
Packit 1fb8d4
#if DEBUG_XCRUSH
Packit 1fb8d4
	WLog_DBG(TAG, "XCrushCompress: Level1ComprFlags: %s Level2ComprFlags: %s",
Packit 1fb8d4
	         xcrush_get_level_1_compression_flags_string(Level1ComprFlags),
Packit 1fb8d4
	         xcrush_get_level_2_compression_flags_string(Level2ComprFlags));
Packit 1fb8d4
#endif
Packit 1fb8d4
Packit 1fb8d4
	if (*pDstSize < (DstSize + 2))
Packit 1fb8d4
		return -1006;
Packit 1fb8d4
Packit 1fb8d4
	*pDstSize = DstSize + 2;
Packit 1fb8d4
	*pFlags = PACKET_COMPRESSED | CompressionLevel;
Packit 1fb8d4
	return 1;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
void xcrush_context_reset(XCRUSH_CONTEXT* xcrush, BOOL flush)
Packit 1fb8d4
{
Packit 1fb8d4
	xcrush->SignatureIndex = 0;
Packit 1fb8d4
	xcrush->SignatureCount = 1000;
Packit 1fb8d4
	ZeroMemory(&(xcrush->Signatures), sizeof(XCRUSH_SIGNATURE) * xcrush->SignatureCount);
Packit 1fb8d4
	xcrush->CompressionFlags = 0;
Packit 1fb8d4
	xcrush->ChunkHead = xcrush->ChunkTail = 1;
Packit 1fb8d4
	ZeroMemory(&(xcrush->Chunks), sizeof(xcrush->Chunks));
Packit 1fb8d4
	ZeroMemory(&(xcrush->NextChunks), sizeof(xcrush->NextChunks));
Packit 1fb8d4
	ZeroMemory(&(xcrush->OriginalMatches), sizeof(xcrush->OriginalMatches));
Packit 1fb8d4
	ZeroMemory(&(xcrush->OptimizedMatches), sizeof(xcrush->OptimizedMatches));
Packit 1fb8d4
Packit 1fb8d4
	if (flush)
Packit 1fb8d4
		xcrush->HistoryOffset = xcrush->HistoryBufferSize + 1;
Packit 1fb8d4
	else
Packit 1fb8d4
		xcrush->HistoryOffset = 0;
Packit 1fb8d4
Packit 1fb8d4
	mppc_context_reset(xcrush->mppc, flush);
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
XCRUSH_CONTEXT* xcrush_context_new(BOOL Compressor)
Packit 1fb8d4
{
Packit 1fb8d4
	XCRUSH_CONTEXT* xcrush;
Packit 1fb8d4
	xcrush = (XCRUSH_CONTEXT*) calloc(1, sizeof(XCRUSH_CONTEXT));
Packit 1fb8d4
Packit 1fb8d4
	if (xcrush)
Packit 1fb8d4
	{
Packit 1fb8d4
		xcrush->Compressor = Compressor;
Packit 1fb8d4
		xcrush->mppc = mppc_context_new(1, Compressor);
Packit 1fb8d4
		xcrush->HistoryOffset = 0;
Packit 1fb8d4
		xcrush->HistoryBufferSize = 2000000;
Packit 1fb8d4
		xcrush_context_reset(xcrush, FALSE);
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	return xcrush;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
void xcrush_context_free(XCRUSH_CONTEXT* xcrush)
Packit 1fb8d4
{
Packit 1fb8d4
	if (xcrush)
Packit 1fb8d4
	{
Packit 1fb8d4
		mppc_context_free(xcrush->mppc);
Packit 1fb8d4
		free(xcrush);
Packit 1fb8d4
	}
Packit 1fb8d4
}
Packit 1fb8d4