mmplugins/imagingplugins/codecs/GifCodec/GIFcodec.cpp
changeset 0 40261b775718
child 7 94dbab0a2133
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mmplugins/imagingplugins/codecs/GifCodec/GIFcodec.cpp	Tue Feb 02 01:56:55 2010 +0200
@@ -0,0 +1,1662 @@
+// Copyright (c) 1997-2009 Nokia Corporation and/or its subsidiary(-ies).
+// All rights reserved.
+// This component and the accompanying materials are made available
+// under the terms of "Eclipse Public License v1.0"
+// which accompanies this distribution, and is available
+// at the URL "http://www.eclipse.org/legal/epl-v10.html".
+//
+// Initial Contributors:
+// Nokia Corporation - initial contribution.
+//
+// Contributors:
+//
+// Description:
+// Licensed under US Patent No 4,558,302 and foreign counterparts
+// 
+//
+
+// CGifWriteCodec::TableEntry() is based on compress_byte() from wrgif.c
+// in the IJG V6 code, Copyright (C) 1991-1997, Thomas G. Lane.
+
+#include <fbs.h>
+#include "GIFcodec.h"
+#include "rawimageprocessor.h"
+
+const TInt KPass2StartLine = 4;
+const TInt KPass3StartLine = 2;
+const TInt KPass4StartLine = 1;
+const TInt KPass1YPosIncrement = 8;
+const TInt KPass2YPosIncrement = 8;
+const TInt KPass3YPosIncrement = 4;
+const TInt KPass4YPosIncrement = 2;
+const TInt KPass1LineRepeat = 7;
+const TInt KPass2LineRepeat = 3;
+const TInt KPass3LineRepeat = 1;
+const TInt KPass4LineRepeat = 0;
+const TUint KLZWLimit = 20000;
+const TInt KSetCommentsLimit = 64;
+const TUint16 KTranspColIdxNotPresent = 0xFFFF;
+
+
+// CGifReadCodec
+CGifReadCodec::CGifReadCodec(TRgb* aGlobalPalette,TInt aBackgroundColorIndex, TSize aScreenSize,TBool aFastDecode):
+	iBackgroundColorIndex(aBackgroundColorIndex),
+	iScreenSize(aScreenSize),
+	iGlobalPalette(aGlobalPalette),
+	iFastDecode(aFastDecode)
+	{
+	}
+
+CGifReadCodec::~CGifReadCodec()
+	{
+	iComment.ResetAndDestroy();
+    delete [] iPrefixIndex;
+	delete [] iSuffixCode;
+	delete [] iOutputString;
+	delete [] i64KPalette;
+	delete [] iPixelBuffer;
+	delete [] iMaskBuffer;
+	}
+
+CGifReadCodec* CGifReadCodec::NewL(TRgb* aGlobalPalette,TInt aBackgroundColorIndex, TSize aScreenSize,TBool aFastDecode)
+	{
+	CGifReadCodec* self = new(ELeave) CGifReadCodec(aGlobalPalette, aBackgroundColorIndex, aScreenSize, aFastDecode);
+	CleanupStack::PushL(self);
+
+    self->ConstructL();
+
+	CleanupStack::Pop(self); 
+	return self;
+	}
+
+void CGifReadCodec::ConstructL()
+    {
+    CImageMaskProcessorReadCodec::ConstructL();
+    
+	iPrefixIndex    = new (ELeave) TInt16[KGifConversionTableSize +1];
+	iSuffixCode     = new (ELeave) TUint8 [KGifConversionTableSize+1];
+	iOutputString   = new (ELeave) TUint8 [KGifConversionTableSize];
+	iPPos = &Pos();
+	iPixelBuffer = NULL;
+	iMaskBuffer = NULL;
+    }
+
+void CGifReadCodec::InitFrameHeader(TFrameInfo& aFrameSettings, CFrameImageData& aFrameImageData)
+	{
+	ASSERT(aFrameSettings.CurrentFrameState() == TFrameInfo::EFrameInfoUninitialised);
+	iFrameInfo = &aFrameSettings;
+	iFrameData = &aFrameImageData;
+	iFrameImageDesc = NULL;
+	iFrameImageControl = NULL;
+	iReadingOtherExtensionBlock=EFalse;
+	iReadingCommentExtensionBlock = EFalse;
+	iComment.ResetAndDestroy();
+	iCommentIndex = 0;
+	iFrameInfo->SetCurrentFrameState(TFrameInfo::EFrameInfoProcessingFrameHeader);
+	}
+
+TFrameState CGifReadCodec::ProcessFrameHeaderL(TBufPtr8& aData)
+	{	
+	iStartDataPtr = CONST_CAST(TUint8*,aData.Ptr());
+	iDataPtr = iStartDataPtr;
+	iDataPtrLimit = iStartDataPtr + aData.Length();
+
+	if (iFrameInfo->CurrentFrameState() == TFrameInfo::EFrameInfoProcessingFrame)
+		{
+		do	{
+			//we need the block length (iDataPtr[0]+1) + the first byte of the next block
+			//(used in the KGifTerminatorId evaluation below)
+			if((iDataPtr + iDataPtr[0] + 2)<iDataPtrLimit)
+				{// If there is enough data in the buffer to continue processing header info
+				iFrameLZWInfo->iCompressedBytes += iDataPtr[0] + 1;
+
+				// Shift the local buffer data pointer to point to the beginning of the next block
+				iDataPtr += iDataPtr[0] + 1;
+			}
+			else
+				{ // Else if there is not enough data in the buffer shift the 'aData' pointer
+				// to point to the degining of the unused data and return to the calling method
+				// so that the buffer can be refilled.
+				aData.Shift((iDataPtr - iStartDataPtr));
+				return EFrameIncomplete;
+				}
+			} while(iDataPtr[0]!=KGifFrameTerminatorId); //Continue until end of frame is reached
+
+		if(iDataPtr[1] == KGifTerminatorId)
+			{ // End of Image File
+			DoSaveCommentsL();
+			iFrameInfo->SetCurrentFrameState(TFrameInfo::EFrameInfoProcessingComplete);
+			return EFrameComplete;
+			}
+		else if ((iDataPtr[1] == KGifImageDescriptorId) || (iDataPtr[1] == KGifExtensionId))
+			{ // End of Frame
+			DoSaveCommentsL();
+			aData.Shift((iDataPtr - iStartDataPtr)+1); 
+			iFrameInfo->SetCurrentFrameState(TFrameInfo::EFrameInfoProcessingComplete);
+			return EFrameIncomplete;
+			}
+		else
+			{ // Unexpected end of data
+			return EUnexpectedEndOfData;
+			}
+		}
+
+	if (iFrameInfo->CurrentFrameState() == TFrameInfo::EFrameInfoProcessingFrameHeader)
+		{
+		TRAPD(err,DoProcessInfoL(iDataPtr,iDataPtrLimit));
+		if (err == KErrCompletion)
+			{
+			DoSaveCommentsL();
+			return EFrameComplete; // KGifTerminatorId found - no more images
+			}
+
+		if (err == KErrUnderflow)
+			{
+			TInt dataUsed = iDataPtr - iStartDataPtr;
+			aData.Shift(dataUsed);
+			TInt frameDataOffset = iFrameInfo->FrameDataOffset();
+			iFrameInfo->SetFrameDataOffset(frameDataOffset + dataUsed);
+			return EFrameIncomplete;
+			}
+
+		if (err!=KErrNone)
+			{
+			User::LeaveIfError(err); // A real error occured
+			}
+
+		if (iFrameImageDesc == NULL)
+			{
+			User::Leave(KErrCorrupt);
+			}
+
+		TInt frameDataOffset = iFrameInfo->FrameDataOffset();
+		iFrameInfo->SetFrameDataOffset(frameDataOffset + (iDataPtr - iStartDataPtr));
+		aData.Shift(iDataPtr - iStartDataPtr);
+
+		iFrameInfo->iFrameSizeInTwips.SetSize(0,0);
+		iFrameInfo->iDelay = (iFrameImageControl) ? iFrameImageControl->iDelayTimeInCentiseconds * KGifCentiSecondsToMicroSeconds : 0;
+		iFrameInfo->iFlags = TFrameInfo::EColor | TFrameInfo::ECanDither | TFrameInfo::EUsesFrameSizeInPixels;
+		if (iFrameImageControl)
+			{
+			if (iFrameImageControl->iTransparentColorIndex != KErrNotFound)
+				{
+				iFrameInfo->iFlags |= TFrameInfo::ETransparencyPossible;
+				if(iFrameImageDesc->iInterlaced)
+					iFrameInfo->iFlags |= TFrameInfo::EPartialDecodeInvalid;
+				}
+			switch (iFrameImageControl->iDisposalMethod)
+				{
+			case TGifImageControl::ELeaveInPlace:
+				iFrameInfo->iFlags |= TFrameInfo::ELeaveInPlace;
+				break;
+			case TGifImageControl::ERestoreToBackground:
+				iFrameInfo->iFlags |= TFrameInfo::ERestoreToBackground;
+				break;
+			case TGifImageControl::ERestoreToPrevious:
+				iFrameInfo->iFlags |= TFrameInfo::ERestoreToPrevious;
+				break;
+			case ENone:
+			default:
+				break;
+				};
+			}
+
+		iFrameInfo->SetCurrentFrameState(TFrameInfo::EFrameInfoProcessingFrame);
+		}
+
+	return EFrameIncomplete;
+	}
+
+TFrameState CGifReadCodec::ProcessFrameL(TBufPtr8& aSrc)
+	{
+	if ((iFrameSize.iWidth == 0) || (iFrameSize.iHeight == 0))
+		return EFrameComplete;
+
+	iPixRead = 0;
+
+	while (aSrc.Length() > 2 && !iComplete)
+		{
+		iDataPtr = aSrc.Ptr();
+		const TInt dataSize = iDataPtr[0];
+		iDataPtr++;
+		if (dataSize == 0 || dataSize >= aSrc.Length())
+		    {
+		    break;
+		    }
+		iDataPtrLimit = iDataPtr + dataSize;
+		DoProcessDataL();
+
+		aSrc.Shift(dataSize + 1);
+		}
+
+	TPoint& pos = Pos();
+	pos = *iPPos;
+	FlushPixBuffer(iLatestPixSize);
+	
+	if (iFastAccessMode) 
+		{
+		const TInt frameWidth = iFrameSize.iWidth;
+		TInt rowPixels = Min(frameWidth - pos.iX, iPixRead);
+		pos.iX += rowPixels;
+		iPixRead -= rowPixels;
+		if (pos.iX == frameWidth)
+			{
+			TInt rowCount = iPixRead/frameWidth+1;
+			pos.iY += rowCount;
+			iPixRead -= (rowCount-1) * frameWidth;
+			pos.iX = iPixRead;
+			}
+		iPixRead = 0;
+		}
+	
+	if (pos.iY >= (iFrameSize.iHeight + iFrameOffset.iY) || iComplete)
+		{
+		ImageProcessor()->FlushPixels();
+		CImageProcessor*const maskProc = MaskProcessor();
+		if (maskProc)
+			maskProc->FlushPixels();
+		pos = iFrameOffset;
+		
+		if(iGifImageControl && iGifImageControl->iTransparentColorIndex != KErrNotFound)
+			{
+			// reset the transparency index
+			if (iTranspColIdx != KTranspColIdxNotPresent)
+				{
+				const_cast<TRgb*>(&iPalette[iTranspColIdx])->SetAlpha(0xFF);
+				}
+			}
+		
+		return EFrameComplete;
+		}
+
+	return EFrameIncomplete;
+	}
+
+void CGifReadCodec::InitFrameL(TFrameInfo& aFrameInfo, CFrameImageData& aFrameImageData, TBool aDisableErrorDiffusion, CFbsBitmap& aDestination, CFbsBitmap* aDestinationMask)
+	{
+  	iFrameInfo = &aFrameInfo;
+  	iFrameData = &aFrameImageData;
+
+	//Make the first frame's size equal to the image size
+	if(CurrentFrame()==0)
+		{
+		iFrameSize = iFirstFrameSize;
+		iFrameOffset = iFirstFrameCoords.iTl;
+		}
+	else
+		{
+		iFrameSize = iFrameInfo->iOverallSizeInPixels;
+		iFrameOffset = TPoint(0,0);
+		}
+	iFrameCoords = iFrameInfo->iFrameCoordsInPixels;
+
+	// If the width or height is zero return. A similar test in ProcessFrameL() will complete the image
+	if ((iFrameSize.iWidth == 0) || (iFrameSize.iHeight == 0))
+		{
+		return;
+		}
+
+	if(iPixelBuffer == NULL || CurrentFrame() == 0)
+		{
+		iPixBufferSize = iFrameSize.iWidth * 8;//allocate buffer for first 8 lines
+		if (iPixBufferSize > KPixelBufMaxSize) 
+			{
+			iPixBufferSize = KPixelBufMaxSize;
+			}
+		if (aDestinationMask != NULL)
+			{
+			iPixBufferSize /= 2;//reserve space for mask
+			}
+		delete[] iPixelBuffer;
+		iPixelBuffer = new (ELeave) TUint32 [iPixBufferSize];
+		}
+
+	// Extract the image descriptor and control blocks.
+	iGifImageDesc = NULL;
+	iGifLZWInfo = NULL;
+	iGifImageControl = NULL;
+	iGifColorTable = NULL;
+
+	TInt frameDataCount = iFrameData->FrameDataCount();
+	for (TInt frameDataIndex = 0 ; frameDataIndex<frameDataCount ; frameDataIndex++)
+		{
+		TFrameDataBlock* frameData = iFrameData->GetFrameData(frameDataIndex);
+		if (frameData->DataType() == KGIFImageDescriptorUid)
+			{
+			iGifImageDesc = STATIC_CAST(TGifImageDescriptor*, frameData);
+			}
+		else if(frameData->DataType() == KGIFColorTableUid)
+			{
+			iGifColorTable = STATIC_CAST(TGifColorTable*, frameData);
+			}
+		else if(frameData->DataType() == KGIFLZWInfoUid)
+			{
+			iGifLZWInfo = STATIC_CAST(TGifLZWInfo*, frameData);
+			}
+		else if(frameData->DataType() == KGIFImageControlUid)
+			{
+			iGifImageControl = STATIC_CAST(TGifImageControl*, frameData);
+			}
+		}
+	iTranspColIdx = (iGifImageControl) ? iGifImageControl->iTransparentColorIndex : KTranspColIdxNotPresent;
+
+	// Set decode info
+	iPass = 1;
+	iYPosIncrement = KPass1YPosIncrement;
+	iBitBuffer = 0;
+	iBitBuffSize = 0;
+	iFirstChar = 0;
+	iPreviousCode = -1;
+	iComplete = EFalse;
+
+	ASSERT(iGifImageDesc);
+	ASSERT(iGifLZWInfo);
+
+	// Set palette to use
+	if(iGifImageDesc && iGifImageDesc->iLocalColorMap)
+		{
+		//Use of a frame palette was requested but was not found
+		if(iGifColorTable == NULL)
+			{
+			User::Leave(KErrCorrupt);
+			}
+		iPalette = iGifColorTable->iPalette;
+		}
+	else
+		{
+		iPalette = iGlobalPalette;
+		}
+
+	// Set table.Check for iClearCode value between 0 and 4096.
+	iClearCode = (1 << (iGifLZWInfo->iInitialCodeLength - 1));
+	if((iClearCode < 0) || (iClearCode > KGifConversionTableSize))
+		{
+		User::Leave(KErrCorrupt);
+		}
+	iEoiCode = iClearCode + 1;
+	for (TInt singleByteCodes = 0; singleByteCodes < iClearCode; singleByteCodes++)
+		{
+		iSuffixCode[singleByteCodes] = STATIC_CAST(TUint8,singleByteCodes);
+		}
+
+	TInt prefixLength = (KGifConversionTableSize + 1) * sizeof(TInt16);
+	Mem::Fill(iPrefixIndex, prefixLength, TChar(static_cast<TUint>(-1)));
+
+	iNextFree = ResetTableL();
+
+	iReductionFactor = 0;
+
+	CImageProcessor* imageProc = NULL;
+
+	const TSize destinationSize(aDestination.SizeInPixels());
+	
+	if(iUseFrameSizeInPixels)
+		{
+		iReductionFactor = ReductionFactor(iFrameInfo->iFrameSizeInPixels,destinationSize);
+		}
+	else
+		{
+		iReductionFactor = ReductionFactor(iFrameInfo->iOverallSizeInPixels,destinationSize);
+		}
+
+    const TDisplayMode destMode = aDestination.DisplayMode();
+    
+    iFast64kMode = (iFastDecode &&
+                    destMode == EColor64K && 
+                    iReductionFactor == 0 && 
+                    !iGifImageDesc->iInterlaced
+                    );
+                    
+    if (iFast64kMode && i64KPalette==NULL)
+        {
+        i64KPalette = new (ELeave) T64KPixel[KGifColorTableMaxEntries];
+        Mem::FillZ(i64KPalette, KGifColorTableMaxEntries*sizeof(T64KPixel) );
+        }
+        
+	
+	if (!iGifImageDesc->iInterlaced && iReductionFactor==0 &&
+	        (iFast64kMode || destMode == EColor16M || destMode == EColor16MU || destMode == EColor16MA) )
+	    {
+	    if (destMode == EColor16M) 
+	    	{
+	    	imageProc   = CRawImageUtilProcessor::NewL();
+	    	}
+		else
+			{
+    		imageProc   = CRawImageProcessor::NewL();
+			}
+	    }
+    
+    if (iFast64kMode)
+        {
+		// calculate fast 64K conversion palette		
+        TInt idx = 0;
+        do
+            {
+            i64KPalette[idx] = iPalette[idx]._Color64K();
+            } 
+            while (++idx < KGifColorTableMaxEntries);
+            
+        iPalette = reinterpret_cast<const TRgb*>( i64KPalette );
+        }
+        
+    if (imageProc == NULL)
+        {
+     	imageProc = ImageProcessorUtility::NewImageProcessorL(aDestination, iReductionFactor, iFast64kMode? EColor64K:ERgb, aDisableErrorDiffusion);    
+        }
+
+	SetImageProcessor(imageProc);
+	iImgProc = imageProc;
+
+	iPositionOffset = TPoint(iFrameCoords.iTl.iX >> iReductionFactor,iFrameCoords.iTl.iY >> iReductionFactor);
+
+	TRect imageRegion(iPositionOffset + iFrameOffset,iPositionOffset + iFrameOffset + iFrameSize);
+	imageProc->PrepareL(aDestination,imageRegion);
+	imageProc->SetPos(iPositionOffset + iFrameOffset);
+	SetPos(iFrameOffset);
+
+	TInt lineLength	= (TDisplayModeUtils::NumDisplayModeBitsPerPixel( aDestination.DisplayMode() ) * aDestination.SizeInPixels().iWidth) >> 3;
+
+	
+	iFastAccessMode = (iReductionFactor == 0 && 
+						!iGifImageDesc->iInterlaced && 
+						imageRegion.Size() == aDestination.SizeInPixels() && 
+						lineLength == aDestination.ScanLineLength(aDestination.SizeInPixels().iWidth, aDestination.DisplayMode())
+						); // for direct access to bitmap buffer line length must be aligned to 4 bytes boundary
+
+	
+	if (iGifImageDesc->iInterlaced)
+		{
+		imageProc->SetYPosIncrement(iYPosIncrement);
+		if(!iGifImageControl || (iGifImageControl->iTransparentColorIndex==KErrNotFound))
+			{
+			imageProc->SetLineRepeat(KPass1LineRepeat);
+			}
+		}
+
+	CImageProcessor* maskProc = NULL;
+	SetMaskProcessor(NULL);
+	iMaskProc = NULL;
+
+	if(aDestinationMask != NULL)
+		{
+
+		ASSERT(aDestinationMask->SizeInPixels() == aDestination.SizeInPixels());
+			// this should be trapped at CImageDecoder::Convert()
+
+		if (iGifImageControl && (iGifImageControl->iTransparentColorIndex != KErrNotFound) && aDestinationMask->Handle())
+			{
+			ASSERT(MaskProcessor()==NULL);
+
+			if (iMaskBuffer == NULL || CurrentFrame() == 0)
+			    {
+			    delete [] iMaskBuffer; 
+				iMaskBuffer     = new (ELeave) TUint32 [iPixBufferSize];
+			    }
+		
+			iOpaqueMask	= 0xFF;// default for 256 mask
+			//Create a mask processor  and disable error diffusion
+			if (iGifImageDesc->iInterlaced || iReductionFactor > 0)
+				{
+				maskProc = ImageProcessorUtility::NewImageProcessorL(*aDestinationMask, iReductionFactor, EGray2, ETrue);	
+				}
+			else
+				{
+				// use optimized processor for non interlaced mask
+				maskProc = CRawImageUtilProcessor::NewL();
+				if(aDestinationMask->DisplayMode() == EGray2)
+					{
+					iOpaqueMask = 1;
+					}
+				}
+			SetMaskProcessor(maskProc);
+			iMaskProc = maskProc;
+			maskProc->PrepareL(*aDestinationMask,imageRegion);
+			if (iGifImageDesc->iInterlaced)
+				{
+				maskProc->SetYPosIncrement(iYPosIncrement);
+				}
+			// fill mask with black, so by default unknown parts don't draw
+			ClearBitmapL(*aDestinationMask,KRgbBlack);
+			maskProc->SetPos(iPositionOffset + iFrameOffset);
+
+			lineLength	= (TDisplayModeUtils::NumDisplayModeBitsPerPixel( aDestinationMask->DisplayMode() ) * aDestinationMask->SizeInPixels().iWidth) >> 3;
+			
+			iFastAccessMode = iFastAccessMode && lineLength == aDestinationMask->ScanLineLength(aDestinationMask->SizeInPixels().iWidth, aDestinationMask->DisplayMode()); // for direct access 
+			// to bitmap buffer line length must be aligned to 4 bytes boundary
+				
+			}
+		}
+    else
+		{
+		if(destMode == EColor16MA && iGifImageControl && iGifImageControl->iTransparentColorIndex != KErrNotFound)
+			{
+			if (iTranspColIdx != KTranspColIdxNotPresent)
+				{
+				const_cast<TRgb*>(&iPalette[iTranspColIdx])->SetAlpha(0);
+				}
+			}
+		delete [] iMaskBuffer;
+		iMaskBuffer = NULL;
+		}
+
+	if ( iGifImageControl && (iGifImageControl->iDisposalMethod == TGifImageControl::ERestoreToBackground) ||
+		maskProc==NULL)
+		{
+		// Clear to background colour if requested or if we have no mask, so that
+		// on streamed partial decodes are background
+		ClearBitmapL(aDestination,iFrameInfo->iBackgroundColor);
+		}
+
+	}
+
+void CGifReadCodec::SetUseFrameSizeInPixels(TBool aUseFrameSizeInPixels)
+	{
+	iUseFrameSizeInPixels = aUseFrameSizeInPixels;
+	}
+
+
+void CGifReadCodec::DoProcessInfoL(const TUint8*& aDataPtr,const TUint8* aDataPtrLimit)
+	{
+	if(!iReadingExtensionBlock)
+		{
+		iBlockId = aDataPtr[0];
+		while (!iBlockId)
+			{
+			aDataPtr++;
+			if (aDataPtr >= aDataPtrLimit)
+				{
+				User::Leave(KErrUnderflow);
+				}
+			
+			iBlockId = aDataPtr[0];
+			}
+		}
+
+	while (iBlockId == KGifExtensionId || iReadingExtensionBlock)
+		{
+		iReadingExtensionBlock = ETrue;
+		DoProcessExtensionL(aDataPtr,aDataPtrLimit);
+		iReadingExtensionBlock = EFalse;
+		
+		// we skip empty blocks here
+		while( aDataPtr < aDataPtrLimit && (iBlockId = *aDataPtr) == 0)
+		    {
+		    ++aDataPtr;
+		    }
+
+		if (aDataPtr >= aDataPtrLimit)
+			{
+			User::Leave(KErrUnderflow);
+			}
+		}
+
+	if (iBlockId == KGifImageDescriptorId)
+		{
+		DoProcessImageDescriptorL(aDataPtr,aDataPtrLimit);
+		}
+	else if (iBlockId == KGifTerminatorId)
+		{
+		User::Leave(KErrCompletion);
+		}
+	else
+		{
+		User::Leave(KErrCorrupt);
+		}
+	}
+
+void CGifReadCodec::DoProcessExtensionL(const TUint8*& aDataPtr,const TUint8* aDataPtrLimit)
+	{
+	// Make sure we leave a block id for DoProcessInfoL()
+	aDataPtrLimit--;
+
+	TInt blockLength;
+	TInt dataPtrVal;
+	const TUint8* dataPtr = aDataPtr;
+	if (iReadingCommentExtensionBlock)
+		{
+		if ((aDataPtr + 2) > aDataPtrLimit)
+			{
+			User::Leave(KErrUnderflow);
+			}
+
+		dataPtrVal = KGifCommentExtensionId;
+		blockLength = aDataPtr[0];
+
+		if ((aDataPtr + blockLength + 2) > aDataPtrLimit)
+			{
+			User::Leave(KErrUnderflow);
+			}
+		}
+	else if (iReadingOtherExtensionBlock)
+		{
+		if ((aDataPtr + 2) > aDataPtrLimit)
+			{
+			User::Leave(KErrUnderflow);
+			}
+
+		dataPtrVal = KGifApplicationExtensionId;
+		blockLength = aDataPtr[0];
+
+		if ((aDataPtr + blockLength + 2) > aDataPtrLimit)
+			{
+			User::Leave(KErrUnderflow);
+			}
+		}
+	else
+		{
+		// we start reading block, there should be at least 3 bytes - id, ext. id, length
+		if ((aDataPtr + KGifExtBlkHeaderSize) > aDataPtrLimit)
+			{
+			User::Leave(KErrUnderflow);
+			}
+			
+		++dataPtr;
+		dataPtrVal  = *dataPtr; // get the ext. ID
+		++dataPtr;
+		blockLength = *dataPtr;
+		
+		// ensure that we've got all the block data in the buffer
+		// that's possible since max. block length for GIF is 255 bytes
+		if ((dataPtr + blockLength) > aDataPtrLimit)
+			{
+			User::Leave(KErrUnderflow);
+			}
+		}
+
+	switch (dataPtrVal)
+		{
+	case KGifApplicationExtensionId:
+	case KGifPlainTextExtensionId:
+		{
+		aDataPtr = dataPtr;
+		iReadingOtherExtensionBlock = ETrue;
+
+		while (blockLength != 0) 
+		    {
+			if (dataPtr + blockLength >= aDataPtrLimit)
+				{
+				aDataPtr = dataPtr;
+				User::Leave(KErrUnderflow);
+				}
+		    if (iReadingLoopIterationExtensionBlock)
+                {
+                TInt loopIterations = dataPtr[2] + (dataPtr[3] << 8);
+                TGifLoopIterations* iterationsDataBlock = new(ELeave) TGifLoopIterations;
+                CleanupStack::PushL(iterationsDataBlock);
+                iterationsDataBlock->iLoopIterations = loopIterations;
+                User::LeaveIfError(iFrameData->AppendImageData(iterationsDataBlock));
+                CleanupStack::Pop(iterationsDataBlock);
+                iReadingLoopIterationExtensionBlock = EFalse;
+                }
+            else if (blockLength == KAppIdBlockLength)
+                {
+                TPtrC8 appId(dataPtr + 1, KAppIdLength);
+                TPtrC8 appAuthenticCode(dataPtr + 1 + KAppIdLength, KAppAuthenticCodeLength);
+                if ((appId == KAppIdNetscape) && (appAuthenticCode == KAppAuthenticCode2_0))
+                    {
+                    iReadingLoopIterationExtensionBlock = ETrue;
+                    }
+                }
+
+			dataPtr += blockLength + 1;
+			if (dataPtr >= aDataPtrLimit)
+			    {
+			    User::Leave(KErrUnderflow);
+			    }
+			blockLength = dataPtr[0];
+			} 
+
+		iReadingOtherExtensionBlock = EFalse;
+		aDataPtr = dataPtr;
+		}
+		break;
+
+	case KGifCommentExtensionId:
+		{ // The problem here is a Block header is expected when were actually half way through the block!!!!!!!
+		if (!iReadingCommentExtensionBlock)
+			{
+			if(iCommentIndex < KSetCommentsLimit)
+				{
+    		    ASSERT(iComment.Count()==iCommentIndex);
+	            HBufC8* comment = HBufC8::NewL(blockLength);
+    			CleanupStack::PushL(comment);
+    			User::LeaveIfError(iComment.Append(comment));
+    			CleanupStack::Pop(comment);
+				}
+			iReadingCommentExtensionBlock = ETrue;
+			}
+		else
+			{
+			ASSERT(iComment.Count()==iCommentIndex+1);
+			HBufC8* comment = iComment[iCommentIndex];
+			iComment[iCommentIndex] = comment->ReAllocL(comment->Length()+blockLength);
+			}
+			
+		TPtr8 commentPtr(NULL,0);
+		if(iCommentIndex < KSetCommentsLimit)
+			{
+	 		commentPtr.Set( iComment[iCommentIndex]->Des() );
+			}
+		while (blockLength != 0)
+			{
+			// Append the block.
+			TPtrC8 newBlock(&dataPtr[1], blockLength);
+			if(iCommentIndex < KSetCommentsLimit)
+				{
+				commentPtr.Append(newBlock);
+				}
+
+			// Calculate the new block/comment length.
+			dataPtr += blockLength + 1;
+			if(dataPtr > aDataPtrLimit)
+				{
+				aDataPtr = dataPtr;
+				User::Leave(KErrUnderflow);
+				}
+			blockLength = dataPtr[0];
+
+			// Leave if the data for the new block is not present.
+			if (blockLength && ((dataPtr+blockLength+1) >= aDataPtrLimit))
+				{
+				aDataPtr = dataPtr;
+				User::Leave(KErrUnderflow);
+				}
+
+			// Re-allocate the comment, if there is another block.
+			if (blockLength != 0&&(iCommentIndex < KSetCommentsLimit))
+				{
+				HBufC8* comment = iComment[iCommentIndex];
+				iComment[iCommentIndex] = comment->ReAllocL(comment->Length()+blockLength);
+				commentPtr.Set(iComment[iCommentIndex]->Des());
+				}
+			}
+
+		iCommentIndex++;
+
+		aDataPtr = dataPtr;
+		}
+
+		iReadingCommentExtensionBlock = EFalse;
+		break;
+
+	case KGifGraphicControlExtensionId:
+		if (aDataPtr + blockLength + KGifExtBlkHeaderSize + 1 >= aDataPtrLimit)
+	        {
+	        User::Leave(KErrUnderflow);
+	        }
+	    
+	    aDataPtr += (KGifExtBlkHeaderSize + blockLength);
+	    // we ignore malformed extension block
+	    if (blockLength < KMinGifGraphicControlBlkLen)
+	        {
+	        break;
+	        }
+
+		++dataPtr; //go into block data
+		TUint8 flags = *dataPtr++;
+		
+		TGifImageControl* gifImageControl = new(ELeave) TGifImageControl;
+		CleanupStack::PushL(gifImageControl);
+
+		gifImageControl->iDelayTimeInCentiseconds = *dataPtr++;
+		gifImageControl->iDelayTimeInCentiseconds |= (*dataPtr++) << 8;
+		if (flags & 0x01)
+			gifImageControl->iTransparentColorIndex = *dataPtr++;
+		else
+			{
+			gifImageControl->iTransparentColorIndex = KErrNotFound;
+			dataPtr++;
+			}
+
+		gifImageControl->iDisposalMethod = TGifImageControl::TDisposalMethod((flags & 0x1c) >> 2);
+		gifImageControl->iUserInputFlag = (flags & 0x02) != 0;
+	
+		User::LeaveIfError(iFrameData->AppendFrameData(gifImageControl));
+
+		CleanupStack::Pop(); // gifImageControl
+		iFrameImageControl = gifImageControl;
+		break;
+		}
+
+	if (aDataPtr[0]!=0)
+		{
+		User::Leave(KErrCorrupt);
+		}
+		
+	aDataPtr++; // Absorb trailing zero
+	}
+
+void CGifReadCodec::DoProcessImageDescriptorL(const TUint8*& aDataPtr,const TUint8* aDataPtrLimit)
+	{
+	if (iFrameImageDesc != NULL)
+		{
+		User::Leave(KErrCorrupt);
+		}
+
+	if (aDataPtr + KGifImageInformationSize + KGifInitialCodeLengthSize > aDataPtrLimit)
+		{
+		User::Leave(KErrUnderflow);
+		}
+
+	TPoint topLeftCorner;
+	topLeftCorner.iX = aDataPtr[1] + (aDataPtr[2] << 8);
+	topLeftCorner.iY = aDataPtr[3] + (aDataPtr[4] << 8);
+
+	TSize imageSize;
+	imageSize.iWidth = aDataPtr[5] + (aDataPtr[6] << 8);
+	imageSize.iHeight = aDataPtr[7] + (aDataPtr[8] << 8);
+
+	//Save the first frame's real dimensions, but use the complete
+	//image size for the first frame
+	if(CurrentFrame()==0)
+		{
+		iFirstFrameSize = imageSize;
+		// TPoint (0,0) means that iFrameOffset is set to 0 as all frames are now treated the same for offset data
+		// But real (firstframe) imageSize is saved here as clients use first frames overallsizeinPixels
+		iFirstFrameCoords.SetRect(TPoint(0,0),imageSize);
+		const TSize screenSize(iScreenSize);
+		// there is leniency here for rogue gifs with first frames bigger than global screen size from gif header
+		TSize lenientImageSize = TSize(Max(imageSize.iWidth,screenSize.iWidth),
+				Max(imageSize.iHeight,screenSize.iHeight));	
+		iFrameInfo->iOverallSizeInPixels = lenientImageSize; 
+		//if the first frame has an offset, put it in the frame info
+		// this will be translated into the iPositionOffset variable
+		iFrameInfo->iFrameCoordsInPixels.SetRect(topLeftCorner,lenientImageSize);
+		}
+	else
+		{
+		iFrameInfo->iOverallSizeInPixels = imageSize;
+		iFrameInfo->iFrameCoordsInPixels.SetRect(topLeftCorner,imageSize);
+		}
+	iFrameInfo->iFrameSizeInPixels = imageSize;
+	
+	//adjust iFrameCoordsInPixels for proper behaviour
+	if(iUseFrameSizeInPixels)
+		{
+		iFrameInfo->iFrameCoordsInPixels.SetSize(iFrameInfo->iFrameSizeInPixels);
+		}
+
+	TUint8 flags = aDataPtr[9];
+
+	TGifImageDescriptor* gifImageDesc = new(ELeave) TGifImageDescriptor;
+	CleanupStack::PushL(gifImageDesc);
+
+	gifImageDesc->iLocalColorMap = flags & 0x80;
+	gifImageDesc->iInterlaced = flags & 0x40;
+	gifImageDesc->iSortedLocalMap = flags & 0x20;
+	if (gifImageDesc->iLocalColorMap)
+		{
+		iFrameInfo->iBitsPerPixel = (flags & 0x07) + 1;
+		TInt paletteEntries = 1 << iFrameInfo->iBitsPerPixel;
+		TInt paletteBytes = paletteEntries * KGifPaletteEntrySize;
+		if (aDataPtr + KGifImageInformationSize + paletteBytes + KGifInitialCodeLengthSize > aDataPtrLimit)
+			{
+			User::Leave(KErrUnderflow);
+			}
+
+		aDataPtr += KGifImageInformationSize;
+		const TUint8* paletteLimit = aDataPtr + paletteBytes;
+
+		TGifColorTable* gifColorTable = new(ELeave) TGifColorTable;
+		CleanupStack::PushL(gifColorTable);
+		TRgb* rgbPtr = gifColorTable->iPalette;
+		while (aDataPtr < paletteLimit)
+			{
+			*rgbPtr++ = TRgb(aDataPtr[0],aDataPtr[1],aDataPtr[2]);
+			aDataPtr += 3;
+			}
+		User::LeaveIfError(iFrameData->AppendFrameData(gifColorTable));
+		CleanupStack::Pop(gifColorTable);
+		}
+	else
+		{
+		aDataPtr += KGifImageInformationSize;
+		}
+
+	User::LeaveIfError(iFrameData->AppendFrameData(gifImageDesc));
+	CleanupStack::Pop(gifImageDesc);
+	
+	TGifLZWInfo* gifLZWInfo = new(ELeave) TGifLZWInfo;
+	CleanupStack::PushL(gifLZWInfo);
+
+	gifLZWInfo->iInitialCodeLength = aDataPtr[0] + 1;
+	User::LeaveIfError(iFrameData->AppendFrameData(gifLZWInfo));
+	aDataPtr++;
+
+	CleanupStack::Pop(gifLZWInfo);
+	iFrameImageDesc = gifImageDesc;
+	iFrameLZWInfo = gifLZWInfo;
+	}
+
+void CGifReadCodec::DoSaveCommentsL()
+	{
+	//If we have comments add it
+	TInt noOfComments = iComment.Count();
+	//If we have more than KSetCommentsLimit comments just restrict them as KSetCommentsLimit
+	if (noOfComments > KSetCommentsLimit)
+		{
+		noOfComments = KSetCommentsLimit;
+		}
+	for(TInt commentNo=0; commentNo<noOfComments; commentNo++)
+		{
+		TGifComment* comment = new(ELeave) TGifComment;
+		CleanupStack::PushL(comment);
+		comment->iComment = iComment[0];
+		User::LeaveIfError(iFrameData->AppendImageData(comment));
+		CleanupStack::Pop(); // comment
+
+		User::LeaveIfError(iFrameData->AppendImageBuffer(iComment[0]));
+		iComment.Remove(0);
+		}
+	}
+
+void CGifReadCodec::DoProcessDataL()
+	{
+	TInt nextFree = iNextFree;
+	TInt prevCode = iPreviousCode;
+	TBitBuffer bBuf = iBitBuffer;
+	TInt bbSize = iBitBuffSize;
+	TInt curCodeLen = iCurrentCodeLength;
+	iLatestPixSize = iFast64kMode ? sizeof(TUint16) : sizeof (TRgb);
+	
+	do
+		{
+		TInt code = NextCode(bBuf, bbSize, curCodeLen);
+		if (code == KErrNotFound)  
+			{
+			break; // not enought data in the buffer to get the code
+			}
+			
+	    if (iTableReset)
+			{
+			iTableReset = EFalse;
+			WriteCodeL(code);
+			prevCode    = code;
+			}
+		else if (code == iClearCode)
+			{
+			nextFree    = ResetTableL();
+			curCodeLen  = iCurrentCodeLength;
+			iTableReset = ETrue;
+			}
+		else if (code == iEoiCode)
+			{
+			iComplete = ETrue;
+			break;
+			}
+		else
+			{
+			if (prevCode >= nextFree)
+				{
+				User::Leave(KErrCorrupt);
+				}
+				
+			if ( (nextFree == (1 << curCodeLen)-1) &&  curCodeLen < KGifMaxBits)
+				{
+				++curCodeLen;
+				}
+				
+			if (code < nextFree)
+				{
+				WriteCodeL(code);
+				if (prevCode != -1)
+					{					
+				    iPrefixIndex[nextFree] = STATIC_CAST(TInt16,prevCode);
+				    iSuffixCode[nextFree] = iFirstChar;
+				    if (nextFree < KGifConversionTableSize )
+				        {
+				        nextFree++;    
+				        }
+					}
+				}
+			else
+				{
+				iPrefixIndex[nextFree] = STATIC_CAST(TInt16,prevCode);
+				iSuffixCode[nextFree] = iFirstChar;
+				WriteCodeL(nextFree);
+			    if (nextFree < KGifConversionTableSize )
+			        {
+			        nextFree++;    
+			        }
+				}
+				
+			if(code < nextFree)
+				{
+				prevCode = code;
+				}
+			else
+				{
+				if(nextFree <= 1)
+					{
+					User::Leave(KErrCorrupt);
+					}
+				prevCode = iPrefixIndex[nextFree-1];
+				}
+			
+			}
+		} 
+		while (iDataPtr <= iDataPtrLimit);
+		
+	ASSERT(iDataPtr <= iDataPtrLimit);
+	
+	SetCurrentCodeLengthL(curCodeLen);
+	iBitBuffer      = bBuf;
+	iBitBuffSize    = bbSize;
+	iNextFree       = nextFree;
+	iPreviousCode   = prevCode;
+	}
+
+inline
+TInt CGifReadCodec::ResetTableL()
+	{
+	const TInt nFree = iEoiCode + 1;
+	
+	SetCurrentCodeLengthL(iGifLZWInfo->iInitialCodeLength);
+	return nFree;
+	}
+	
+#if defined(__ARMCC__)
+__forceinline
+#else
+inline 
+#endif
+TInt CGifReadCodec::NextCode(TBitBuffer& aBitBuffer, TInt& aBitBufSize,const TInt aCurCodeLen )
+	{
+	
+	if (aCurCodeLen > aBitBufSize)
+	    {
+	    const TUint8* dataPtr = iDataPtr;
+	    ASSERT( dataPtr <= iDataPtrLimit );
+	    
+	    TInt bytesToRead = (sizeof(TBitBuffer) * 8 - aBitBufSize) >> 3;
+	    if (dataPtr + bytesToRead >= iDataPtrLimit)
+	        {
+	        bytesToRead = iDataPtrLimit - dataPtr;
+	        if (bytesToRead == 0)
+	            {
+	            return KErrNotFound;
+	            }
+	        }
+	    
+	    do
+	        {
+	        aBitBuffer |= *dataPtr++ << aBitBufSize;
+	        aBitBufSize +=8;
+	        } 
+	        while (--bytesToRead > 0);
+	    
+	    iDataPtr    = dataPtr;
+	    if (aBitBufSize < aCurCodeLen)
+	        {
+	        return KErrNotFound;
+	        }
+
+	    }
+    TInt code   = aBitBuffer;
+    aBitBuffer >>= aCurCodeLen;
+    code &= (1 << aCurCodeLen) - 1;
+    aBitBufSize -= aCurCodeLen;
+
+    return code;
+	}
+
+template <class TPalType, TInt aPtrDelta>
+inline 
+TUint8* CGifReadCodec::WriteGifBuffer(TUint8* aOutputStringPtr, TUint8* aOutputStringLimit)
+	{
+	TInt bufUsed = iPixBufCount;
+	TInt bufFree = iPixBufferSize - bufUsed;
+	
+	if ((aOutputStringLimit-aOutputStringPtr) > bufFree) 
+		{
+		aOutputStringLimit = aOutputStringPtr+bufFree;
+		}
+	
+	register TPalType* pixelBufferPtr = reinterpret_cast<TPalType*>( iPixelBuffer ) + bufUsed;
+	const TPalType* tmp = pixelBufferPtr;
+	const TPalType* palette;
+
+	if (aPtrDelta == 4)
+		{
+		palette = reinterpret_cast<const TPalType*>( iPalette );
+		}
+	else
+		{
+		palette = reinterpret_cast<const TPalType*>( i64KPalette );	
+		}
+
+	if (iMaskProc)
+		{
+		register TUint32* maskPixelBufferPtr = iMaskBuffer + bufUsed;
+		const TUint16 KTranspIdx= iTranspColIdx;
+		const TUint32 KTranspMask = 0;
+    	const TUint32 KOpaqueMask = iOpaqueMask;
+		const TPalType bgCol    = palette[ KTranspIdx ];
+			
+		while (aOutputStringPtr < aOutputStringLimit)
+			{ 
+			const TUint8 code = *aOutputStringPtr;
+			if (code == KTranspIdx)
+				{
+				*pixelBufferPtr = bgCol; 
+				*maskPixelBufferPtr = KTranspMask;
+				}
+			else 
+				{
+				*pixelBufferPtr = palette[code]; 
+				*maskPixelBufferPtr = KOpaqueMask;
+				}
+			maskPixelBufferPtr++;
+			pixelBufferPtr++;
+			aOutputStringPtr++;
+			}
+		}
+	else
+		{
+
+		while (aOutputStringPtr < aOutputStringLimit)
+			{ 
+			*pixelBufferPtr = palette[*aOutputStringPtr]; 
+			pixelBufferPtr++;
+			aOutputStringPtr++;
+			}
+		}                                          
+
+	iPixBufCount += pixelBufferPtr-tmp;
+	return aOutputStringPtr;	
+	}
+
+/**
+    That shall only leave with KErrCorrupt
+    which means that image decoding is not possible
+*/
+void CGifReadCodec::WriteCodeL(TInt aCode)
+	{
+	TUint8* outputStringLimit = iOutputString + KGifConversionTableSize;
+	register TUint8* outputStringPtr = outputStringLimit;
+	register TUint16 latestChar=0;
+
+	while (aCode >= 0)
+		{
+		ASSERT((aCode >= 0) && (aCode <= KGifConversionTableSize));
+		
+		outputStringPtr--;
+		latestChar = iSuffixCode[aCode];
+		outputStringPtr[0] = latestChar;
+		aCode = iPrefixIndex[aCode];
+		}                     
+
+	iFirstChar = latestChar; 
+	if (aCode != KErrNotFound)
+		{
+		User::Leave(KErrCorrupt);
+		}
+
+	while (true) 
+		{
+		if (iFast64kMode)
+	    	{
+	    	outputStringPtr = WriteGifBuffer<TUint16, sizeof(TUint16)>(outputStringPtr, outputStringLimit);
+	    	}
+		else
+	    	{
+	    	outputStringPtr = WriteGifBuffer<TRgb, sizeof(TRgb)>(outputStringPtr, outputStringLimit);    
+	    	}
+	
+    	if (outputStringPtr != outputStringLimit)
+        	{
+			FlushPixBuffer(iLatestPixSize);
+        	}
+        else
+        	{
+        	break;	
+        	}
+		}
+	}
+
+inline
+void CGifReadCodec::FlushPixBuffer(TInt aPixSize)
+    {
+    if (iPixBufCount)
+        {
+        if (iMaskProc)        	
+            {
+            WriteStringWithTransparency(reinterpret_cast<TUint8*>(iPixelBuffer), aPixSize, iMaskBuffer, iPixBufCount);
+            }        
+        else
+            {
+            WriteStringWithoutTransparency(reinterpret_cast<TUint8*>(iPixelBuffer), aPixSize, iPixBufCount);
+            }
+        
+        iPixBufCount = 0;
+        }    
+    }
+
+void CGifReadCodec::WriteStringWithoutTransparency(TUint8* aOutputString, TInt aPixSize, TInt aNumOfPixels)
+	{
+	CImageProcessor*const imageProc = iImgProc;
+
+	if (iFastAccessMode) 
+		{
+		imageProc->SetPixels(reinterpret_cast<TRgb*>(aOutputString), aNumOfPixels);
+		iPixRead += aNumOfPixels;
+		aNumOfPixels = 0;
+		return;
+		}
+
+	const TInt KImgXLimit = iFrameSize.iWidth + iFrameOffset.iX;
+	
+	while ( aNumOfPixels )
+		{
+		TInt rowPixels = Min(KImgXLimit - iPPos->iX, aNumOfPixels);
+
+		imageProc->SetPixels(reinterpret_cast<TRgb*>(aOutputString), rowPixels);
+		aNumOfPixels    -= rowPixels;
+		aOutputString   += rowPixels * aPixSize;
+
+		iPPos->iX += rowPixels;
+		if (iPPos->iX == KImgXLimit)
+			{
+			imageProc->FlushPixels();
+			UpdateYPos();
+			imageProc->SetPos( TPoint(iPPos->iX+iPositionOffset.iX, iPPos->iY+iPositionOffset.iY) );
+			}
+		}
+	}
+
+void CGifReadCodec::WriteStringWithTransparency(TUint8* aOutputString, TInt aPixSize, TUint32* aMaskString, TInt aNumOfPixels)
+	{
+	CImageProcessor*const imageProc = iImgProc;
+	CImageProcessor*const maskProc  = iMaskProc;
+	
+	if (iFastAccessMode) 
+		{
+		imageProc->SetPixels(reinterpret_cast<TRgb*>(aOutputString), aNumOfPixels);
+		if(maskProc) // For non-single 16MA bitmaps
+			{
+			maskProc->SetMonoPixels(reinterpret_cast<TUint32*>(aMaskString), aNumOfPixels);	
+			}
+		
+		iPixRead += aNumOfPixels;
+		aNumOfPixels = 0;
+		return;
+		}
+
+	const TInt KImgXLimit = iFrameSize.iWidth + iFrameOffset.iX;
+	
+	while ( aNumOfPixels )
+		{
+		TInt rowPixels = Min(KImgXLimit - iPPos->iX, aNumOfPixels);
+
+		imageProc->SetPixels(reinterpret_cast<TRgb*>(aOutputString), rowPixels);
+		maskProc->SetMonoPixels(reinterpret_cast<TUint32*>(aMaskString), rowPixels);
+
+		iPPos->iX       += rowPixels;
+		aOutputString   += rowPixels * aPixSize;
+		aMaskString     += rowPixels;
+		aNumOfPixels    -= rowPixels;
+
+		if (iPPos->iX == KImgXLimit)
+			{
+			imageProc->FlushPixels();
+			UpdateYPos();
+			const TPoint newPos(iPPos->iX+iPositionOffset.iX, iPPos->iY+iPositionOffset.iY);
+			imageProc->SetPos(newPos);
+			maskProc->SetPos(newPos);
+			}
+		}
+	}
+
+inline
+void CGifReadCodec::SetCurrentCodeLengthL(TInt aCodeLength)
+	{
+	if ((aCodeLength > KGifMaxBits) || (aCodeLength < 0))
+		{
+		User::Leave(KErrCorrupt);
+		}
+	iCurrentCodeLength = aCodeLength;
+	}
+
+inline
+void CGifReadCodec::UpdateYPos()
+	{
+	iPPos->iX = iFrameOffset.iX;
+
+	if (!iGifImageDesc->iInterlaced)
+		{
+		iPPos->iY++;
+		return;
+		}
+		
+	UpdateYPosInterlaced();
+	}
+
+void CGifReadCodec::UpdateYPosInterlaced()
+    {
+    iPPos->iY += iYPosIncrement;
+
+	CImageProcessor*const imageProc = ImageProcessor();
+	while (iPPos->iY >= iFrameSize.iHeight + iFrameOffset.iY)
+		{
+		iPass++;
+		TInt lineRepeat;
+		if (iPass == 2)
+			{
+			iPPos->iY = iFrameOffset.iY + KPass2StartLine;
+			iYPosIncrement = KPass2YPosIncrement;
+			lineRepeat = KPass2LineRepeat;
+			}
+		else if (iPass == 3)
+			{
+			iPPos->iY = iFrameOffset.iY + KPass3StartLine;
+			iYPosIncrement = KPass3YPosIncrement;
+			lineRepeat = KPass3LineRepeat;
+			}
+		else if (iPass == 4)
+			{
+			iPPos->iY = iFrameOffset.iY + KPass4StartLine;
+			iYPosIncrement = KPass4YPosIncrement;
+			lineRepeat = KPass4LineRepeat;
+			}
+		else
+			break;
+		imageProc->SetYPosIncrement(iYPosIncrement);
+		if(!iGifImageControl || (iGifImageControl->iTransparentColorIndex==KErrNotFound))
+		    {
+		    imageProc->SetLineRepeat(lineRepeat);
+		    }
+		}
+	}
+
+// CGifWriteCodec
+CGifWriteCodec* CGifWriteCodec::NewL(const CGifEncoder& aEncoder)
+	{
+	CGifWriteCodec* self = new(ELeave) CGifWriteCodec(aEncoder);
+	CleanupStack::PushL(self);
+	self->ConstructL();
+	CleanupStack::Pop(self); 
+	return self;
+	}
+
+CGifWriteCodec::CGifWriteCodec(const CGifEncoder& aEncoder)
+	:iEncoder(aEncoder)
+	{
+	}
+
+TFrameState CGifWriteCodec::ProcessFrameL(TBufPtr8& aDst)
+	{
+	iDestStartPtr = CONST_CAST(TUint8*,aDst.Ptr());
+	iDestPtr = iDestStartPtr;
+	iDestPtrLimit = iDestPtr + aDst.MaxLength();
+
+	FillBufferL(*Source());
+
+	if (iImageComplete)
+		{
+		while (iBufferSize > 0)
+			{
+			if (!WriteBuffer())
+				{
+				aDst.SetLength(iDestPtr - iDestStartPtr);
+				return EFrameIncomplete;
+				}
+			}
+		TBool terminatorWritten = WriteTerminator();
+		aDst.SetLength(iDestPtr - iDestStartPtr);
+		
+		return (terminatorWritten) ? EFrameComplete : EFrameIncomplete;
+		}
+	else
+		{
+		WriteBuffer();
+		}
+
+	aDst.SetLength(iDestPtr - iDestStartPtr);
+	return EFrameIncomplete;
+	}
+
+void CGifWriteCodec::FillBufferL(const CFbsBitmap& aFrame)
+	{
+	TUint pixelsScanned =0;
+	TBool pixelWritten = EFalse;
+
+	const CPalette* palette = iEncoder.Palette();
+	while (iPos.iY < iSourceRect.iBr.iY)
+		{
+		TRgb pixelColor;
+		aFrame.GetPixel(pixelColor,iPos);
+		iPos.iX++;
+		if (iPos.iX == iSourceRect.iBr.iX)
+			{
+			iPos.iX = iSourceRect.iTl.iX;
+			iPos.iY++;
+			}
+		TUint8 nextColorIndex;
+		if (palette)
+			{
+			nextColorIndex = palette->NearestIndex(pixelColor);	
+			}
+		else
+			{
+			nextColorIndex = STATIC_CAST(TUint8, pixelColor.Color256());
+			}
+
+		TUint32 hashValue=0;
+		TInt index=-1;
+		if (!TableEntry(iWaitingCode,nextColorIndex,index,hashValue))
+			{
+			if(index!=KErrNotFound)
+				{
+				pixelWritten = ETrue;
+				WriteData(iWaitingCode);
+				AddToTableL(index,hashValue);
+
+				if (iNextFree > iNextLimit)
+					{
+					iCodeLength++;
+					if (iCodeLength > KGifMaxBits)
+						{
+						iCodeLength=KGifMaxBits;
+						ResetTable();
+						}
+					iNextLimit = 1 << iCodeLength;
+					}
+				}
+			iWaitingCode = nextColorIndex;
+			}
+		else
+			{
+			iWaitingCode = iHashCode[index];	
+			}
+
+		if ((iBufferFull) || ((pixelsScanned++ > KLZWLimit) && pixelWritten !=EFalse))
+		{
+			return;
+		}
+
+	}
+
+
+	if (iPos.iY == iSourceRect.iBr.iY)
+		{
+		if (iWaitingCode != KErrNotFound)
+			{
+			WriteData(iWaitingCode);
+			}
+		WriteData(iClearCode + 1); // End-Of-Information
+		if (iBitOffset > 0)
+			{
+			iBufferSize++;
+			iBitOffset = 0;
+			}
+		iCodeLength = 8;
+		iBufferPtr++;
+		iImageComplete = ETrue;
+		}
+	}
+
+void CGifWriteCodec::InitFrameL(TBufPtr8& aDst, const CFbsBitmap& aSource)
+	{
+	SetSource(&aSource);
+
+	iDestStartPtr = CONST_CAST(TUint8*,aDst.Ptr());
+	iDestPtr = iDestStartPtr;
+	iDestPtrLimit = iDestPtr + aDst.MaxLength();
+
+	iSourceRect = TRect(aSource.SizeInPixels());
+	iPos.SetXY(0,0);
+
+	iBitsPerPixel = 8;
+
+	iBufferPtr = iBuffer;
+	iBufferSize = 0;
+
+	iClearCode = 1 << iBitsPerPixel;
+	iCodeLength = iBitsPerPixel + 1;
+	iWaitingCode = -1;
+
+	ResetTable();
+
+	*iDestPtr++ = KGifImageDescriptorId; // Image Separator Header
+	*iDestPtr++ = 0; // Coordinate Left Border
+	*iDestPtr++ = 0; // Coordinate Left Border
+	*iDestPtr++ = 0; // Coordinate Top Border
+	*iDestPtr++ = 0; // Coordinate Top Border
+	*iDestPtr++ = TUint8(iSourceRect.Width());
+	*iDestPtr++ = TUint8(iSourceRect.Width() >> 8);
+	*iDestPtr++ = TUint8(iSourceRect.Height());
+	*iDestPtr++ = TUint8(iSourceRect.Height() >> 8);
+	*iDestPtr++ = 0; // Flags
+
+	*iDestPtr++ = TUint8(iCodeLength - 1); // Initial Code Length - 1
+
+	aDst.SetLength(iDestPtr - iDestStartPtr);
+	}
+
+void CGifWriteCodec::AddToTableL(TInt aIndex, TUint32 aHashValue)
+	{
+	ASSERT(aIndex<KGifHashTableSize);
+	ASSERT(iNextFree<=KGifConversionTableSize);
+	iHashCode[aIndex] = static_cast<TInt16>(iNextFree++);
+	iHashValue[aIndex] = aHashValue;
+	}
+
+// The hash algoritm use open addressing double hashing (no chaining)
+// on the prefix code / suffix character combination. A variant of Knuth's
+// algorithm D (vol. 3, sec. 6.4) along with G. Knott's relatively-prime
+// secondary probe.
+TBool CGifWriteCodec::TableEntry(TInt16 aWaitingCode, TUint8 aNewCode, TInt& aIndex, TUint32& aHashValue)
+	{
+	TInt offset;
+
+	ASSERT(aWaitingCode>=KErrNotFound && aWaitingCode<KGifConversionTableSize);
+
+	aIndex = KErrNotFound;
+
+	//Very first code
+	if(aWaitingCode==KErrNotFound)
+		return EFalse;
+
+	aIndex = static_cast<TInt>(aNewCode<<(KGifMaxBits-8)) + aWaitingCode;
+	if(aIndex>=KGifHashTableSize)
+		aIndex -= KGifHashTableSize;
+	ASSERT(aIndex < KGifHashTableSize);
+
+	//hash function
+	aHashValue = static_cast<TUint32>(aWaitingCode<<8)|aNewCode;
+
+	if(iHashCode[aIndex]==KErrNotFound) //slot is empty
+		return EFalse;
+
+	//slot has an entry
+	if(iHashValue[aIndex]==aHashValue) //symbol already in table
+		return ETrue;
+
+	if(aIndex==0)	// secondary hash (after G. Knott)
+		offset = 1; 
+	else
+		offset = KGifHashTableSize - aIndex;
+
+	FOREVER
+		{
+		aIndex -= offset;
+		if(aIndex<0)
+			aIndex += KGifHashTableSize;
+
+		if(iHashCode[aIndex]==KErrNotFound)
+			return EFalse; //slot is empty
+
+		if(iHashValue[aIndex]==aHashValue) //symbol already in table
+			return ETrue;
+		}
+	}
+
+void CGifWriteCodec::ResetTable()
+	{
+	WriteData(iClearCode); // Send reset code
+
+	iNextFree = iClearCode + 2;
+	iCodeLength = iBitsPerPixel + 1;
+	iNextLimit = 1 << iCodeLength;
+
+	for (TInt index = 0; index < KGifHashTableSize; index++)
+		iHashCode[index] = KErrNotFound;
+	}
+
+void CGifWriteCodec::WriteData(TInt aIndex)
+	{
+	aIndex <<= iBitOffset;
+	iBufferPtr[0] |= TUint8(aIndex);
+	iBufferPtr[1] |= TUint8(aIndex >> 8);
+	iBufferPtr[2] |= TUint8(aIndex >> 16);
+
+	TInt newBitOffset = iBitOffset + iCodeLength;
+	iBitOffset = newBitOffset & 7;
+	TInt byteOffset = newBitOffset >> 3;
+	iBufferPtr += byteOffset;
+	iBufferSize += byteOffset;
+
+	if (iBufferSize >= KGifBlockSize)
+		{
+		ASSERT(iBufferSize <= KGifBufferSize);
+		iBufferFull = ETrue;
+		}
+	}
+
+TBool CGifWriteCodec::WriteBuffer()
+	{
+	ASSERT(iBufferSize <= KGifBufferSize);
+	if (iBufferSize == 0)
+		return ETrue;
+
+	TInt blockSize = Min(KGifBlockSize,iBufferSize);
+	if (iDestPtrLimit - iDestPtr < blockSize + 1)
+		return EFalse;
+
+	*iDestPtr++ = STATIC_CAST(TUint8,blockSize);
+	Mem::Copy(iDestPtr,iBuffer,blockSize);
+	iDestPtr += blockSize;
+	iBufferFull = EFalse;
+
+	iBufferSize -= blockSize;
+	iBufferPtr = iBuffer + iBufferSize;
+
+	TInt bitBufferSize = iBufferSize;
+	if (iBitOffset)
+		bitBufferSize++;
+	Mem::Copy(iBuffer,&iBuffer[blockSize],bitBufferSize);
+	Mem::FillZ(iBuffer + bitBufferSize,KGifBufferSize - bitBufferSize);
+
+	return ETrue;
+	}
+
+TBool CGifWriteCodec::WriteTerminator()
+	{
+	if (iDestPtrLimit - iDestPtr < 2)
+		return EFalse;
+
+	*iDestPtr++ = TUint8(0);
+	*iDestPtr++ = TUint8(KGifTerminatorId);
+	return ETrue;
+	}