From 2b3cd390265a001f21d8064690698882423694eb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Moreau?= Date: Tue, 29 Jul 2014 12:38:29 -0400 Subject: [PATCH] libfreerdp-codec: more parsing of progressive data blocks --- include/freerdp/codec/progressive.h | 81 ++++++-- libfreerdp/codec/progressive.c | 295 ++++++++++++++++++++++++---- 2 files changed, 324 insertions(+), 52 deletions(-) diff --git a/include/freerdp/codec/progressive.h b/include/freerdp/codec/progressive.h index be063aadd..603d1efe4 100644 --- a/include/freerdp/codec/progressive.h +++ b/include/freerdp/codec/progressive.h @@ -32,10 +32,41 @@ #define PROGRESSIVE_WBT_CONTEXT 0xCCC3 #define PROGRESSIVE_WBT_REGION 0xCCC4 #define PROGRESSIVE_WBT_TILE_SIMPLE 0xCCC5 -#define PROGRESSIVE_WBT_TILE_PROGRESSIVE_FIRST 0xCCC6 -#define PROGRESSIVE_WBT_TILE_PROGRESSIVE_UPGRADE 0xCCC7 +#define PROGRESSIVE_WBT_TILE_FIRST 0xCCC6 +#define PROGRESSIVE_WBT_TILE_UPGRADE 0xCCC7 -struct _PROGRESSIVE_SYNC +struct _RFX_PROGRESSIVE_CODEC_QUANT +{ + BYTE quality; + BYTE yQuantValues[5]; + BYTE cbQuantValues[5]; + BYTE crQuantValues[5]; +}; +typedef struct _RFX_PROGRESSIVE_CODEC_QUANT RFX_PROGRESSIVE_CODEC_QUANT; + +struct _RFX_COMPONENT_CODEC_QUANT +{ + BYTE LL3; + BYTE HL3; + BYTE LH3; + BYTE HH3; + BYTE HL2; + BYTE LH2; + BYTE HH2; + BYTE HL1; + BYTE LH1; + BYTE HH1; +}; +typedef struct _RFX_COMPONENT_CODEC_QUANT RFX_COMPONENT_CODEC_QUANT; + +struct _PROGRESSIVE_BLOCK +{ + UINT16 blockType; + UINT32 blockLen; +}; +typedef struct _PROGRESSIVE_BLOCK PROGRESSIVE_BLOCK; + +struct _PROGRESSIVE_BLOCK_SYNC { UINT16 blockType; UINT32 blockLen; @@ -43,9 +74,20 @@ struct _PROGRESSIVE_SYNC UINT32 magic; UINT16 version; }; -typedef struct _PROGRESSIVE_SYNC PROGRESSIVE_SYNC; +typedef struct _PROGRESSIVE_BLOCK_SYNC PROGRESSIVE_BLOCK_SYNC; -struct _PROGRESSIVE_REGION +struct _PROGRESSIVE_BLOCK_CONTEXT +{ + UINT16 blockType; + UINT32 blockLen; + + BYTE ctxId; + UINT16 tileSize; + BYTE flags; +}; +typedef struct _PROGRESSIVE_BLOCK_CONTEXT PROGRESSIVE_BLOCK_CONTEXT; + +struct _PROGRESSIVE_BLOCK_REGION { UINT16 blockType; UINT32 blockLen; @@ -58,30 +100,31 @@ struct _PROGRESSIVE_REGION UINT16 numTiles; UINT32 tileDataSize; RFX_RECT* rects; - UINT32* quantVals; - UINT32* quantProgVals; + RFX_COMPONENT_CODEC_QUANT* quantVals; + RFX_PROGRESSIVE_CODEC_QUANT* quantProgVals; + PROGRESSIVE_BLOCK** tiles; }; -typedef struct _PROGRESSIVE_REGION PROGRESSIVE_REGION; +typedef struct _PROGRESSIVE_BLOCK_REGION PROGRESSIVE_BLOCK_REGION; -struct _PROGRESSIVE_FRAME_BEGIN +struct _PROGRESSIVE_BLOCK_FRAME_BEGIN { UINT16 blockType; UINT32 blockLen; UINT32 frameIndex; UINT16 regionCount; - PROGRESSIVE_REGION* regions; + PROGRESSIVE_BLOCK_REGION* regions; }; -typedef struct _PROGRESSIVE_FRAME_BEGIN PROGRESSIVE_FRAME_BEGIN; +typedef struct _PROGRESSIVE_BLOCK_FRAME_BEGIN PROGRESSIVE_BLOCK_FRAME_BEGIN; -struct _PROGRESSIVE_FRAME_END +struct _PROGRESSIVE_BLOCK_FRAME_END { UINT16 blockType; UINT32 blockLen; }; -typedef struct _PROGRESSIVE_FRAME_END PROGRESSIVE_FRAME_END; +typedef struct _PROGRESSIVE_BLOCK_FRAME_END PROGRESSIVE_BLOCK_FRAME_END; -struct _PROGRESSIVE_TILE_SIMPLE +struct _PROGRESSIVE_BLOCK_TILE_SIMPLE { UINT16 blockType; UINT32 blockLen; @@ -101,9 +144,9 @@ struct _PROGRESSIVE_TILE_SIMPLE BYTE* crData; BYTE* tailData; }; -typedef struct _PROGRESSIVE_TILE_SIMPLE PROGRESSIVE_TILE_SIMPLE; +typedef struct _PROGRESSIVE_BLOCK_TILE_SIMPLE PROGRESSIVE_BLOCK_TILE_SIMPLE; -struct _PROGRESSIVE_TILE_FIRST +struct _PROGRESSIVE_BLOCK_TILE_FIRST { UINT16 blockType; UINT32 blockLen; @@ -124,9 +167,9 @@ struct _PROGRESSIVE_TILE_FIRST BYTE* crData; BYTE* tailData; }; -typedef struct _PROGRESSIVE_TILE_FIRST PROGRESSIVE_TILE_FIRST; +typedef struct _PROGRESSIVE_BLOCK_TILE_FIRST PROGRESSIVE_BLOCK_TILE_FIRST; -struct _PROGRESSIVE_TILE_UPGRADE +struct _PROGRESSIVE_BLOCK_TILE_UPGRADE { UINT16 blockType; UINT32 blockLen; @@ -150,7 +193,7 @@ struct _PROGRESSIVE_TILE_UPGRADE BYTE* crSrlData; BYTE* crRawData; }; -typedef struct _PROGRESSIVE_TILE_UPGRADE PROGRESSIVE_TILE_UPGRADE; +typedef struct _PROGRESSIVE_BLOCK_TILE_UPGRADE PROGRESSIVE_BLOCK_TILE_UPGRADE; struct _PROGRESSIVE_CONTEXT { diff --git a/libfreerdp/codec/progressive.c b/libfreerdp/codec/progressive.c index 2dfee8460..1cd1ce76d 100644 --- a/libfreerdp/codec/progressive.c +++ b/libfreerdp/codec/progressive.c @@ -28,83 +28,171 @@ #include #include +const char* progressive_get_block_type_string(UINT16 blockType) +{ + switch (blockType) + { + case PROGRESSIVE_WBT_SYNC: + return "PROGRESSIVE_WBT_SYNC"; + break; + + case PROGRESSIVE_WBT_FRAME_BEGIN: + return "PROGRESSIVE_WBT_FRAME_BEGIN"; + break; + + case PROGRESSIVE_WBT_FRAME_END: + return "PROGRESSIVE_WBT_FRAME_END"; + break; + + case PROGRESSIVE_WBT_CONTEXT: + return "PROGRESSIVE_WBT_CONTEXT"; + break; + + case PROGRESSIVE_WBT_REGION: + return "PROGRESSIVE_WBT_REGION"; + break; + + case PROGRESSIVE_WBT_TILE_SIMPLE: + return "PROGRESSIVE_WBT_TILE_SIMPLE"; + break; + + case PROGRESSIVE_WBT_TILE_FIRST: + return "PROGRESSIVE_WBT_TILE_FIRST"; + break; + + case PROGRESSIVE_WBT_TILE_UPGRADE: + return "PROGRESSIVE_WBT_TILE_UPGRADE"; + break; + + default: + return "PROGRESSIVE_WBT_UNKNOWN"; + break; + } + + return "PROGRESSIVE_WBT_UNKNOWN"; +} + int progressive_decompress(PROGRESSIVE_CONTEXT* progressive, BYTE* pSrcData, UINT32 SrcSize, BYTE** ppDstData, DWORD DstFormat, int nDstStep, int nXDst, int nYDst, int nWidth, int nHeight) { BYTE* block; + UINT16 index; UINT32 boffset; - UINT32 ctxId; - UINT32 flags; - UINT32 tileSize; - UINT32 magic; - UINT32 version; UINT16 blockType; UINT32 blockLen; + RFX_RECT* rect; UINT32 offset = 0; - UINT32 frameIndex; - UINT32 regionCount; - PROGRESSIVE_REGION region; - PROGRESSIVE_TILE_SIMPLE simple; - PROGRESSIVE_TILE_FIRST first; - PROGRESSIVE_TILE_UPGRADE upgrade; + PROGRESSIVE_BLOCK_SYNC sync; + PROGRESSIVE_BLOCK_REGION region; + PROGRESSIVE_BLOCK_CONTEXT context; + PROGRESSIVE_BLOCK_FRAME_BEGIN frameBegin; + PROGRESSIVE_BLOCK_FRAME_END frameEnd; + PROGRESSIVE_BLOCK_TILE_SIMPLE simple; + PROGRESSIVE_BLOCK_TILE_FIRST first; + PROGRESSIVE_BLOCK_TILE_UPGRADE upgrade; + RFX_COMPONENT_CODEC_QUANT* quantVal; + RFX_PROGRESSIVE_CODEC_QUANT* quantProgVal; printf("ProgressiveDecompress\n"); - while ((SrcSize - offset) > 6) + if (SrcSize < 6) + return -1001; + + while ((SrcSize - offset) >= 6) { boffset = 0; block = &pSrcData[offset]; - blockType = *((UINT16*) &block[boffset]); /* blockType (2 bytes) */ + blockType = *((UINT16*) &block[boffset + 0]); /* blockType (2 bytes) */ blockLen = *((UINT32*) &block[boffset + 2]); /* blockLen (4 bytes) */ boffset += 6; + if ((SrcSize - offset) < blockLen) + return -1002; + switch (blockType) { case PROGRESSIVE_WBT_SYNC: - if (blockLen != 12) - return -1; + sync.blockType = blockType; + sync.blockLen = blockLen; - magic = (UINT32) *((UINT32*) &block[boffset]); /* magic (4 bytes) */ - version = (UINT32) *((UINT16*) &block[boffset + 4]); /* version (2 bytes) */ + if (blockLen != 12) + return -1003; + + sync.magic = (UINT32) *((UINT32*) &block[boffset + 0]); /* magic (4 bytes) */ + sync.version = (UINT32) *((UINT16*) &block[boffset + 4]); /* version (2 bytes) */ boffset += 6; + /* magic SHOULD be set to 0xCACCACCA, but the decoder SHOULD ignore it */ + /* version SHOULD be set to 0x0100, but the decoder SHOULD ignore it */ + break; case PROGRESSIVE_WBT_FRAME_BEGIN: - frameIndex = (UINT32) *((UINT32*) &block[boffset]); /* frameIndex (4 bytes) */ - regionCount = (UINT32) *((UINT16*) &block[boffset + 4]); /* regionCount (2 bytes) */ + frameBegin.blockType = blockType; + frameBegin.blockLen = blockLen; + + if ((blockLen - boffset) < 6) + return -1004; + + frameBegin.frameIndex = (UINT32) *((UINT32*) &block[boffset + 0]); /* frameIndex (4 bytes) */ + frameBegin.regionCount = (UINT32) *((UINT16*) &block[boffset + 4]); /* regionCount (2 bytes) */ boffset += 6; + /** + * If the number of elements specified by the regionCount field is + * larger than the actual number of elements in the regions field, + * the decoder SHOULD ignore this inconsistency. + */ + + if ((blockLen - boffset) > 6) + { + fprintf(stderr, "warning: regions present in frame begin block are ignored\n"); + } + + boffset = blockLen; + break; case PROGRESSIVE_WBT_FRAME_END: + frameEnd.blockType = blockType; + frameEnd.blockLen = blockLen; + if (blockLen != 6) - return -1; + return -1005; break; case PROGRESSIVE_WBT_CONTEXT: - if (blockLen != 10) - return -1; + context.blockType = blockType; + context.blockLen = blockLen; - ctxId = (UINT32) block[boffset]; /* ctxId (1 byte) */ - tileSize = (UINT32) *((UINT16*) &block[boffset + 1]); /* tileSize (2 bytes) */ - flags = (UINT32) block[boffset + 3]; /* flags (1 byte) */ + if (blockLen != 10) + return -1006; + + context.ctxId = block[boffset + 0]; /* ctxId (1 byte) */ + context.tileSize = *((UINT16*) &block[boffset + 1]); /* tileSize (2 bytes) */ + context.flags = block[boffset + 3]; /* flags (1 byte) */ boffset += 4; - if (tileSize != 64) - return -1; + if (context.tileSize != 64) + return -1007; break; case PROGRESSIVE_WBT_REGION: - region.tileSize = block[boffset]; /* tileSize (1 byte) */ + region.blockType = blockType; + region.blockLen = blockLen; + + if ((blockLen - boffset) < 12) + return -1008; + + region.tileSize = block[boffset + 0]; /* tileSize (1 byte) */ region.numRects = *((UINT16*) &block[boffset + 1]); /* numRects (2 bytes) */ region.numQuant = block[boffset + 3]; /* numQuant (1 byte) */ region.numProgQuant = block[boffset + 4]; /* numProgQuant (1 byte) */ @@ -113,11 +201,97 @@ int progressive_decompress(PROGRESSIVE_CONTEXT* progressive, BYTE* pSrcData, UIN region.tileDataSize = *((UINT32*) &block[boffset + 8]); /* tileDataSize (4 bytes) */ boffset += 12; + if (region.tileSize != 64) + return -1; + + if (region.numRects < 1) + return -1; + + if (region.numQuant > 7) + return -1; + + if ((blockLen - boffset) < (region.numRects * 8)) + return -1; + + region.rects = (RFX_RECT*) malloc(region.numRects * sizeof(RFX_RECT)); + + if (!region.rects) + return -1; + + for (index = 0; index < region.numRects; index++) + { + rect = &(region.rects[index]); + rect->x = *((UINT16*) &block[boffset + 0]); + rect->y = *((UINT16*) &block[boffset + 2]); + rect->width = *((UINT16*) &block[boffset + 4]); + rect->height = *((UINT16*) &block[boffset + 6]); + boffset += 8; + } + + if (region.numQuant > 0) + { + if ((blockLen - boffset) < (region.numQuant * 5)) + return -1; + + region.quantVals = (RFX_COMPONENT_CODEC_QUANT*) malloc(region.numQuant * sizeof(RFX_COMPONENT_CODEC_QUANT)); + + if (!region.quantVals) + return -1; + + for (index = 0; index < region.numQuant; index++) + { + quantVal = &(region.quantVals[index]); + quantVal->LL3 = block[boffset + 0] & 0x0F; + quantVal->HL3 = block[boffset + 0] >> 4; + quantVal->LH3 = block[boffset + 1] & 0x0F; + quantVal->HH3 = block[boffset + 1] >> 4; + quantVal->HL2 = block[boffset + 2] & 0x0F; + quantVal->LH2 = block[boffset + 2] >> 4; + quantVal->HH2 = block[boffset + 3] & 0x0F; + quantVal->HL1 = block[boffset + 3] >> 4; + quantVal->LH1 = block[boffset + 4] & 0x0F; + quantVal->HH1 = block[boffset + 4] >> 4; + boffset += 5; + } + } + + if (region.numProgQuant > 0) + { + if ((blockLen - boffset) < (region.numProgQuant * 16)) + return -1; + + region.quantProgVals = (RFX_PROGRESSIVE_CODEC_QUANT*) malloc(region.numProgQuant * sizeof(RFX_PROGRESSIVE_CODEC_QUANT)); + + if (!region.quantVals) + return -1; + + for (index = 0; index < region.numProgQuant; index++) + { + quantProgVal = &(region.quantProgVals[index]); + quantProgVal->quality = block[boffset + 0]; + CopyMemory(quantProgVal->yQuantValues, &block[boffset + 1], 5); + CopyMemory(quantProgVal->cbQuantValues, &block[boffset + 6], 5); + CopyMemory(quantProgVal->crQuantValues, &block[boffset + 11], 5); + boffset += 16; + } + } + + printf("numTiles: %d tileDataSize: %d numQuant: %d numProgQuant: %d\n", + region.numTiles, region.tileDataSize, region.numQuant, region.numProgQuant); + + boffset += region.tileDataSize; /* skip for now */ + break; case PROGRESSIVE_WBT_TILE_SIMPLE: - simple.quantIdxY = block[boffset]; /* quantIdxY (1 byte) */ + simple.blockType = blockType; + simple.blockLen = blockLen; + + if ((blockLen - boffset) < 16) + return -1009; + + simple.quantIdxY = block[boffset + 0]; /* quantIdxY (1 byte) */ simple.quantIdxCb = block[boffset + 1]; /* quantIdxCb (1 byte) */ simple.quantIdxCr = block[boffset + 2]; /* quantIdxCr (1 byte) */ simple.xIdx = *((UINT16*) &block[boffset + 3]); /* xIdx (2 bytes) */ @@ -143,9 +317,15 @@ int progressive_decompress(PROGRESSIVE_CONTEXT* progressive, BYTE* pSrcData, UIN break; - case PROGRESSIVE_WBT_TILE_PROGRESSIVE_FIRST: + case PROGRESSIVE_WBT_TILE_FIRST: - first.quantIdxY = block[boffset]; /* quantIdxY (1 byte) */ + first.blockType = blockType; + first.blockLen = blockLen; + + if ((blockLen - boffset) < 17) + return -1010; + + first.quantIdxY = block[boffset + 0]; /* quantIdxY (1 byte) */ first.quantIdxCb = block[boffset + 1]; /* quantIdxCb (1 byte) */ first.quantIdxCr = block[boffset + 2]; /* quantIdxCr (1 byte) */ first.xIdx = *((UINT16*) &block[boffset + 3]); /* xIdx (2 bytes) */ @@ -158,23 +338,41 @@ int progressive_decompress(PROGRESSIVE_CONTEXT* progressive, BYTE* pSrcData, UIN first.tailLen = *((UINT16*) &block[boffset + 15]); /* tailLen (2 bytes) */ boffset += 17; + if ((blockLen - boffset) < first.yLen) + return -1011; + first.yData = &block[boffset]; boffset += first.yLen; + if ((blockLen - boffset) < first.cbLen) + return -1012; + first.cbData = &block[boffset]; boffset += first.cbLen; + if ((blockLen - boffset) < first.crLen) + return -1013; + first.crData = &block[boffset]; boffset += first.crLen; + if ((blockLen - boffset) < first.tailLen) + return -1014; + first.tailData = &block[boffset]; boffset += first.tailLen; break; - case PROGRESSIVE_WBT_TILE_PROGRESSIVE_UPGRADE: + case PROGRESSIVE_WBT_TILE_UPGRADE: - upgrade.quantIdxY = block[boffset]; /* quantIdxY (1 byte) */ + upgrade.blockType = blockType; + upgrade.blockLen = blockLen; + + if ((blockLen - boffset) < 18) + return -1015; + + upgrade.quantIdxY = block[boffset + 0]; /* quantIdxY (1 byte) */ upgrade.quantIdxCb = block[boffset + 1]; /* quantIdxCb (1 byte) */ upgrade.quantIdxCr = block[boffset + 2]; /* quantIdxCr (1 byte) */ upgrade.xIdx = *((UINT16*) &block[boffset + 3]); /* xIdx (2 bytes) */ @@ -188,30 +386,61 @@ int progressive_decompress(PROGRESSIVE_CONTEXT* progressive, BYTE* pSrcData, UIN upgrade.crRawLen = *((UINT16*) &block[boffset + 18]); /* crRawLen (2 bytes) */ boffset += 18; + if ((blockLen - boffset) < upgrade.ySrlLen) + return -1016; + upgrade.ySrlData = &block[boffset]; boffset += upgrade.ySrlLen; + if ((blockLen - boffset) < upgrade.yRawLen) + return -1017; + upgrade.yRawData = &block[boffset]; boffset += upgrade.yRawLen; + if ((blockLen - boffset) < upgrade.cbSrlLen) + return -1018; + upgrade.cbSrlData = &block[boffset]; boffset += upgrade.cbSrlLen; + if ((blockLen - boffset) < upgrade.cbRawLen) + return -1019; + upgrade.cbRawData = &block[boffset]; boffset += upgrade.cbRawLen; + if ((blockLen - boffset) < upgrade.crSrlLen) + return -1020; + upgrade.crSrlData = &block[boffset]; boffset += upgrade.crSrlLen; + if ((blockLen - boffset) < upgrade.crRawLen) + return -1021; + upgrade.crRawData = &block[boffset]; boffset += upgrade.crRawLen; break; + + default: + return -1022; + break; + } + + if (boffset != blockLen) + { + printf("failure %s\n", progressive_get_block_type_string(blockType)); + return -1023; } offset += blockLen; } + if (offset != SrcSize) + return -1024; + return 1; }