Blame libfreerdp/codec/zgfx.c

Packit 1fb8d4
/**
Packit 1fb8d4
 * FreeRDP: A Remote Desktop Protocol Implementation
Packit 1fb8d4
 * ZGFX (RDP8) 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/zgfx.h>
Packit 1fb8d4
Packit 1fb8d4
#define TAG FREERDP_TAG("codec")
Packit 1fb8d4
Packit 1fb8d4
/**
Packit 1fb8d4
 * RDP8 Compressor Limits:
Packit 1fb8d4
 *
Packit 1fb8d4
 * Maximum number of uncompressed bytes in a single segment: 65535
Packit 1fb8d4
 * Maximum match distance / minimum history size: 2500000 bytes.
Packit 1fb8d4
 * Maximum number of segments: 65535
Packit 1fb8d4
 * Maximum expansion of a segment (when compressed size exceeds uncompressed): 1000 bytes
Packit 1fb8d4
 * Minimum match length: 3 bytes
Packit 1fb8d4
 */
Packit 1fb8d4
Packit 1fb8d4
struct _ZGFX_TOKEN
Packit 1fb8d4
{
Packit 1fb8d4
	UINT32 prefixLength;
Packit 1fb8d4
	UINT32 prefixCode;
Packit 1fb8d4
	UINT32 valueBits;
Packit 1fb8d4
	UINT32 tokenType;
Packit 1fb8d4
	UINT32 valueBase;
Packit 1fb8d4
};
Packit 1fb8d4
typedef struct _ZGFX_TOKEN ZGFX_TOKEN;
Packit 1fb8d4
Packit 1fb8d4
struct _ZGFX_CONTEXT
Packit 1fb8d4
{
Packit 1fb8d4
	BOOL Compressor;
Packit 1fb8d4
Packit 1fb8d4
	const BYTE* pbInputCurrent;
Packit 1fb8d4
	const BYTE* pbInputEnd;
Packit 1fb8d4
Packit 1fb8d4
	UINT32 bits;
Packit 1fb8d4
	UINT32 cBitsRemaining;
Packit 1fb8d4
	UINT32 BitsCurrent;
Packit 1fb8d4
	UINT32 cBitsCurrent;
Packit 1fb8d4
Packit 1fb8d4
	BYTE OutputBuffer[65536];
Packit 1fb8d4
	UINT32 OutputCount;
Packit 1fb8d4
Packit 1fb8d4
	BYTE HistoryBuffer[2500000];
Packit 1fb8d4
	UINT32 HistoryIndex;
Packit 1fb8d4
	UINT32 HistoryBufferSize;
Packit 1fb8d4
};
Packit 1fb8d4
Packit 1fb8d4
static const ZGFX_TOKEN ZGFX_TOKEN_TABLE[] =
Packit 1fb8d4
{
Packit 1fb8d4
	// len code vbits type  vbase
Packit 1fb8d4
	{  1,    0,   8,   0,           0 },    // 0
Packit 1fb8d4
	{  5,   17,   5,   1,           0 },    // 10001
Packit 1fb8d4
	{  5,   18,   7,   1,          32 },    // 10010
Packit 1fb8d4
	{  5,   19,   9,   1,         160 },    // 10011
Packit 1fb8d4
	{  5,   20,  10,   1,         672 },    // 10100
Packit 1fb8d4
	{  5,   21,  12,   1,        1696 },    // 10101
Packit 1fb8d4
	{  5,   24,   0,   0,  0x00       },    // 11000
Packit 1fb8d4
	{  5,   25,   0,   0,  0x01       },    // 11001
Packit 1fb8d4
	{  6,   44,  14,   1,        5792 },    // 101100
Packit 1fb8d4
	{  6,   45,  15,   1,       22176 },    // 101101
Packit 1fb8d4
	{  6,   52,   0,   0,  0x02       },    // 110100
Packit 1fb8d4
	{  6,   53,   0,   0,  0x03       },    // 110101
Packit 1fb8d4
	{  6,   54,   0,   0,  0xFF       },    // 110110
Packit 1fb8d4
	{  7,   92,  18,   1,       54944 },    // 1011100
Packit 1fb8d4
	{  7,   93,  20,   1,      317088 },    // 1011101
Packit 1fb8d4
	{  7,  110,   0,   0,  0x04       },    // 1101110
Packit 1fb8d4
	{  7,  111,   0,   0,  0x05       },    // 1101111
Packit 1fb8d4
	{  7,  112,   0,   0,  0x06       },    // 1110000
Packit 1fb8d4
	{  7,  113,   0,   0,  0x07       },    // 1110001
Packit 1fb8d4
	{  7,  114,   0,   0,  0x08       },    // 1110010
Packit 1fb8d4
	{  7,  115,   0,   0,  0x09       },    // 1110011
Packit 1fb8d4
	{  7,  116,   0,   0,  0x0A       },    // 1110100
Packit 1fb8d4
	{  7,  117,   0,   0,  0x0B       },    // 1110101
Packit 1fb8d4
	{  7,  118,   0,   0,  0x3A       },    // 1110110
Packit 1fb8d4
	{  7,  119,   0,   0,  0x3B       },    // 1110111
Packit 1fb8d4
	{  7,  120,   0,   0,  0x3C       },    // 1111000
Packit 1fb8d4
	{  7,  121,   0,   0,  0x3D       },    // 1111001
Packit 1fb8d4
	{  7,  122,   0,   0,  0x3E       },    // 1111010
Packit 1fb8d4
	{  7,  123,   0,   0,  0x3F       },    // 1111011
Packit 1fb8d4
	{  7,  124,   0,   0,  0x40       },    // 1111100
Packit 1fb8d4
	{  7,  125,   0,   0,  0x80       },    // 1111101
Packit 1fb8d4
	{  8,  188,  20,   1,     1365664 },    // 10111100
Packit 1fb8d4
	{  8,  189,  21,   1,     2414240 },    // 10111101
Packit 1fb8d4
	{  8,  252,   0,   0,  0x0C       },    // 11111100
Packit 1fb8d4
	{  8,  253,   0,   0,  0x38       },    // 11111101
Packit 1fb8d4
	{  8,  254,   0,   0,  0x39       },    // 11111110
Packit 1fb8d4
	{  8,  255,   0,   0,  0x66       },    // 11111111
Packit 1fb8d4
	{  9,  380,  22,   1,     4511392 },    // 101111100
Packit 1fb8d4
	{  9,  381,  23,   1,     8705696 },    // 101111101
Packit 1fb8d4
	{  9,  382,  24,   1,    17094304 },    // 101111110
Packit 1fb8d4
	{ 0 }
Packit 1fb8d4
};
Packit 1fb8d4
Packit 1fb8d4
static INLINE BOOL zgfx_GetBits(ZGFX_CONTEXT* _zgfx, UINT32 _nbits)
Packit 1fb8d4
{
Packit 1fb8d4
	if (!_zgfx)
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	while (_zgfx->cBitsCurrent < _nbits)
Packit 1fb8d4
	{
Packit 1fb8d4
		_zgfx->BitsCurrent <<= 8;
Packit 1fb8d4
Packit 1fb8d4
		if (_zgfx->pbInputCurrent < _zgfx->pbInputEnd)
Packit 1fb8d4
			_zgfx->BitsCurrent += *(_zgfx->pbInputCurrent)++;
Packit 1fb8d4
Packit 1fb8d4
		_zgfx->cBitsCurrent += 8;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	_zgfx->cBitsRemaining -= _nbits;
Packit 1fb8d4
	_zgfx->cBitsCurrent -= _nbits;
Packit 1fb8d4
	_zgfx->bits = _zgfx->BitsCurrent >> _zgfx->cBitsCurrent;
Packit 1fb8d4
	_zgfx->BitsCurrent &= ((1 << _zgfx->cBitsCurrent) - 1);
Packit 1fb8d4
	return TRUE;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
static void zgfx_history_buffer_ring_write(ZGFX_CONTEXT* zgfx, const BYTE* src, size_t count)
Packit 1fb8d4
{
Packit 1fb8d4
	UINT32 front;
Packit 1fb8d4
Packit 1fb8d4
	if (count <= 0)
Packit 1fb8d4
		return;
Packit 1fb8d4
Packit 1fb8d4
	if (count > zgfx->HistoryBufferSize)
Packit 1fb8d4
	{
Packit 1fb8d4
		const size_t residue = count - zgfx->HistoryBufferSize;
Packit 1fb8d4
		count = zgfx->HistoryBufferSize;
Packit 1fb8d4
		src += residue;
Packit 1fb8d4
		zgfx->HistoryIndex = (zgfx->HistoryIndex + residue) % zgfx->HistoryBufferSize;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	if (zgfx->HistoryIndex + count <= zgfx->HistoryBufferSize)
Packit 1fb8d4
	{
Packit 1fb8d4
		CopyMemory(&(zgfx->HistoryBuffer[zgfx->HistoryIndex]), src, count);
Packit 1fb8d4
Packit 1fb8d4
		if ((zgfx->HistoryIndex += count) == zgfx->HistoryBufferSize)
Packit 1fb8d4
			zgfx->HistoryIndex = 0;
Packit 1fb8d4
	}
Packit 1fb8d4
	else
Packit 1fb8d4
	{
Packit 1fb8d4
		front = zgfx->HistoryBufferSize - zgfx->HistoryIndex;
Packit 1fb8d4
		CopyMemory(&(zgfx->HistoryBuffer[zgfx->HistoryIndex]), src, front);
Packit 1fb8d4
		CopyMemory(zgfx->HistoryBuffer, &src[front], count - front);
Packit 1fb8d4
		zgfx->HistoryIndex = count - front;
Packit 1fb8d4
	}
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
static void zgfx_history_buffer_ring_read(ZGFX_CONTEXT* zgfx, int offset, BYTE* dst, UINT32 count)
Packit 1fb8d4
{
Packit 1fb8d4
	UINT32 front;
Packit 1fb8d4
	UINT32 index;
Packit 1fb8d4
	UINT32 bytes;
Packit 1fb8d4
	UINT32 valid;
Packit 1fb8d4
	UINT32 bytesLeft;
Packit 1fb8d4
	BYTE* dptr = dst;
Packit 1fb8d4
	BYTE* origDst = dst;
Packit 1fb8d4
Packit 1fb8d4
	if (count <= 0)
Packit 1fb8d4
		return;
Packit 1fb8d4
Packit 1fb8d4
	bytesLeft = count;
Packit 1fb8d4
	index = (zgfx->HistoryIndex + zgfx->HistoryBufferSize - offset) % zgfx->HistoryBufferSize;
Packit 1fb8d4
	bytes = MIN(bytesLeft, offset);
Packit 1fb8d4
Packit 1fb8d4
	if ((index + bytes) <= zgfx->HistoryBufferSize)
Packit 1fb8d4
	{
Packit 1fb8d4
		CopyMemory(dptr, &(zgfx->HistoryBuffer[index]), bytes);
Packit 1fb8d4
	}
Packit 1fb8d4
	else
Packit 1fb8d4
	{
Packit 1fb8d4
		front = zgfx->HistoryBufferSize - index;
Packit 1fb8d4
		CopyMemory(dptr, &(zgfx->HistoryBuffer[index]), front);
Packit 1fb8d4
		CopyMemory(&dptr[front], zgfx->HistoryBuffer, bytes - front);
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	if ((bytesLeft -= bytes) == 0)
Packit 1fb8d4
		return;
Packit 1fb8d4
Packit 1fb8d4
	dptr += bytes;
Packit 1fb8d4
	valid = bytes;
Packit 1fb8d4
Packit 1fb8d4
	do
Packit 1fb8d4
	{
Packit 1fb8d4
		bytes = valid;
Packit 1fb8d4
Packit 1fb8d4
		if (bytes > bytesLeft)
Packit 1fb8d4
			bytes = bytesLeft;
Packit 1fb8d4
Packit 1fb8d4
		CopyMemory(dptr, origDst, bytes);
Packit 1fb8d4
		dptr += bytes;
Packit 1fb8d4
		valid <<= 1;
Packit 1fb8d4
	}
Packit 1fb8d4
	while ((bytesLeft -= bytes) > 0);
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
static BOOL zgfx_decompress_segment(ZGFX_CONTEXT* zgfx, wStream* stream, size_t segmentSize)
Packit 1fb8d4
{
Packit 1fb8d4
	BYTE c;
Packit 1fb8d4
	BYTE flags;
Packit 1fb8d4
	UINT32 extra = 0;
Packit 1fb8d4
	int opIndex;
Packit 1fb8d4
	int haveBits;
Packit 1fb8d4
	int inPrefix;
Packit 1fb8d4
	UINT32 count;
Packit 1fb8d4
	UINT32 distance;
Packit 1fb8d4
	BYTE* pbSegment;
Packit 1fb8d4
	size_t cbSegment;
Packit 1fb8d4
Packit 1fb8d4
	if (!zgfx || !stream)
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	cbSegment = segmentSize - 1;
Packit 1fb8d4
Packit 1fb8d4
	if ((Stream_GetRemainingLength(stream) < segmentSize) || (segmentSize < 1) ||
Packit 1fb8d4
	    (segmentSize > UINT32_MAX))
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	Stream_Read_UINT8(stream, flags); /* header (1 byte) */
Packit 1fb8d4
	zgfx->OutputCount = 0;
Packit 1fb8d4
	pbSegment = Stream_Pointer(stream);
Packit 1fb8d4
	Stream_Seek(stream, cbSegment);
Packit 1fb8d4
Packit 1fb8d4
	if (!(flags & PACKET_COMPRESSED))
Packit 1fb8d4
	{
Packit 1fb8d4
		zgfx_history_buffer_ring_write(zgfx, pbSegment, cbSegment);
Packit 1fb8d4
Packit 1fb8d4
		if (cbSegment > sizeof(zgfx->OutputBuffer))
Packit 1fb8d4
			return FALSE;
Packit 1fb8d4
Packit 1fb8d4
		CopyMemory(zgfx->OutputBuffer, pbSegment, cbSegment);
Packit 1fb8d4
		zgfx->OutputCount = cbSegment;
Packit 1fb8d4
		return TRUE;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	zgfx->pbInputCurrent = pbSegment;
Packit 1fb8d4
	zgfx->pbInputEnd = &pbSegment[cbSegment - 1];
Packit 1fb8d4
	/* NumberOfBitsToDecode = ((NumberOfBytesToDecode - 1) * 8) - ValueOfLastByte */
Packit 1fb8d4
	zgfx->cBitsRemaining = 8 * (cbSegment - 1) - *zgfx->pbInputEnd;
Packit 1fb8d4
	zgfx->cBitsCurrent = 0;
Packit 1fb8d4
	zgfx->BitsCurrent = 0;
Packit 1fb8d4
Packit 1fb8d4
	while (zgfx->cBitsRemaining)
Packit 1fb8d4
	{
Packit 1fb8d4
		haveBits = 0;
Packit 1fb8d4
		inPrefix = 0;
Packit 1fb8d4
Packit 1fb8d4
		for (opIndex = 0; ZGFX_TOKEN_TABLE[opIndex].prefixLength != 0; opIndex++)
Packit 1fb8d4
		{
Packit 1fb8d4
			while (haveBits < ZGFX_TOKEN_TABLE[opIndex].prefixLength)
Packit 1fb8d4
			{
Packit 1fb8d4
				zgfx_GetBits(zgfx, 1);
Packit 1fb8d4
				inPrefix = (inPrefix << 1) + zgfx->bits;
Packit 1fb8d4
				haveBits++;
Packit 1fb8d4
			}
Packit 1fb8d4
Packit 1fb8d4
			if (inPrefix == ZGFX_TOKEN_TABLE[opIndex].prefixCode)
Packit 1fb8d4
			{
Packit 1fb8d4
				if (ZGFX_TOKEN_TABLE[opIndex].tokenType == 0)
Packit 1fb8d4
				{
Packit 1fb8d4
					/* Literal */
Packit 1fb8d4
					zgfx_GetBits(zgfx, ZGFX_TOKEN_TABLE[opIndex].valueBits);
Packit 1fb8d4
					c = (BYTE)(ZGFX_TOKEN_TABLE[opIndex].valueBase + zgfx->bits);
Packit 1fb8d4
					zgfx->HistoryBuffer[zgfx->HistoryIndex] = c;
Packit 1fb8d4
Packit 1fb8d4
					if (++zgfx->HistoryIndex == zgfx->HistoryBufferSize)
Packit 1fb8d4
						zgfx->HistoryIndex = 0;
Packit 1fb8d4
Packit 1fb8d4
					if (zgfx->OutputCount >= sizeof(zgfx->OutputBuffer))
Packit 1fb8d4
						return FALSE;
Packit 1fb8d4
Packit 1fb8d4
					zgfx->OutputBuffer[zgfx->OutputCount++] = c;
Packit 1fb8d4
				}
Packit 1fb8d4
				else
Packit 1fb8d4
				{
Packit 1fb8d4
					zgfx_GetBits(zgfx, ZGFX_TOKEN_TABLE[opIndex].valueBits);
Packit 1fb8d4
					distance = ZGFX_TOKEN_TABLE[opIndex].valueBase + zgfx->bits;
Packit 1fb8d4
Packit 1fb8d4
					if (distance != 0)
Packit 1fb8d4
					{
Packit 1fb8d4
						/* Match */
Packit 1fb8d4
						zgfx_GetBits(zgfx, 1);
Packit 1fb8d4
Packit 1fb8d4
						if (zgfx->bits == 0)
Packit 1fb8d4
						{
Packit 1fb8d4
							count = 3;
Packit 1fb8d4
						}
Packit 1fb8d4
						else
Packit 1fb8d4
						{
Packit 1fb8d4
							count = 4;
Packit 1fb8d4
							extra = 2;
Packit 1fb8d4
							zgfx_GetBits(zgfx, 1);
Packit 1fb8d4
Packit 1fb8d4
							while (zgfx->bits == 1)
Packit 1fb8d4
							{
Packit 1fb8d4
								count *= 2;
Packit 1fb8d4
								extra++;
Packit 1fb8d4
								zgfx_GetBits(zgfx, 1);
Packit 1fb8d4
							}
Packit 1fb8d4
Packit 1fb8d4
							zgfx_GetBits(zgfx, extra);
Packit 1fb8d4
							count += zgfx->bits;
Packit 1fb8d4
						}
Packit 1fb8d4
Packit 1fb8d4
						if (count > sizeof(zgfx->OutputBuffer) - zgfx->OutputCount)
Packit 1fb8d4
							return FALSE;
Packit 1fb8d4
Packit 1fb8d4
						zgfx_history_buffer_ring_read(zgfx, distance, &(zgfx->OutputBuffer[zgfx->OutputCount]), count);
Packit 1fb8d4
						zgfx_history_buffer_ring_write(zgfx, &(zgfx->OutputBuffer[zgfx->OutputCount]), count);
Packit 1fb8d4
						zgfx->OutputCount += count;
Packit 1fb8d4
					}
Packit 1fb8d4
					else
Packit 1fb8d4
					{
Packit 1fb8d4
						/* Unencoded */
Packit 1fb8d4
						zgfx_GetBits(zgfx, 15);
Packit 1fb8d4
						count = zgfx->bits;
Packit 1fb8d4
						zgfx->cBitsRemaining -= zgfx->cBitsCurrent;
Packit 1fb8d4
						zgfx->cBitsCurrent = 0;
Packit 1fb8d4
						zgfx->BitsCurrent = 0;
Packit 1fb8d4
Packit 1fb8d4
						if (count > sizeof(zgfx->OutputBuffer) - zgfx->OutputCount)
Packit 1fb8d4
							return FALSE;
Packit 1fb8d4
Packit 1fb8d4
						CopyMemory(&(zgfx->OutputBuffer[zgfx->OutputCount]), zgfx->pbInputCurrent, count);
Packit 1fb8d4
						zgfx_history_buffer_ring_write(zgfx, zgfx->pbInputCurrent, count);
Packit 1fb8d4
						zgfx->pbInputCurrent += count;
Packit 1fb8d4
						zgfx->cBitsRemaining -= (8 * count);
Packit 1fb8d4
						zgfx->OutputCount += count;
Packit 1fb8d4
					}
Packit 1fb8d4
				}
Packit 1fb8d4
Packit 1fb8d4
				break;
Packit 1fb8d4
			}
Packit 1fb8d4
		}
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	return TRUE;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
int zgfx_decompress(ZGFX_CONTEXT* zgfx, const BYTE* pSrcData, UINT32 SrcSize, BYTE** ppDstData,
Packit 1fb8d4
                    UINT32* pDstSize, UINT32 flags)
Packit 1fb8d4
{
Packit 1fb8d4
	int status = -1;
Packit 1fb8d4
	BYTE descriptor;
Packit 1fb8d4
	wStream* stream = Stream_New((BYTE*)pSrcData, SrcSize);
Packit 1fb8d4
Packit 1fb8d4
	if (!stream)
Packit 1fb8d4
		return -1;
Packit 1fb8d4
Packit 1fb8d4
	if (Stream_GetRemainingLength(stream) < 1)
Packit 1fb8d4
		goto fail;
Packit 1fb8d4
Packit 1fb8d4
	Stream_Read_UINT8(stream, descriptor); /* descriptor (1 byte) */
Packit 1fb8d4
Packit 1fb8d4
	if (descriptor == ZGFX_SEGMENTED_SINGLE)
Packit 1fb8d4
	{
Packit 1fb8d4
		if (!zgfx_decompress_segment(zgfx, stream, Stream_GetRemainingLength(stream)))
Packit 1fb8d4
			goto fail;
Packit 1fb8d4
Packit 1fb8d4
		*ppDstData = NULL;
Packit 1fb8d4
Packit 1fb8d4
		if (zgfx->OutputCount > 0)
Packit 1fb8d4
			*ppDstData = (BYTE*) malloc(zgfx->OutputCount);
Packit 1fb8d4
Packit 1fb8d4
		if (!*ppDstData)
Packit 1fb8d4
			goto fail;
Packit 1fb8d4
Packit 1fb8d4
		*pDstSize = zgfx->OutputCount;
Packit 1fb8d4
		CopyMemory(*ppDstData, zgfx->OutputBuffer, zgfx->OutputCount);
Packit 1fb8d4
	}
Packit 1fb8d4
	else if (descriptor == ZGFX_SEGMENTED_MULTIPART)
Packit 1fb8d4
	{
Packit 1fb8d4
		UINT32 segmentSize;
Packit 1fb8d4
		UINT16 segmentNumber;
Packit 1fb8d4
		UINT16 segmentCount;
Packit 1fb8d4
		UINT32 uncompressedSize;
Packit 1fb8d4
		BYTE* pConcatenated;
Packit 1fb8d4
		size_t used = 0;
Packit 1fb8d4
Packit 1fb8d4
		if (Stream_GetRemainingLength(stream) < 6)
Packit 1fb8d4
			goto fail;
Packit 1fb8d4
Packit 1fb8d4
		Stream_Read_UINT16(stream, segmentCount); /* segmentCount (2 bytes) */
Packit 1fb8d4
		Stream_Read_UINT32(stream, uncompressedSize); /* uncompressedSize (4 bytes) */
Packit 1fb8d4
Packit 1fb8d4
		if (Stream_GetRemainingLength(stream) < segmentCount * sizeof(UINT32))
Packit 1fb8d4
			goto fail;
Packit 1fb8d4
Packit 1fb8d4
		pConcatenated = (BYTE*) malloc(uncompressedSize);
Packit 1fb8d4
Packit 1fb8d4
		if (!pConcatenated)
Packit 1fb8d4
			goto fail;
Packit 1fb8d4
Packit 1fb8d4
		*ppDstData = pConcatenated;
Packit 1fb8d4
		*pDstSize = uncompressedSize;
Packit 1fb8d4
Packit 1fb8d4
		for (segmentNumber = 0; segmentNumber < segmentCount; segmentNumber++)
Packit 1fb8d4
		{
Packit 1fb8d4
			if (Stream_GetRemainingLength(stream) < sizeof(UINT32))
Packit 1fb8d4
				goto fail;
Packit 1fb8d4
Packit 1fb8d4
			Stream_Read_UINT32(stream, segmentSize); /* segmentSize (4 bytes) */
Packit 1fb8d4
Packit 1fb8d4
			if (!zgfx_decompress_segment(zgfx, stream, segmentSize))
Packit 1fb8d4
				goto fail;
Packit 1fb8d4
Packit 1fb8d4
			if (zgfx->OutputCount > UINT32_MAX - used)
Packit 1fb8d4
				goto fail;
Packit 1fb8d4
Packit 1fb8d4
			if (used + zgfx->OutputCount > uncompressedSize)
Packit 1fb8d4
				goto fail;
Packit 1fb8d4
Packit 1fb8d4
			CopyMemory(pConcatenated, zgfx->OutputBuffer, zgfx->OutputCount);
Packit 1fb8d4
			pConcatenated += zgfx->OutputCount;
Packit 1fb8d4
			used += zgfx->OutputCount;
Packit 1fb8d4
		}
Packit 1fb8d4
	}
Packit 1fb8d4
	else
Packit 1fb8d4
	{
Packit 1fb8d4
		goto fail;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	status = 1;
Packit 1fb8d4
fail:
Packit 1fb8d4
	Stream_Free(stream, FALSE);
Packit 1fb8d4
	return status;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
static BOOL zgfx_compress_segment(ZGFX_CONTEXT* zgfx, wStream* s, const BYTE* pSrcData,
Packit 1fb8d4
                                  UINT32 SrcSize, UINT32* pFlags)
Packit 1fb8d4
{
Packit 1fb8d4
	/* FIXME: Currently compression not implemented. Just copy the raw source */
Packit 1fb8d4
	if (!Stream_EnsureRemainingCapacity(s, SrcSize + 1))
Packit 1fb8d4
	{
Packit 1fb8d4
		WLog_ERR(TAG, "Stream_EnsureRemainingCapacity failed!");
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	(*pFlags) |= ZGFX_PACKET_COMPR_TYPE_RDP8; /* RDP 8.0 compression format */
Packit 1fb8d4
	Stream_Write_UINT8(s, (*pFlags)); /* header (1 byte) */
Packit 1fb8d4
	Stream_Write(s, pSrcData, SrcSize);
Packit 1fb8d4
	return TRUE;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
int zgfx_compress_to_stream(ZGFX_CONTEXT* zgfx, wStream* sDst, const BYTE* pUncompressed,
Packit 1fb8d4
                            UINT32 uncompressedSize, UINT32* pFlags)
Packit 1fb8d4
{
Packit 1fb8d4
	int fragment;
Packit 1fb8d4
	UINT16 maxLength;
Packit 1fb8d4
	UINT32 totalLength;
Packit 1fb8d4
	size_t posSegmentCount = 0;
Packit 1fb8d4
	const BYTE* pSrcData;
Packit 1fb8d4
	int status = 0;
Packit 1fb8d4
	maxLength = ZGFX_SEGMENTED_MAXSIZE;
Packit 1fb8d4
	totalLength = uncompressedSize;
Packit 1fb8d4
	pSrcData = pUncompressed;
Packit 1fb8d4
Packit 1fb8d4
	for (fragment = 0; (totalLength > 0) || (fragment == 0); fragment++)
Packit 1fb8d4
	{
Packit 1fb8d4
		UINT32 SrcSize;
Packit 1fb8d4
		size_t posDstSize;
Packit 1fb8d4
		size_t posDataStart;
Packit 1fb8d4
		UINT32 DstSize;
Packit 1fb8d4
		SrcSize = (totalLength > maxLength) ? maxLength : totalLength;
Packit 1fb8d4
		posDstSize = 0;
Packit 1fb8d4
		totalLength -= SrcSize;
Packit 1fb8d4
Packit 1fb8d4
		/* Ensure we have enough space for headers */
Packit 1fb8d4
		if (!Stream_EnsureRemainingCapacity(sDst, 12))
Packit 1fb8d4
		{
Packit 1fb8d4
			WLog_ERR(TAG, "Stream_EnsureRemainingCapacity failed!");
Packit 1fb8d4
			return -1;
Packit 1fb8d4
		}
Packit 1fb8d4
Packit 1fb8d4
		if (fragment == 0)
Packit 1fb8d4
		{
Packit 1fb8d4
			/* First fragment */
Packit 1fb8d4
			/* descriptor (1 byte) */
Packit 1fb8d4
			Stream_Write_UINT8(sDst, (totalLength == 0) ?
Packit 1fb8d4
			                   ZGFX_SEGMENTED_SINGLE : ZGFX_SEGMENTED_MULTIPART);
Packit 1fb8d4
Packit 1fb8d4
			if (totalLength > 0)
Packit 1fb8d4
			{
Packit 1fb8d4
				posSegmentCount = Stream_GetPosition(sDst); /* segmentCount (2 bytes) */
Packit 1fb8d4
				Stream_Seek(sDst, 2);
Packit 1fb8d4
				Stream_Write_UINT32(sDst, uncompressedSize); /* uncompressedSize (4 bytes) */
Packit 1fb8d4
			}
Packit 1fb8d4
		}
Packit 1fb8d4
Packit 1fb8d4
		if (fragment > 0 || totalLength > 0)
Packit 1fb8d4
		{
Packit 1fb8d4
			/* Multipart */
Packit 1fb8d4
			posDstSize = Stream_GetPosition(sDst); /* size (4 bytes) */
Packit 1fb8d4
			Stream_Seek(sDst, 4);
Packit 1fb8d4
		}
Packit 1fb8d4
Packit 1fb8d4
		posDataStart = Stream_GetPosition(sDst);
Packit 1fb8d4
Packit 1fb8d4
		if (!zgfx_compress_segment(zgfx, sDst, pSrcData, SrcSize, pFlags))
Packit 1fb8d4
			return -1;
Packit 1fb8d4
Packit 1fb8d4
		if (posDstSize)
Packit 1fb8d4
		{
Packit 1fb8d4
			/* Fill segment data size */
Packit 1fb8d4
			DstSize = Stream_GetPosition(sDst) - posDataStart;
Packit 1fb8d4
			Stream_SetPosition(sDst, posDstSize);
Packit 1fb8d4
			Stream_Write_UINT32(sDst, DstSize);
Packit 1fb8d4
			Stream_SetPosition(sDst, posDataStart + DstSize);
Packit 1fb8d4
		}
Packit 1fb8d4
Packit 1fb8d4
		pSrcData += SrcSize;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	Stream_SealLength(sDst);
Packit 1fb8d4
Packit 1fb8d4
	/* fill back segmentCount */
Packit 1fb8d4
	if (posSegmentCount)
Packit 1fb8d4
	{
Packit 1fb8d4
		Stream_SetPosition(sDst, posSegmentCount);
Packit 1fb8d4
		Stream_Write_UINT16(sDst, fragment);
Packit 1fb8d4
		Stream_SetPosition(sDst, Stream_Length(sDst));
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	return status;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
int zgfx_compress(ZGFX_CONTEXT* zgfx, const BYTE* pSrcData, UINT32 SrcSize, BYTE** ppDstData,
Packit 1fb8d4
                  UINT32* pDstSize, UINT32* pFlags)
Packit 1fb8d4
{
Packit 1fb8d4
	int status;
Packit 1fb8d4
	wStream* s = Stream_New(NULL, SrcSize);
Packit 1fb8d4
	status = zgfx_compress_to_stream(zgfx, s, pSrcData, SrcSize, pFlags);
Packit 1fb8d4
	(*ppDstData) = Stream_Buffer(s);
Packit 1fb8d4
	(*pDstSize) = Stream_GetPosition(s);
Packit 1fb8d4
	Stream_Free(s, FALSE);
Packit 1fb8d4
	return status;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
Packit 1fb8d4
void zgfx_context_reset(ZGFX_CONTEXT* zgfx, BOOL flush)
Packit 1fb8d4
{
Packit 1fb8d4
	zgfx->HistoryIndex = 0;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
ZGFX_CONTEXT* zgfx_context_new(BOOL Compressor)
Packit 1fb8d4
{
Packit 1fb8d4
	ZGFX_CONTEXT* zgfx;
Packit 1fb8d4
	zgfx = (ZGFX_CONTEXT*) calloc(1, sizeof(ZGFX_CONTEXT));
Packit 1fb8d4
Packit 1fb8d4
	if (zgfx)
Packit 1fb8d4
	{
Packit 1fb8d4
		zgfx->Compressor = Compressor;
Packit 1fb8d4
		zgfx->HistoryBufferSize = sizeof(zgfx->HistoryBuffer);
Packit 1fb8d4
		zgfx_context_reset(zgfx, FALSE);
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	return zgfx;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
void zgfx_context_free(ZGFX_CONTEXT* zgfx)
Packit 1fb8d4
{
Packit 1fb8d4
	free(zgfx);
Packit 1fb8d4
}
Packit 1fb8d4