mirror of
https://github.com/morgan9e/FreeRDP
synced 2026-04-14 00:14:11 +09:00
libfreerdp-codec: integrate basic RDP8 decompression support
This commit is contained in:
@@ -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}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user