From 61eb7f2f8e7dbda8ecc02a795b013b7eef1ed0b8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Moreau?= Date: Fri, 13 Jun 2014 17:30:13 -0400 Subject: [PATCH] libfreerdp-codec: fix ClearCodec decoding --- client/X11/xf_client.c | 49 +++++--- client/X11/xf_gfx.c | 38 +++++- client/X11/xfreerdp.h | 3 +- include/freerdp/codec/clear.h | 4 + libfreerdp/codec/clear.c | 109 ++++++++++++------ libfreerdp/codec/test/TestFreeRDPCodecClear.c | 4 +- 6 files changed, 151 insertions(+), 56 deletions(-) diff --git a/client/X11/xf_client.c b/client/X11/xf_client.c index 4d9c26151..8011e6a82 100644 --- a/client/X11/xf_client.c +++ b/client/X11/xf_client.c @@ -985,45 +985,54 @@ void xf_process_channel_event(rdpChannels *channels, freerdp *instance) void xf_window_free(xfContext *xfc) { - rdpContext *context = (rdpContext *) xfc; + rdpContext* context = (rdpContext*) xfc; + xf_keyboard_free(xfc); - if(xfc->gc) + + if (xfc->gc) { XFreeGC(xfc->display, xfc->gc); xfc->gc = 0; } - if(xfc->gc_mono) + + if (xfc->gc_mono) { XFreeGC(xfc->display, xfc->gc_mono); xfc->gc_mono = 0; } - if(xfc->window) + + if (xfc->window) { xf_DestroyWindow(xfc, xfc->window); xfc->window = NULL; } - if(xfc->primary) + + if (xfc->primary) { XFreePixmap(xfc->display, xfc->primary); xfc->primary = 0; } - if(xfc->bitmap_mono) + + if (xfc->bitmap_mono) { XFreePixmap(xfc->display, xfc->bitmap_mono); xfc->bitmap_mono = 0; } - if(xfc->image) + + if (xfc->image) { xfc->image->data = NULL; XDestroyImage(xfc->image); xfc->image = NULL; } - if(context->cache) + + if (context->cache) { cache_free(context->cache); context->cache = NULL; } - if(context->rail) + + if (context->rail) { rail_free(context->rail); context->rail = NULL; @@ -1040,26 +1049,38 @@ void xf_window_free(xfContext *xfc) nsc_context_free(xfc->nsc); xfc->nsc = NULL; } - if(xfc->clrconv) + + if (xfc->clear) + { + clear_context_free(xfc->clear); + xfc->clear = NULL; + } + + if (xfc->clrconv) { freerdp_clrconv_free(xfc->clrconv); xfc->clrconv = NULL; } - if(xfc->hdc) + + if (xfc->hdc) + { gdi_DeleteDC(xfc->hdc); - if(xfc->xv_context) + } + + if (xfc->xv_context) { xf_tsmf_uninit(xfc); xfc->xv_context = NULL; } - if(xfc->clipboard_context) + + if (xfc->clipboard_context) { xf_cliprdr_uninit(xfc); xfc->clipboard_context = NULL; } } -void *xf_update_thread(void *arg) +void* xf_update_thread(void *arg) { int status; wMessage message; diff --git a/client/X11/xf_gfx.c b/client/X11/xf_gfx.c index 55dffb2c1..94d01257c 100644 --- a/client/X11/xf_gfx.c +++ b/client/X11/xf_gfx.c @@ -54,6 +54,8 @@ int xf_ResetGraphics(RdpgfxClientContext* context, RDPGFX_RESET_GRAPHICS_PDU* re xfc->nsc->height = resetGraphics->height; nsc_context_set_pixel_format(xfc->nsc, RDP_PIXEL_FORMAT_B8G8R8A8); + xfc->clear = clear_context_new(FALSE); + region16_init(&(xfc->invalidRegion)); xfc->graphicsReset = TRUE; @@ -256,6 +258,33 @@ int xf_SurfaceCommand_RemoteFX(xfContext* xfc, RdpgfxClientContext* context, RDP int xf_SurfaceCommand_ClearCodec(xfContext* xfc, RdpgfxClientContext* context, RDPGFX_SURFACE_COMMAND* cmd) { + int status; + UINT32 DstSize = 0; + BYTE* pDstData = NULL; + xfGfxSurface* surface; + RECTANGLE_16 invalidRect; + + surface = (xfGfxSurface*) context->GetSurfaceData(context, cmd->surfaceId); + + if (!surface) + return -1; + + status = clear_decompress(xfc->clear, cmd->data, cmd->length, &pDstData, &DstSize); + + printf("xf_SurfaceCommand_ClearCodec: status: %d\n", status); + + /* fill with pink for now to distinguish from the rest */ + + freerdp_image_fill(surface->data, PIXEL_FORMAT_XRGB32, surface->scanline, + cmd->left, cmd->top, cmd->width, cmd->height, 0xFF69B4); + + invalidRect.left = cmd->left; + invalidRect.top = cmd->top; + invalidRect.right = cmd->right; + invalidRect.bottom = cmd->bottom; + + region16_union_rect(&(xfc->invalidRegion), &(xfc->invalidRegion), &invalidRect); + if (!xfc->inGfxFrame) xf_OutputUpdate(xfc); @@ -286,7 +315,6 @@ int xf_SurfaceCommand(RdpgfxClientContext* context, RDPGFX_SURFACE_COMMAND* cmd) break; case RDPGFX_CODECID_CLEARCODEC: - printf("xf_SurfaceCommand_ClearCodec\n"); status = xf_SurfaceCommand_ClearCodec(xfc, context, cmd); break; @@ -482,8 +510,8 @@ int xf_SurfaceToCache(RdpgfxClientContext* context, RDPGFX_SURFACE_TO_CACHE_PDU* surface = (xfGfxSurface*) context->GetSurfaceData(context, surfaceToCache->surfaceId); - printf("xf_SurfaceToCache: cacheKey: 0x%016X cacheSlot: %ld\n", - surfaceToCache->cacheKey, surfaceToCache->cacheSlot); + //printf("xf_SurfaceToCache: cacheKey: 0x%016X cacheSlot: %ld\n", + // surfaceToCache->cacheKey, surfaceToCache->cacheSlot); if (!surface) return -1; @@ -524,8 +552,8 @@ int xf_CacheToSurface(RdpgfxClientContext* context, RDPGFX_CACHE_TO_SURFACE_PDU* surface = (xfGfxSurface*) context->GetSurfaceData(context, cacheToSurface->surfaceId); cacheEntry = (xfGfxCacheEntry*) context->GetCacheSlotData(context, cacheToSurface->cacheSlot); - printf("xf_CacheToSurface: cacheEntry: %d\n", - cacheToSurface->cacheSlot); + //printf("xf_CacheToSurface: cacheEntry: %d\n", + // cacheToSurface->cacheSlot); if (!surface || !cacheEntry) return -1; diff --git a/client/X11/xfreerdp.h b/client/X11/xfreerdp.h index 347d7c62f..a1e6ebf16 100644 --- a/client/X11/xfreerdp.h +++ b/client/X11/xfreerdp.h @@ -31,7 +31,7 @@ typedef struct xf_context xfContext; #include #include #include -#include +#include #include #include #include @@ -151,6 +151,7 @@ struct xf_context BYTE* bmp_codec_nsc; RFX_CONTEXT* rfx; NSC_CONTEXT* nsc; + CLEAR_CONTEXT* clear; void* xv_context; void* clipboard_context; diff --git a/include/freerdp/codec/clear.h b/include/freerdp/codec/clear.h index c7fc22433..bb1550a25 100644 --- a/include/freerdp/codec/clear.h +++ b/include/freerdp/codec/clear.h @@ -30,6 +30,10 @@ struct _CLEAR_CONTEXT { BOOL Compressor; + UINT32 VBarStorageCursor; + void* VBarStorage[32768]; + UINT32 ShortVBarStorageCursor; + void* ShortVBarStorage[16384]; }; typedef struct _CLEAR_CONTEXT CLEAR_CONTEXT; diff --git a/libfreerdp/codec/clear.c b/libfreerdp/codec/clear.c index d0bc0924f..c57f8c641 100644 --- a/libfreerdp/codec/clear.c +++ b/libfreerdp/codec/clear.c @@ -29,6 +29,7 @@ int clear_decompress(CLEAR_CONTEXT* clear, BYTE* pSrcData, UINT32 SrcSize, BYTE** ppDstData, UINT32* pDstSize) { + int index; BYTE glyphFlags; BYTE seqNumber; UINT16 glyphIndex; @@ -38,7 +39,7 @@ int clear_decompress(CLEAR_CONTEXT* clear, BYTE* pSrcData, UINT32 SrcSize, BYTE* UINT32 subcodecByteCount; if (SrcSize < 2) - return -1; + return -1001; glyphFlags = pSrcData[0]; seqNumber = pSrcData[1]; @@ -49,7 +50,7 @@ int clear_decompress(CLEAR_CONTEXT* clear, BYTE* pSrcData, UINT32 SrcSize, BYTE* if (glyphFlags & CLEARCODEC_FLAG_GLYPH_INDEX) { if (SrcSize < 4) - return -1; + return -1002; glyphIndex = *((UINT16*) &pSrcData[2]); offset += 2; @@ -68,7 +69,7 @@ int clear_decompress(CLEAR_CONTEXT* clear, BYTE* pSrcData, UINT32 SrcSize, BYTE* /* Read composition payload header parameters */ if ((SrcSize - offset) < 12) - return -1; + return -1003; residualByteCount = *((UINT32*) &pSrcData[offset]); bandsByteCount = *((UINT32*) &pSrcData[offset + 4]); @@ -91,7 +92,7 @@ int clear_decompress(CLEAR_CONTEXT* clear, BYTE* pSrcData, UINT32 SrcSize, BYTE* UINT32 runLengthFactor = 0; if ((SrcSize - offset) < residualByteCount) - return -1; + return -1004; suboffset = 0; residualData = &pSrcData[offset]; @@ -99,7 +100,7 @@ int clear_decompress(CLEAR_CONTEXT* clear, BYTE* pSrcData, UINT32 SrcSize, BYTE* while (suboffset < residualByteCount) { if ((residualByteCount - suboffset) < 4) - return -1; + return -1005; blueValue = residualData[suboffset]; greenValue = residualData[suboffset + 1]; @@ -113,7 +114,7 @@ int clear_decompress(CLEAR_CONTEXT* clear, BYTE* pSrcData, UINT32 SrcSize, BYTE* if (runLengthFactor1 >= 0xFF) { if ((residualByteCount - suboffset) < 2) - return -1; + return -1006; runLengthFactor2 = *((UINT16*) &residualData[suboffset]); runLengthFactor = runLengthFactor2; @@ -122,7 +123,7 @@ int clear_decompress(CLEAR_CONTEXT* clear, BYTE* pSrcData, UINT32 SrcSize, BYTE* if (runLengthFactor2 >= 0xFFFF) { if ((residualByteCount - suboffset) < 4) - return -1; + return -1007; runLengthFactor3 = *((UINT32*) &residualData[suboffset]); runLengthFactor = runLengthFactor3; @@ -141,7 +142,7 @@ int clear_decompress(CLEAR_CONTEXT* clear, BYTE* pSrcData, UINT32 SrcSize, BYTE* UINT32 suboffset; if ((SrcSize - offset) < bandsByteCount) - return -1; + return -1008; suboffset = 0; bandsData = &pSrcData[offset]; @@ -157,9 +158,14 @@ int clear_decompress(CLEAR_CONTEXT* clear, BYTE* pSrcData, UINT32 SrcSize, BYTE* BYTE redBkg; BYTE* vBars; UINT16 vBarHeader; + UINT16 vBarIndex; + UINT16 vBarYOn; + UINT16 vBarYOff; + int vBarCount; + int vBarPixelCount; if ((bandsByteCount - suboffset) < 11) - return -1; + return -1009; xStart = *((UINT16*) &bandsData[suboffset]); xEnd = *((UINT16*) &bandsData[suboffset + 2]); @@ -170,31 +176,66 @@ int clear_decompress(CLEAR_CONTEXT* clear, BYTE* pSrcData, UINT32 SrcSize, BYTE* redBkg = bandsData[suboffset + 10]; suboffset += 11; - vBars = &bandsData[suboffset]; + vBarCount = (xEnd - xStart) + 1; - vBarHeader = *((UINT16*) &vBars[0]); + printf("CLEARCODEC_BAND: xStart: %d xEnd: %d yStart: %d yEnd: %d vBarCount: %d blueBkg: 0x%02X greenBkg: 0x%02X redBkg: 0x%02X\n", + xStart, xEnd, yStart, yEnd, vBarCount, blueBkg, greenBkg, redBkg); - if ((vBarHeader & 0xC000) == 0x8000) /* VBAR_CACHE_HIT */ + for (index = 0; index < vBarCount; index++) { - printf("VBAR_CACHE_HIT\n"); + vBars = &bandsData[suboffset]; + + if ((bandsByteCount - suboffset) < 2) + return -1010; + + vBarHeader = *((UINT16*) &vBars[0]); suboffset += 2; - } - else if ((vBarHeader & 0xC000) == 0xC000) /* SHORT_VBAR_CACHE_HIT */ - { - printf("SHORT_VBAR_CACHE_HIT\n"); - suboffset += 3; - } - else if ((vBarHeader & 0xC000) == 0) /* SHORT_VBAR_CACHE_MISS */ - { - printf("SHORT_VBAR_CACHE_MISS\n"); - suboffset += 2; - } - else - { - return -1; /* invalid vBarHeader */ - } - /* shortVBarPixels: variable */ + if ((vBarHeader & 0xC000) == 0x8000) /* VBAR_CACHE_HIT */ + { + vBarIndex = (vBarHeader & 0x7FFF); + + printf("VBAR_CACHE_HIT: vBarIndex: %d\n", + vBarIndex); + } + else if ((vBarHeader & 0xC000) == 0xC000) /* SHORT_VBAR_CACHE_HIT */ + { + vBarIndex = (vBarHeader & 0x3FFF); + + if ((bandsByteCount - suboffset) < 1) + return -1011; + + vBarYOn = vBars[2]; + suboffset += 1; + + printf("SHORT_VBAR_CACHE_HIT: vBarIndex: %d vBarYOn: %d\n", + vBarIndex, vBarYOn); + } + else if ((vBarHeader & 0xC000) == 0x0000) /* SHORT_VBAR_CACHE_MISS */ + { + vBarYOn = (vBarHeader & 0xFF); + vBarYOff = ((vBarHeader >> 8) & 0x3F); + + if (vBarYOff < vBarYOn) + return -1012; + + /* shortVBarPixels: variable */ + + vBarPixelCount = (3 * (vBarYOff - vBarYOn)); + + printf("SHORT_VBAR_CACHE_MISS: vBarYOn: %d vBarYOff: %d bytes: %d\n", + vBarYOn, vBarYOff, vBarPixelCount); + + if ((bandsByteCount - suboffset) < vBarPixelCount) + return -1013; + + suboffset += vBarPixelCount; + } + else + { + return -1014; /* invalid vBarHeader */ + } + } } /* Decompress bands layer and write to output bitmap */ @@ -214,7 +255,7 @@ int clear_decompress(CLEAR_CONTEXT* clear, BYTE* pSrcData, UINT32 SrcSize, BYTE* UINT32 suboffset; if ((SrcSize - offset) < subcodecByteCount) - return -1; + return -1015; suboffset = 0; subcodecs = &pSrcData[offset]; @@ -222,7 +263,7 @@ int clear_decompress(CLEAR_CONTEXT* clear, BYTE* pSrcData, UINT32 SrcSize, BYTE* while (suboffset < subcodecByteCount) { if ((subcodecByteCount - suboffset) < 13) - return -1; + return -1016; xStart = *((UINT16*) &subcodecs[suboffset]); yStart = *((UINT16*) &subcodecs[suboffset + 2]); @@ -232,11 +273,11 @@ int clear_decompress(CLEAR_CONTEXT* clear, BYTE* pSrcData, UINT32 SrcSize, BYTE* subcodecId = subcodecs[suboffset + 12]; suboffset += 13; - printf("bitmapDataByteCount: %d subcodecByteCount: %d suboffset: %d\n", - bitmapDataByteCount, subcodecByteCount, suboffset); + printf("bitmapDataByteCount: %d subcodecByteCount: %d suboffset: %d subCodecId: %d\n", + bitmapDataByteCount, subcodecByteCount, suboffset, subcodecId); if ((subcodecByteCount - suboffset) < bitmapDataByteCount) - return -1; + return -1017; bitmapData = &subcodecs[suboffset]; diff --git a/libfreerdp/codec/test/TestFreeRDPCodecClear.c b/libfreerdp/codec/test/TestFreeRDPCodecClear.c index c83993b0f..fcec61acf 100644 --- a/libfreerdp/codec/test/TestFreeRDPCodecClear.c +++ b/libfreerdp/codec/test/TestFreeRDPCodecClear.c @@ -135,9 +135,9 @@ int TestFreeRDPCodecClear(int argc, char* argv[]) //test_ClearDecompressExample2(); - test_ClearDecompressExample3(); + //test_ClearDecompressExample3(); - //test_ClearDecompressExample4(); + test_ClearDecompressExample4(); return 0; }