text: /**
   * FreeRDP: A Remote Desktop Protocol Implementation
   * ClearCodec Bitmap Compression
   *
   * Copyright 2014 Marc-Andre Moreau <marcandre.moreau@gmail.com>
   *
   * Licensed under the Apache License, Version 2.0 (the "License");
   * you may not use this file except in compliance with the License.
   * You may obtain a copy of the License at
   *
   *     http://www.apache.org/licenses/LICENSE-2.0
   *
   * Unless required by applicable law or agreed to in writing, software
   * distributed under the License is distributed on an "AS IS" BASIS,
   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   * See the License for the specific language governing permissions and
   * limitations under the License.
   */
  
  #ifdef HAVE_CONFIG_H
  #include "config.h"
  #endif
  
  #include <winpr/crt.h>
  #include <winpr/print.h>
  #include <winpr/bitstream.h>
  
  #include <freerdp/codec/color.h>
  #include <freerdp/codec/clear.h>
  
  static UINT32 CLEAR_LOG2_FLOOR[256] =
  {
  	0, 0, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3,
  	4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
  	5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
  	5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
  	6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
  	6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
  	6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
  	6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
  	7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
  	7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
  	7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
  	7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
  	7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
  	7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
  	7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
  	7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7
  };
  
  static BYTE CLEAR_8BIT_MASKS[9] =
  {
  	0x00, 0x01, 0x03, 0x07, 0x0F, 0x1F, 0x3F, 0x7F, 0xFF
  };
  
  int clear_decompress(CLEAR_CONTEXT* clear, BYTE* pSrcData, UINT32 SrcSize,
  		BYTE** ppDstData, DWORD DstFormat, int nDstStep, int nXDst, int nYDst, int nWidth, int nHeight)
  {
  	UINT32 i;
  	UINT32 x, y;
  	UINT32 count;
  	UINT32 color;
  	int nXDstRel;
  	int nYDstRel;
  	int nSrcStep;
  	BYTE seqNumber;
  	BYTE glyphFlags;
  	BYTE* glyphData;
  	UINT32 offset = 0;
  	UINT16 glyphIndex = 0;
  	BYTE* pDstData = NULL;
  	UINT32 residualByteCount;
  	UINT32 bandsByteCount;
  	UINT32 subcodecByteCount;
  	UINT32 runLengthFactor;
  	UINT32 pixelIndex = 0;
  	UINT32 pixelCount = 0;
  	BYTE* pSrcPixel8 = NULL;
  	BYTE* pDstPixel8 = NULL;
  	UINT32* pSrcPixel32 = NULL;
  	UINT32* pDstPixel32 = NULL;
  	CLEAR_GLYPH_ENTRY* glyphEntry;
  
  	if (!ppDstData)
  		return -1001;
  
  	pDstData = *ppDstData;
  
  	if (!pDstData)
  		return -1002;
  
  	if (SrcSize < 2)
  		return -1003;
  
  	if ((nWidth > 0xFFFF) || (nHeight > 0xFFFF))
  		return -1004;
  
  	glyphFlags = pSrcData[0];
  	seqNumber = pSrcData[1];
  	offset += 2;
  
  	if (seqNumber != clear->seqNumber)
  		return -1005;
  
  	clear->seqNumber = (seqNumber + 1) % 256;
  
  	if (glyphFlags & CLEARCODEC_FLAG_CACHE_RESET)
  	{
  		clear->VBarStorageCursor = 0;
  		clear->ShortVBarStorageCursor = 0;
  	}
  
  	if ((glyphFlags & CLEARCODEC_FLAG_GLYPH_HIT) && !(glyphFlags & CLEARCODEC_FLAG_GLYPH_INDEX))
  		return -1006;
  
  	if (glyphFlags & CLEARCODEC_FLAG_GLYPH_INDEX)
  	{
  		if ((nWidth * nHeight) > (1024 * 1024))
  			return -1007;
  
  		if (SrcSize < 4)
  			return -1008;
  
  		glyphIndex = *((UINT16*) &pSrcData[2]);
  		offset += 2;
  
  		if (glyphIndex >= 4000)
  			return -1009;
  
  		if (glyphFlags & CLEARCODEC_FLAG_GLYPH_HIT)
  		{
  			glyphEntry = &(clear->GlyphCache[glyphIndex]);
  			glyphData = (BYTE*) glyphEntry->pixels;
  
  			if (!glyphData)
  				return -1010;
  
  			if ((nWidth * nHeight) > (int) glyphEntry->count)
  				return -1011;
  
  			nSrcStep = nWidth * 4;
  			pSrcPixel8 = glyphData;
  			pDstPixel8 = &pDstData[(nYDst * nDstStep) + (nXDst * 4)];
  
  			for (y = 0; y < (UINT32) nHeight; y++)
  			{
  				CopyMemory(pDstPixel8, pSrcPixel8, nSrcStep);
  				pSrcPixel8 += nSrcStep;
  				pDstPixel8 += nDstStep;
  			}
  
  			return 1; /* Finish */
  		}
  	}
  
  	/* Read composition payload header parameters */
  
  	if ((SrcSize - offset) < 12)
  		return -1012;
  
  	residualByteCount = *((UINT32*) &pSrcData[offset]);
  	bandsByteCount = *((UINT32*) &pSrcData[offset + 4]);
  	subcodecByteCount = *((UINT32*) &pSrcData[offset + 8]);
  	offset += 12;
  
  	//DEBUG_MSG("residualByteCount: %d bandsByteCount: %d subcodecByteCount: %d\n",
  	//		residualByteCount, bandsByteCount, subcodecByteCount);
  
  	if (residualByteCount > 0)
  	{
  		UINT32 suboffset;
  		BYTE* residualData;
  
  		if ((SrcSize - offset) < residualByteCount)
  			return -1013;
  
  		suboffset = 0;
  		residualData = &pSrcData[offset];
  
  		if ((nWidth * nHeight * 4) > (int) clear->TempSize)
  		{
  			clear->TempSize = (nWidth * nHeight * 4);
  			clear->TempBuffer = (BYTE*) realloc(clear->TempBuffer, clear->TempSize);
  
  			if (!clear->TempBuffer)
  				return -1014;
  		}
  
  		pixelIndex = 0;
  		pixelCount = nWidth * nHeight;
  		pDstPixel32 = (UINT32*) clear->TempBuffer;
  
  		while (suboffset < residualByteCount)
  		{
  			if ((residualByteCount - suboffset) < 4)
  				return -1015;
  
  			color = RGB32(residualData[suboffset + 2], residualData[suboffset + 1], residualData[suboffset + 0]);
  			suboffset += 3;
  
  			runLengthFactor = (UINT32) residualData[suboffset];
  			suboffset++;
  
  			if (runLengthFactor >= 0xFF)
  			{
  				if ((residualByteCount - suboffset) < 2)
  					return -1016;
  
  				runLengthFactor = (UINT32) *((UINT16*) &residualData[suboffset]);
  				suboffset += 2;
  
  				if (runLengthFactor >= 0xFFFF)
  				{
  					if ((residualByteCount - suboffset) < 4)
  						return -1017;
  
  					runLengthFactor = *((UINT32*) &residualData[suboffset]);
  					suboffset += 4;
  				}
  			}
  
  			if ((pixelIndex + runLengthFactor) > pixelCount)
  				return -1018;
  
  			for (i = 0; i < runLengthFactor; i++)
  			{
  				*pDstPixel32 = color;
  				pDstPixel32++;
  			}
  
  			pixelIndex += runLengthFactor;
  		}
  
  		nSrcStep = nWidth * 4;
  		pSrcPixel8 = clear->TempBuffer;
  		pDstPixel8 = &pDstData[(nYDst * nDstStep) + (nXDst * 4)];
  
  		if (pixelIndex != pixelCount)
  			return -1019;
  
  		for (y = 0; y < (UINT32) nHeight; y++)
  		{
  			CopyMemory(pDstPixel8, pSrcPixel8, nSrcStep);
  			pSrcPixel8 += nSrcStep;
  			pDstPixel8 += nDstStep;
  		}
  
  		offset += residualByteCount;
  	}
  
  	if (bandsByteCount > 0)
  	{
  		BYTE* bandsData;
  		UINT32 suboffset;
  
  		if ((SrcSize - offset) < bandsByteCount)
  			return -1020;
  
  		suboffset = 0;
  		bandsData = &pSrcData[offset];
  
  		while (suboffset < bandsByteCount)
  		{
  			UINT16 xStart;
  			UINT16 xEnd;
  			UINT16 yStart;
  			UINT16 yEnd;
  			BYTE* vBar;
  			BOOL vBarUpdate;
  			UINT32 colorBkg;
  			UINT16 vBarHeader;
  			UINT16 vBarIndex;
  			UINT16 vBarYOn;
  			UINT16 vBarYOff;
  			UINT32 vBarCount;
  			UINT32 vBarHeight;
  			UINT32 vBarPixelCount;
  			UINT32 vBarShortPixelCount;
  			CLEAR_VBAR_ENTRY* vBarEntry;
  			CLEAR_VBAR_ENTRY* vBarShortEntry;
  
  			if ((bandsByteCount - suboffset) < 11)
  				return -1021;
  
  			xStart = *((UINT16*) &bandsData[suboffset]);
  			xEnd = *((UINT16*) &bandsData[suboffset + 2]);
  			yStart = *((UINT16*) &bandsData[suboffset + 4]);
  			yEnd = *((UINT16*) &bandsData[suboffset + 6]);
  			suboffset += 8;
  
  			colorBkg = RGB32(bandsData[suboffset + 2], bandsData[suboffset + 1], bandsData[suboffset + 0]);
  			suboffset += 3;
  
  			if (xEnd < xStart)
  				return -1022;
  
  			if (yEnd < yStart)
  				return -1023;
  
  			vBarCount = (xEnd - xStart) + 1;
  
  			for (i = 0; i < vBarCount; i++)
  			{
  				vBarUpdate = FALSE;
  				vBar = &bandsData[suboffset];
  
  				if ((bandsByteCount - suboffset) < 2)
  					return -1024;
  
  				vBarHeader = *((UINT16*) &vBar[0]);
  				suboffset += 2;
  
  				vBarHeight = (yEnd - yStart + 1);
  
  				if (vBarHeight > 52)
  					return -1025;
  
  				if ((vBarHeader & 0xC000) == 0x4000) /* SHORT_VBAR_CACHE_HIT */
  				{
  					vBarIndex = (vBarHeader & 0x3FFF);
  
  					if (vBarIndex >= 16384)
  						return -1026;
  
  					if ((bandsByteCount - suboffset) < 1)
  						return -1027;
  
  					vBarYOn = vBar[2];
  					suboffset += 1;
  
  					vBarShortEntry = &(clear->ShortVBarStorage[vBarIndex]);
  
  					if (!vBarShortEntry)
  						return -1028;
  
  					vBarShortPixelCount = vBarShortEntry->count;
  
  					vBarUpdate = TRUE;
  				}
  				else if ((vBarHeader & 0xC000) == 0x0000) /* SHORT_VBAR_CACHE_MISS */
  				{
  					vBarYOn = (vBarHeader & 0xFF);
  					vBarYOff = ((vBarHeader >> 8) & 0x3F);
  
  					if (vBarYOff < vBarYOn)
  						return -1029;
  
  					pSrcPixel8 = &vBar[2];
  					vBarShortPixelCount = (vBarYOff - vBarYOn);
  
  					if (vBarShortPixelCount > 52)
  						return -1030;
  
  					if ((bandsByteCount - suboffset) < (vBarShortPixelCount * 3))
  						return -1031;
  
  					if (clear->ShortVBarStorageCursor >= 16384)
  						return -1032;
  
  					vBarShortEntry = &(clear->ShortVBarStorage[clear->ShortVBarStorageCursor]);
  
  					vBarShortEntry->count = vBarShortPixelCount;
  
  					if (vBarShortEntry->count > vBarShortEntry->size)
  					{
  						vBarShortEntry->size = vBarShortEntry->count;
  
  						if (!vBarShortEntry->pixels)
  							vBarShortEntry->pixels = (UINT32*) malloc(vBarShortEntry->count * 4);
  						else
  							vBarShortEntry->pixels = (UINT32*) realloc(vBarShortEntry->pixels, vBarShortEntry->count * 4);
  					}
  
  					if (!vBarShortEntry->pixels && vBarShortEntry->size)
  						return -1033;
  
  					pDstPixel32 = vBarShortEntry->pixels;
  
  					for (y = 0; y < vBarShortPixelCount; y++)
  					{
  						*pDstPixel32 = RGB32(pSrcPixel8[2], pSrcPixel8[1], pSrcPixel8[0]);
  						pSrcPixel8 += 3;
  						pDstPixel32++;
  					}
  
  					suboffset += (vBarShortPixelCount * 3);
  
  					vBarShortEntry->count = vBarShortPixelCount;
  					clear->ShortVBarStorageCursor = (clear->ShortVBarStorageCursor + 1) % 16384;
  
  					vBarUpdate = TRUE;
  				}
  				else if ((vBarHeader & 0x8000) == 0x8000) /* VBAR_CACHE_HIT */
  				{
  					vBarIndex = (vBarHeader & 0x7FFF);
  
  					if (vBarIndex >= 32768)
  						return -1034;
  
  					vBarEntry = &(clear->VBarStorage[vBarIndex]);
  				}
  				else
  				{
  					return -1035; /* invalid vBarHeader */
  				}
  
  				if (vBarUpdate)
  				{
  					if (clear->VBarStorageCursor >= 32768)
  						return -1036;
  
  					vBarEntry = &(clear->VBarStorage[clear->VBarStorageCursor]);
  
  					vBarPixelCount = vBarHeight;
  					vBarEntry->count = vBarPixelCount;
  
  					if (vBarEntry->count > vBarEntry->size)
  					{
  						vBarEntry->size = vBarEntry->count;
  
  						if (!vBarEntry->pixels)
  							vBarEntry->pixels = (UINT32*) malloc(vBarEntry->count * 4);
  						else
  							vBarEntry->pixels = (UINT32*) realloc(vBarEntry->pixels, vBarEntry->count * 4);
  					}
  
  					if (!vBarEntry->pixels && vBarEntry->size)
  						return -1037;
  
  					pDstPixel32 = vBarEntry->pixels;
  
  					/* if (y < vBarYOn), use colorBkg */
  
  					y = 0;
  					count = vBarYOn;
  
  					if ((y + count) > vBarPixelCount)
  						count = (vBarPixelCount > y) ? (vBarPixelCount - y) : 0;
  
  					while (count--)
  					{
  						*pDstPixel32 = colorBkg;
  						pDstPixel32++;
  					}
  
  					/*
  					 * if ((y >= vBarYOn) && (y < (vBarYOn + vBarShortPixelCount))),
  					 * use vBarShortPixels at index (y - shortVBarYOn)
  					 */
  
  					y = vBarYOn;
  					count = vBarShortPixelCount;
  
  					if ((y + count) > vBarPixelCount)
  						count = (vBarPixelCount > y) ? (vBarPixelCount - y) : 0;
  
  					pSrcPixel32 = &(vBarShortEntry->pixels[y - vBarYOn]);
  					CopyMemory(pDstPixel32, pSrcPixel32, count * 4);
  					pDstPixel32 += count;
  
  					/* if (y >= (vBarYOn + vBarShortPixelCount)), use colorBkg */
  
  					y = vBarYOn + vBarShortPixelCount;
  					count = (vBarPixelCount > y) ? (vBarPixelCount - y) : 0;
  
  					while (count--)
  					{
  						*pDstPixel32 = colorBkg;
  						pDstPixel32++;
  					}
  
  					vBarEntry->count = vBarPixelCount;
  					clear->VBarStorageCursor = (clear->VBarStorageCursor + 1) % 32768;
  				}
  
  				nXDstRel = nXDst + xStart;
  				nYDstRel = nYDst + yStart;
  
  				pSrcPixel32 = vBarEntry->pixels;
  				pDstPixel8 = &pDstData[(nYDstRel * nDstStep) + ((nXDstRel + i) * 4)];
  
  				count = yEnd - yStart + 1;
  
  				if (vBarEntry->count != count)
  					return -1038;
  
  				for (y = 0; y < count; y++)
  				{
  					*((UINT32*) pDstPixel8) = *pSrcPixel32;
  					pDstPixel8 += nDstStep;
  					pSrcPixel32++;
  				}
  			}
  		}
  
  		offset += bandsByteCount;
  	}
  
  	if (subcodecByteCount > 0)
  	{
  		UINT16 xStart;
  		UINT16 yStart;
  		UINT16 width;
  		UINT16 height;
  		BYTE* bitmapData;
  		UINT32 bitmapDataOffset;
  		UINT32 bitmapDataByteCount;
  		BYTE subcodecId;
  		BYTE* subcodecs;
  		UINT32 suboffset;
  
  		if ((SrcSize - offset) < subcodecByteCount)
  			return -1039;
  
  		suboffset = 0;
  		subcodecs = &pSrcData[offset];
  
  		while (suboffset < subcodecByteCount)
  		{
  			if ((subcodecByteCount - suboffset) < 13)
  				return -1040;
  
  			xStart = *((UINT16*) &subcodecs[suboffset]);
  			yStart = *((UINT16*) &subcodecs[suboffset + 2]);
  			width = *((UINT16*) &subcodecs[suboffset + 4]);
  			height = *((UINT16*) &subcodecs[suboffset + 6]);
  			bitmapDataByteCount = *((UINT32*) &subcodecs[suboffset + 8]);
  			subcodecId = subcodecs[suboffset + 12];
  			suboffset += 13;
  
  			//DEBUG_MSG("bitmapDataByteCount: %d subcodecByteCount: %d suboffset: %d subCodecId: %d\n",
  			//		bitmapDataByteCount, subcodecByteCount, suboffset, subcodecId);
  
  			if ((subcodecByteCount - suboffset) < bitmapDataByteCount)
  				return -1041;
  
  			nXDstRel = nXDst + xStart;
  			nYDstRel = nYDst + yStart;
  
  			if (width > nWidth)
  				return -1042;
  
  			if (height > nHeight)
  				return -1043;
  
  			if (((UINT32) (width * height * 4)) > clear->TempSize)
  			{
  				clear->TempSize = (width * height * 4);
  				clear->TempBuffer = (BYTE*) realloc(clear->TempBuffer, clear->TempSize);
  
  				if (!clear->TempBuffer)
  					return -1044;
  			}
  
  			bitmapData = &subcodecs[suboffset];
  
  			if (subcodecId == 0) /* Uncompressed */
  			{
  				if (bitmapDataByteCount != (width * height * 3))
  					return -1045;
  
  				pSrcPixel8 = bitmapData;
  
  				for (y = 0; y < height; y++)
  				{
  					pDstPixel32 = (UINT32*) &pDstData[((nYDstRel + y) * nDstStep) + (nXDstRel * 4)];
  
  					for (x = 0; x < width; x++)
  					{
  						*pDstPixel32 = RGB32(pSrcPixel8[2], pSrcPixel8[1], pSrcPixel8[0]);
  						pSrcPixel8 += 3;
  						pDstPixel32++;
  					}
  				}
  			}
  			else if (subcodecId == 1) /* NSCodec */
  			{
  				if (nsc_process_message(clear->nsc, 32, width, height, bitmapData, bitmapDataByteCount) < 0)
  					return -1046;
  
  				nSrcStep = width * 4;
  				pSrcPixel8 = clear->nsc->BitmapData;
  				pDstPixel8 = &pDstData[(nYDstRel * nDstStep) + (nXDstRel * 4)];
  
  				for (y = 0; y < height; y++)
  				{
  					CopyMemory(pDstPixel8, pSrcPixel8, nSrcStep);
  					pSrcPixel8 += nSrcStep;
  					pDstPixel8 += nDstStep;
  				}
  			}
  			else if (subcodecId == 2) /* CLEARCODEC_SUBCODEC_RLEX */
  			{
  				UINT32 numBits;
  				BYTE startIndex;
  				BYTE stopIndex;
  				BYTE suiteIndex;
  				BYTE suiteDepth;
  				BYTE paletteCount;
  				UINT32 palette[128];
  
  				paletteCount = bitmapData[0];
  				pSrcPixel8 = &bitmapData[1];
  				bitmapDataOffset = 1 + (paletteCount * 3);
  
  				if (paletteCount > 127)
  					return -1047;
  
  				for (i = 0; i < paletteCount; i++)
  				{
  					palette[i] = RGB32(pSrcPixel8[2], pSrcPixel8[1], pSrcPixel8[0]);
  					pSrcPixel8 += 3;
  				}
  
  				pixelIndex = 0;
  				pixelCount = width * height;
  				pDstPixel32 = (UINT32*) clear->TempBuffer;
  
  				numBits = CLEAR_LOG2_FLOOR[paletteCount - 1] + 1;
  
  				while (bitmapDataOffset < bitmapDataByteCount)
  				{
  					if ((bitmapDataByteCount - bitmapDataOffset) < 2)
  						return -1048;
  
  					stopIndex = bitmapData[bitmapDataOffset] & CLEAR_8BIT_MASKS[numBits];
  					suiteDepth = (bitmapData[bitmapDataOffset] >> numBits) & CLEAR_8BIT_MASKS[(8 - numBits)];
  					startIndex = stopIndex - suiteDepth;
  					bitmapDataOffset++;
  
  					runLengthFactor = (UINT32) bitmapData[bitmapDataOffset];
  					bitmapDataOffset++;
  
  					if (runLengthFactor >= 0xFF)
  					{
  						if ((bitmapDataByteCount - bitmapDataOffset) < 2)
  							return -1049;
  
  						runLengthFactor = (UINT32) *((UINT16*) &bitmapData[bitmapDataOffset]);
  						bitmapDataOffset += 2;
  
  						if (runLengthFactor >= 0xFFFF)
  						{
  							if ((bitmapDataByteCount - bitmapDataOffset) < 4)
  								return -1050;
  
  							runLengthFactor = *((UINT32*) &bitmapData[bitmapDataOffset]);
  							bitmapDataOffset += 4;
  						}
  					}
  
  					if (startIndex >= paletteCount)
  						return -1051;
  
  					if (stopIndex >= paletteCount)
  						return -1052;
  
  					suiteIndex = startIndex;
  					color = palette[suiteIndex];
  
  					if ((pixelIndex + runLengthFactor) > pixelCount)
  						return -1053;
  
  					for (i = 0; i < runLengthFactor; i++)
  					{
  						*pDstPixel32 = color;
  						pDstPixel32++;
  					}
  
  					pixelIndex += runLengthFactor;
  
  					if ((pixelIndex + (suiteDepth + 1)) > pixelCount)
  						return -1054;
  
  					for (i = 0; i <= suiteDepth; i++)
  					{
  						*pDstPixel32 = palette[suiteIndex++];
  						pDstPixel32++;
  					}
  
  					pixelIndex += (suiteDepth + 1);
  				}
  
  				nSrcStep = width * 4;
  				pSrcPixel8 = clear->TempBuffer;
  				pDstPixel8 = &pDstData[(nYDstRel * nDstStep) + (nXDstRel * 4)];
  
  				if (pixelIndex != pixelCount)
  					return -1055;
  
  				for (y = 0; y < height; y++)
  				{
  					CopyMemory(pDstPixel8, pSrcPixel8, nSrcStep);
  					pSrcPixel8 += nSrcStep;
  					pDstPixel8 += nDstStep;
  					pixelCount -= count;
  				}
  			}
  			else
  			{
  				return -1056;
  			}
  
  			suboffset += bitmapDataByteCount;
  		}
  
  		offset += subcodecByteCount;
  	}
  
  	if (glyphFlags & CLEARCODEC_FLAG_GLYPH_INDEX)
  	{
  		glyphEntry = &(clear->GlyphCache[glyphIndex]);
  
  		glyphEntry->count = nWidth * nHeight;
  
  		if (glyphEntry->count > glyphEntry->size)
  		{
  			glyphEntry->size = glyphEntry->count;
  
  			if (!glyphEntry->pixels)
  				glyphEntry->pixels = (UINT32*) malloc(glyphEntry->size * 4);
  			else
  				glyphEntry->pixels = (UINT32*) realloc(glyphEntry->pixels, glyphEntry->size * 4);
  		}
  
  		if (!glyphEntry->pixels)
  			return -1057;
  
  		glyphData = (BYTE*) glyphEntry->pixels;
  
  		nSrcStep = nWidth * 4;
  		pDstPixel8 = glyphData;
  		pSrcPixel8 = &pDstData[(nYDst * nDstStep) + (nXDst * 4)];
  
  		for (y = 0; y < (UINT32) nHeight; y++)
  		{
  			CopyMemory(pDstPixel8, pSrcPixel8, nSrcStep);
  			pDstPixel8 += nSrcStep;
  			pSrcPixel8 += nDstStep;
  		}
  	}
  
  	if (offset != SrcSize)
  		return -1058;
  
  	return 1;
  }
  
  int clear_compress(CLEAR_CONTEXT* clear, BYTE* pSrcData, UINT32 SrcSize, BYTE** ppDstData, UINT32* pDstSize)
  {
  	return 1;
  }
  
  void clear_context_reset(CLEAR_CONTEXT* clear)
  {
  	clear->seqNumber = 0;
  	clear->VBarStorageCursor = 0;
  	clear->ShortVBarStorageCursor = 0;
  }
  
  CLEAR_CONTEXT* clear_context_new(BOOL Compressor)
  {
  	CLEAR_CONTEXT* clear;
  
  	clear = (CLEAR_CONTEXT*) calloc(1, sizeof(CLEAR_CONTEXT));
  
  	if (clear)
  	{
  		clear->Compressor = Compressor;
  
  		clear->nsc = nsc_context_new();
  
  		if (!clear->nsc)
  			return NULL;
  
  		nsc_context_set_pixel_format(clear->nsc, RDP_PIXEL_FORMAT_R8G8B8);
  
  		clear->TempSize = 512 * 512 * 4;
  		clear->TempBuffer = (BYTE*) malloc(clear->TempSize);
  
  		clear_context_reset(clear);
  	}
  
  	return clear;
  }
  
  void clear_context_free(CLEAR_CONTEXT* clear)
  {
  	int i;
  
  	if (!clear)
  		return;
  
  	nsc_context_free(clear->nsc);
  
  	free(clear->TempBuffer);
  
  	for (i = 0; i < 4000; i++)
  		free(clear->GlyphCache[i].pixels);
  
  	for (i = 0; i < 32768; i++)
  		free(clear->VBarStorage[i].pixels);
  
  	for (i = 0; i < 16384; i++)
  		free(clear->ShortVBarStorage[i].pixels);
  
  	free(clear);
  }
  
  