userlibandfileserver/fileserver/sfile/sf_inflate.cpp
changeset 0 a41df078684a
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/userlibandfileserver/fileserver/sfile/sf_inflate.cpp	Mon Oct 19 15:55:17 2009 +0100
@@ -0,0 +1,183 @@
+// Copyright (c) 1998-2009 Nokia Corporation and/or its subsidiary(-ies).
+// All rights reserved.
+// This component and the accompanying materials are made available
+// under the terms of the License "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:
+// f32\sfile\sf_inflate.h
+// 
+//
+
+#include "sf_deflate.h"
+#include "sf_ldr.h"
+
+// Class RInflater
+//
+// The inflation algorithm, complete with huffman decoding
+
+inline CInflater::CInflater(TBitInput& aInput)
+	:iBits(&aInput),iEncoding(0),iOut(0)
+	{}
+
+void CInflater::ConstructL()
+	{
+	iEncoding=new(ELeave) TEncoding;
+	InitL();
+	iLen=0;
+	iOut=new(ELeave) TUint8[KDeflateMaxDistance];
+	iAvail=iLimit=iOut;
+	}
+
+CInflater* CInflater::NewLC(TBitInput& aInput)
+	{
+	CInflater* self=new(ELeave) CInflater(aInput);
+	CleanupStack::PushL(self);
+	self->ConstructL();
+	return self;
+	}
+
+CInflater::~CInflater()
+	{
+	delete iEncoding;
+	delete [] iOut;
+	}
+
+TInt CInflater::ReadL(TUint8* aBuffer,TInt aLength, TMemoryMoveFunction aMemMovefn)
+	{
+	TInt tfr=0;
+	for (;;)
+		{
+		TInt len=Min(aLength,iLimit-iAvail);
+		if (len && aBuffer)
+			{
+			aMemMovefn(aBuffer,iAvail,len);
+			aBuffer+=len;
+			}
+		aLength-=len;
+		iAvail+=len;
+		tfr+=len;
+		if (aLength==0)
+			return tfr;
+		len=InflateL();
+		if (len==0)
+			return tfr;
+		iAvail=iOut;
+		iLimit=iAvail+len;
+		}
+	}
+
+TInt CInflater::SkipL(TInt aLength)
+	{
+	return ReadL(0,aLength,Mem::Move);
+	}
+
+void CInflater::InitL()
+	{
+// read the encoding
+	Huffman::InternalizeL(*iBits,iEncoding->iLitLen,KDeflationCodes);
+// validate the encoding
+	if (!Huffman::IsValid(iEncoding->iLitLen,TEncoding::ELitLens) ||
+		!Huffman::IsValid(iEncoding->iDistance,TEncoding::EDistances))
+		LEAVE_FAILURE(KErrCorrupt);
+// convert the length tables into huffman decoding trees
+	Huffman::Decoding(iEncoding->iLitLen,TEncoding::ELitLens,iEncoding->iLitLen);
+	Huffman::Decoding(iEncoding->iDistance,TEncoding::EDistances,iEncoding->iDistance,KDeflateDistCodeBase);
+	}
+
+TInt CInflater::InflateL()
+//
+// consume all data lag in the history buffer, then decode to fill up the output buffer
+// return the number of available bytes in the output buffer. This is only ever less than
+// the buffer size if the end of stream marker has been read
+//
+	{
+// empty the history buffer into the output
+	TUint8* out=iOut;
+	TUint8* const end=out+KDeflateMaxDistance;
+	const TUint32* tree=iEncoding->iLitLen;
+	if (iLen<0)	// EOF
+		return 0;
+	if (iLen>0)
+		goto useHistory;
+//
+	while (out<end)
+		{
+		// get a huffman code
+		{
+		TInt val=iBits->HuffmanL(tree)-TEncoding::ELiterals;
+		if (val<0)
+			{
+			*out++=TUint8(val);
+			continue;			// another literal/length combo
+			}
+		if (val==TEncoding::EEos-TEncoding::ELiterals)
+			{	// eos marker. we're done
+			iLen=-1;
+			break;
+			}
+		// get the extra bits for the code
+		TInt code=val&0xff;
+		if (code>=8)
+			{	// xtra bits
+			TInt xtra=(code>>2)-1;
+			code-=xtra<<2;
+			code<<=xtra;
+			code|=iBits->ReadL(xtra);
+			}
+		if (val<KDeflateDistCodeBase-TEncoding::ELiterals)
+			{
+			// length code... get the code
+			if(TUint(code)>TUint(KDeflateMaxLength-KDeflateMinLength))
+				{
+				CHECK_FAILURE(KErrCorrupt);
+				goto error;
+				}
+			iLen=code+KDeflateMinLength;
+			tree=iEncoding->iDistance;
+			continue;			// read the huffman code
+			}
+		// distance code
+		if(TUint(code)>TUint(KDeflateMaxDistance-1))
+			{
+			CHECK_FAILURE(KErrCorrupt);
+			goto error;
+			}
+		iRptr=out-(code+1);
+		if (iRptr+KDeflateMaxDistance<end)
+			iRptr+=KDeflateMaxDistance;
+		if(!iLen)
+			{
+			CHECK_FAILURE(KErrCorrupt);
+			goto error;
+			}
+		}
+useHistory:
+		{
+		TInt tfr=Min(end-out,iLen);
+		iLen-=tfr;
+		const TUint8* from=iRptr;
+		do
+			{
+			*out++=*from++;
+			if (from==end)
+				from-=KDeflateMaxDistance;
+			} while (--tfr!=0);
+		iRptr=from;
+		tree=iEncoding->iLitLen;
+		}
+
+		};
+	return out-iOut;
+
+error:
+	LEAVE_FAILURE(KErrCorrupt);
+	return 0;
+	}
+