libfreerdp-codec: integrate basic RDP8 decompression support

This commit is contained in:
Marc-André Moreau
2014-06-03 14:29:55 -04:00
parent abd833c27e
commit a50e4d16fc
4 changed files with 352 additions and 12 deletions

View File

@@ -32,7 +32,7 @@ set_target_properties(${MODULE_NAME} PROPERTIES PREFIX "")
set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS
MONOLITHIC ${MONOLITHIC_BUILD}
MODULE freerdp
MODULES freerdp-common freerdp-utils)
MODULES freerdp-common freerdp-codec freerdp-utils)
set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS
MONOLITHIC ${MONOLITHIC_BUILD}

View File

@@ -37,6 +37,7 @@
#include <winpr/collections.h>
#include <freerdp/addin.h>
#include <freerdp/codec/zgfx.h>
#include "rdpgfx_common.h"
@@ -68,6 +69,8 @@ struct _RDPGFX_PLUGIN
IWTSListener* listener;
RDPGFX_LISTENER_CALLBACK* listener_callback;
ZGFX_CONTEXT* zgfx;
};
typedef struct _RDPGFX_PLUGIN RDPGFX_PLUGIN;
@@ -149,12 +152,6 @@ int rdpgfx_recv_pdu(RDPGFX_CHANNEL_CALLBACK* callback, wStream* s)
/* RDPGFX_HEADER */
/* data needs to be decompressed first */
//winpr_HexDump(Stream_Buffer(s), 32);
return 0;
Stream_Read_UINT16(s, header.cmdId); /* cmdId (2 bytes) */
Stream_Read_UINT16(s, header.flags); /* flags (2 bytes) */
Stream_Read_UINT32(s, header.pduLength); /* pduLength (4 bytes) */
@@ -169,15 +166,28 @@ static int rdpgfx_on_data_received(IWTSVirtualChannelCallback* pChannelCallback,
{
wStream* s;
int status = 0;
UINT32 DstSize = 0;
BYTE* pDstData = NULL;
RDPGFX_PLUGIN* gfx = NULL;
RDPGFX_CHANNEL_CALLBACK* callback = (RDPGFX_CHANNEL_CALLBACK*) pChannelCallback;
gfx = (RDPGFX_PLUGIN*) callback->plugin;
fprintf(stderr, "RdpGfxOnDataReceived: cbSize: %d\n", cbSize);
s = Stream_New(pBuffer, cbSize);
status = zgfx_decompress(gfx->zgfx, pBuffer, cbSize, &pDstData, &DstSize, 0);
if (status < 0)
{
printf("zgfx_decompress failure! status: %d\n", status);
return 0;
}
s = Stream_New(pDstData, DstSize);
status = rdpgfx_recv_pdu(callback, s);
Stream_Free(s, FALSE);
Stream_Free(s, TRUE);
return status;
}
@@ -259,6 +269,8 @@ static int rdpgfx_plugin_terminated(IWTSPlugin* pPlugin)
if (rdpgfx->listener_callback)
free(rdpgfx->listener_callback);
zgfx_context_free(rdpgfx->zgfx);
free(rdpgfx);
return 0;
@@ -308,6 +320,8 @@ int DVCPluginEntry(IDRDYNVC_ENTRY_POINTS* pEntryPoints)
rdpgfx->iface.pInterface = (void*) context;
rdpgfx->zgfx = zgfx_context_new(FALSE);
error = pEntryPoints->RegisterPlugin(pEntryPoints, "rdpgfx", (IWTSPlugin*) rdpgfx);
}

View File

@@ -25,15 +25,43 @@
#include <freerdp/codec/bulk.h>
#define ZGFX_SEGMENTED_SINGLE 0xE0
#define ZGFX_SEGMENTED_MULTIPART 0xE1
#pragma pack(push,1)
typedef struct
{
BYTE descriptor;
UINT16 segmentCount;
UINT32 uncompressedSize;
// RDP_DATA_SEGMENT first;
} RDP_SEGMENTED_DATA;
typedef struct
{
UINT32 size;
// BYTE data[size];
} RDP_DATA_SEGMENT;
#pragma pack(pop)
struct _ZGFX_CONTEXT
{
BOOL Compressor;
BYTE* pbInputCurrent;
BYTE* pbInputEnd;
UINT32 cBitsRemaining;
UINT32 BitsCurrent;
UINT32 cBitsCurrent;
BYTE OutputBuffer[65536];
UINT32 OutputCount;
BYTE HistoryBuffer[2500000];
UINT32 HistoryIndex;
};
typedef struct _ZGFX_CONTEXT ZGFX_CONTEXT;

View File

@@ -27,23 +27,321 @@
#include <freerdp/codec/zgfx.h>
struct _ZGFX_TOKEN
{
int prefixLength;
int prefixCode;
int valueBits;
int tokenType;
UINT32 valueBase;
};
typedef struct _ZGFX_TOKEN ZGFX_TOKEN;
static const ZGFX_TOKEN ZGFX_TOKEN_TABLE[] =
{
// len code vbits type vbase
{ 1, 0, 8, 0, 0 }, // 0
{ 5, 17, 5, 1, 0 }, // 10001
{ 5, 18, 7, 1, 32 }, // 10010
{ 5, 19, 9, 1, 160 }, // 10011
{ 5, 20, 10, 1, 672 }, // 10100
{ 5, 21, 12, 1, 1696 }, // 10101
{ 5, 24, 0, 0, 0x00 }, // 11000
{ 5, 25, 0, 0, 0x01 }, // 11001
{ 6, 44, 14, 1, 5792 }, // 101100
{ 6, 45, 15, 1, 22176 }, // 101101
{ 6, 52, 0, 0, 0x02 }, // 110100
{ 6, 53, 0, 0, 0x03 }, // 110101
{ 6, 54, 0, 0, 0xFF }, // 110110
{ 7, 92, 18, 1, 54944 }, // 1011100
{ 7, 93, 20, 1, 317088 }, // 1011101
{ 7, 110, 0, 0, 0x04 }, // 1101110
{ 7, 111, 0, 0, 0x05 }, // 1101111
{ 7, 112, 0, 0, 0x06 }, // 1110000
{ 7, 113, 0, 0, 0x07 }, // 1110001
{ 7, 114, 0, 0, 0x08 }, // 1110010
{ 7, 115, 0, 0, 0x09 }, // 1110011
{ 7, 116, 0, 0, 0x0A }, // 1110100
{ 7, 117, 0, 0, 0x0B }, // 1110101
{ 7, 118, 0, 0, 0x3A }, // 1110110
{ 7, 119, 0, 0, 0x3B }, // 1110111
{ 7, 120, 0, 0, 0x3C }, // 1111000
{ 7, 121, 0, 0, 0x3D }, // 1111001
{ 7, 122, 0, 0, 0x3E }, // 1111010
{ 7, 123, 0, 0, 0x3F }, // 1111011
{ 7, 124, 0, 0, 0x40 }, // 1111100
{ 7, 125, 0, 0, 0x80 }, // 1111101
{ 8, 188, 20, 1, 1365664 }, // 10111100
{ 8, 189, 21, 1, 2414240 }, // 10111101
{ 8, 252, 0, 0, 0x0C }, // 11111100
{ 8, 253, 0, 0, 0x38 }, // 11111101
{ 8, 254, 0, 0, 0x39 }, // 11111110
{ 8, 255, 0, 0, 0x66 }, // 11111111
{ 9, 380, 22, 1, 4511392 }, // 101111100
{ 9, 381, 23, 1, 8705696 }, // 101111101
{ 9, 382, 24, 1, 17094304 }, // 101111110
{ 0 }
};
UINT32 zgfx_GetBits(ZGFX_CONTEXT* zgfx, UINT32 bitCount)
{
UINT32 result;
while (zgfx->cBitsCurrent < bitCount)
{
zgfx->BitsCurrent <<= 8;
if (zgfx->pbInputCurrent < zgfx->pbInputEnd)
{
zgfx->BitsCurrent += *(zgfx->pbInputCurrent)++;
}
zgfx->cBitsCurrent += 8;
}
zgfx->cBitsRemaining -= bitCount;
zgfx->cBitsCurrent -= bitCount;
result = zgfx->BitsCurrent >> zgfx->cBitsCurrent;
zgfx->BitsCurrent &= ((1 << zgfx->cBitsCurrent) - 1);
return result;
}
int zgfx_OutputFromNotCompressed(ZGFX_CONTEXT* zgfx, BYTE* pbRaw, int cbRaw)
{
BYTE c;
int iRaw;
zgfx->OutputCount = 0;
for (iRaw = 0; iRaw < cbRaw; iRaw++)
{
c = pbRaw[iRaw];
zgfx->HistoryBuffer[zgfx->HistoryIndex++] = c;
if (zgfx->HistoryIndex == sizeof(zgfx->HistoryBuffer))
zgfx->HistoryIndex = 0;
zgfx->OutputBuffer[zgfx->OutputCount++] = c;
}
return 1;
}
int zgfx_OutputFromCompressed(ZGFX_CONTEXT* zgfx, BYTE* pbEncoded, int cbEncoded)
{
BYTE c;
int extra;
int opIndex;
int haveBits;
int inPrefix;
UINT32 count;
UINT32 distance;
UINT32 prevIndex;
zgfx->OutputCount = 0;
zgfx->pbInputCurrent = pbEncoded;
zgfx->pbInputEnd = pbEncoded + cbEncoded - 1;
zgfx->cBitsRemaining = 8 * (cbEncoded - 1) - *zgfx->pbInputEnd;
zgfx->cBitsCurrent = 0;
zgfx->BitsCurrent = 0;
while (zgfx->cBitsRemaining)
{
haveBits = 0;
inPrefix = 0;
for (opIndex = 0; ZGFX_TOKEN_TABLE[opIndex].prefixLength != 0; opIndex++)
{
while (haveBits < ZGFX_TOKEN_TABLE[opIndex].prefixLength)
{
inPrefix = (inPrefix << 1) + zgfx_GetBits(zgfx, 1);
haveBits++;
}
if (inPrefix == ZGFX_TOKEN_TABLE[opIndex].prefixCode)
{
if (ZGFX_TOKEN_TABLE[opIndex].tokenType == 0)
{
c = (BYTE)(ZGFX_TOKEN_TABLE[opIndex].valueBase +
zgfx_GetBits(zgfx, ZGFX_TOKEN_TABLE[opIndex].valueBits));
goto output_literal;
}
else
{
distance = ZGFX_TOKEN_TABLE[opIndex].valueBase +
zgfx_GetBits(zgfx, ZGFX_TOKEN_TABLE[opIndex].valueBits);
if (distance != 0)
{
if (zgfx_GetBits(zgfx, 1) == 0)
{
count = 3;
}
else
{
count = 4;
extra = 2;
while (zgfx_GetBits(zgfx, 1) == 1)
{
count *= 2;
extra++;
}
count += zgfx_GetBits(zgfx, extra);
}
goto output_match;
}
else
{
count = zgfx_GetBits(zgfx, 15);
zgfx->cBitsRemaining -= zgfx->cBitsCurrent;
zgfx->cBitsCurrent = 0;
zgfx->BitsCurrent = 0;
goto output_unencoded;
}
}
}
}
break;
output_literal:
zgfx->HistoryBuffer[zgfx->HistoryIndex] = c;
if (++zgfx->HistoryIndex == sizeof(zgfx->HistoryBuffer))
zgfx->HistoryIndex = 0;
zgfx->OutputBuffer[zgfx->OutputCount++] = c;
continue;
output_match:
prevIndex = zgfx->HistoryIndex + sizeof(zgfx->HistoryBuffer) - distance;
prevIndex = prevIndex % sizeof(zgfx->HistoryBuffer);
while (count--)
{
c = zgfx->HistoryBuffer[prevIndex];
if (++prevIndex == sizeof(zgfx->HistoryBuffer))
prevIndex = 0;
zgfx->HistoryBuffer[zgfx->HistoryIndex] = c;
if (++zgfx->HistoryIndex == sizeof(zgfx->HistoryBuffer))
zgfx->HistoryIndex = 0;
zgfx->OutputBuffer[zgfx->OutputCount] = c;
++zgfx->OutputCount;
}
continue;
output_unencoded:
while (count--)
{
c = *zgfx->pbInputCurrent++;
zgfx->cBitsRemaining -= 8;
zgfx->HistoryBuffer[zgfx->HistoryIndex] = c;
if (++zgfx->HistoryIndex == sizeof(zgfx->HistoryBuffer))
zgfx->HistoryIndex = 0;
zgfx->OutputBuffer[zgfx->OutputCount] = c;
++zgfx->OutputCount;
}
continue;
}
return 1;
}
int zgfx_OutputFromSegment(ZGFX_CONTEXT* zgfx, BYTE* pbSegment, int cbSegment)
{
int status;
if (pbSegment[0] & PACKET_COMPRESSED)
status = zgfx_OutputFromCompressed(zgfx, pbSegment + 1, cbSegment - 1);
else
status = zgfx_OutputFromNotCompressed(zgfx, pbSegment + 1, cbSegment - 1);
return status;
}
int zgfx_Decompress_Internal(ZGFX_CONTEXT* zgfx, BYTE* pbInput, int cbInput, BYTE** ppbOutput, int* pcbOutput)
{
int status;
RDP_SEGMENTED_DATA* pSegmentedData = (RDP_SEGMENTED_DATA*) pbInput;
if (pSegmentedData->descriptor == ZGFX_SEGMENTED_SINGLE)
{
status = zgfx_OutputFromSegment(zgfx, pbInput + 1, cbInput - 1);
*ppbOutput = (BYTE*) malloc(zgfx->OutputCount);
*pcbOutput = zgfx->OutputCount;
CopyMemory(*ppbOutput, zgfx->OutputBuffer, zgfx->OutputCount);
}
else if (pSegmentedData->descriptor == ZGFX_SEGMENTED_MULTIPART)
{
UINT16 segmentNumber;
UINT32 segmentOffset = sizeof(RDP_SEGMENTED_DATA);
BYTE* pConcatenated = (BYTE*) malloc(pSegmentedData->uncompressedSize);
*ppbOutput = pConcatenated;
*pcbOutput = pSegmentedData->uncompressedSize;
for (segmentNumber = 0; segmentNumber < pSegmentedData->segmentCount; segmentNumber++)
{
RDP_DATA_SEGMENT* pSegment = (RDP_DATA_SEGMENT*) (pbInput + segmentOffset);
status = zgfx_OutputFromSegment(zgfx, pbInput + segmentOffset + sizeof(RDP_DATA_SEGMENT), pSegment->size);
segmentOffset += sizeof(RDP_DATA_SEGMENT) + pSegment->size;
CopyMemory(pConcatenated, zgfx->OutputBuffer, zgfx->OutputCount);
pConcatenated += zgfx->OutputCount;
}
}
return 1;
}
int zgfx_decompress(ZGFX_CONTEXT* zgfx, BYTE* pSrcData, UINT32 SrcSize, BYTE** ppDstData, UINT32* pDstSize, UINT32 flags)
{
int status = 0;
int cbOutput = 0;
BYTE* pbOutput = NULL;
status = zgfx_Decompress_Internal(zgfx, pSrcData, SrcSize, &pbOutput, &cbOutput);
if (status >= 0)
{
*ppDstData = pbOutput;
*pDstSize = (UINT32) cbOutput;
}
return status;
}
int zgfx_compress(ZGFX_CONTEXT* zgfx, BYTE* pSrcData, UINT32 SrcSize, BYTE** ppDstData, UINT32* pDstSize, UINT32* pFlags)
{
int status = 0;
return 1;
}
void zgfx_context_reset(ZGFX_CONTEXT* zgfx, BOOL flush)
{
zgfx->HistoryIndex = 0;
}
ZGFX_CONTEXT* zgfx_context_new(BOOL Compressor)