os/kernelhwsrv/userlibandfileserver/fileserver/sfile/sf_inflate.cpp
author sl
Tue, 10 Jun 2014 14:32:02 +0200
changeset 1 260cb5ec6c19
permissions -rw-r--r--
Update contrib.
     1 // Copyright (c) 1998-2009 Nokia Corporation and/or its subsidiary(-ies).
     2 // All rights reserved.
     3 // This component and the accompanying materials are made available
     4 // under the terms of the License "Eclipse Public License v1.0"
     5 // which accompanies this distribution, and is available
     6 // at the URL "http://www.eclipse.org/legal/epl-v10.html".
     7 //
     8 // Initial Contributors:
     9 // Nokia Corporation - initial contribution.
    10 //
    11 // Contributors:
    12 //
    13 // Description:
    14 // f32\sfile\sf_inflate.h
    15 // 
    16 //
    17 
    18 #include "sf_deflate.h"
    19 #include "sf_ldr.h"
    20 
    21 // Class RInflater
    22 //
    23 // The inflation algorithm, complete with huffman decoding
    24 
    25 inline CInflater::CInflater(TBitInput& aInput)
    26 	:iBits(&aInput),iEncoding(0),iOut(0)
    27 	{}
    28 
    29 void CInflater::ConstructL()
    30 	{
    31 	iEncoding=new(ELeave) TEncoding;
    32 	InitL();
    33 	iLen=0;
    34 	iOut=new(ELeave) TUint8[KDeflateMaxDistance];
    35 	iAvail=iLimit=iOut;
    36 	}
    37 
    38 CInflater* CInflater::NewLC(TBitInput& aInput)
    39 	{
    40 	CInflater* self=new(ELeave) CInflater(aInput);
    41 	CleanupStack::PushL(self);
    42 	self->ConstructL();
    43 	return self;
    44 	}
    45 
    46 CInflater::~CInflater()
    47 	{
    48 	delete iEncoding;
    49 	delete [] iOut;
    50 	}
    51 
    52 TInt CInflater::ReadL(TUint8* aBuffer,TInt aLength, TMemoryMoveFunction aMemMovefn)
    53 	{
    54 	TInt tfr=0;
    55 	for (;;)
    56 		{
    57 		TInt len=Min(aLength,iLimit-iAvail);
    58 		if (len && aBuffer)
    59 			{
    60 			aMemMovefn(aBuffer,iAvail,len);
    61 			aBuffer+=len;
    62 			}
    63 		aLength-=len;
    64 		iAvail+=len;
    65 		tfr+=len;
    66 		if (aLength==0)
    67 			return tfr;
    68 		len=InflateL();
    69 		if (len==0)
    70 			return tfr;
    71 		iAvail=iOut;
    72 		iLimit=iAvail+len;
    73 		}
    74 	}
    75 
    76 TInt CInflater::SkipL(TInt aLength)
    77 	{
    78 	return ReadL(0,aLength,Mem::Move);
    79 	}
    80 
    81 void CInflater::InitL()
    82 	{
    83 // read the encoding
    84 	Huffman::InternalizeL(*iBits,iEncoding->iLitLen,KDeflationCodes);
    85 // validate the encoding
    86 	if (!Huffman::IsValid(iEncoding->iLitLen,TEncoding::ELitLens) ||
    87 		!Huffman::IsValid(iEncoding->iDistance,TEncoding::EDistances))
    88 		LEAVE_FAILURE(KErrCorrupt);
    89 // convert the length tables into huffman decoding trees
    90 	Huffman::Decoding(iEncoding->iLitLen,TEncoding::ELitLens,iEncoding->iLitLen);
    91 	Huffman::Decoding(iEncoding->iDistance,TEncoding::EDistances,iEncoding->iDistance,KDeflateDistCodeBase);
    92 	}
    93 
    94 TInt CInflater::InflateL()
    95 //
    96 // consume all data lag in the history buffer, then decode to fill up the output buffer
    97 // return the number of available bytes in the output buffer. This is only ever less than
    98 // the buffer size if the end of stream marker has been read
    99 //
   100 	{
   101 // empty the history buffer into the output
   102 	TUint8* out=iOut;
   103 	TUint8* const end=out+KDeflateMaxDistance;
   104 	const TUint32* tree=iEncoding->iLitLen;
   105 	if (iLen<0)	// EOF
   106 		return 0;
   107 	if (iLen>0)
   108 		goto useHistory;
   109 //
   110 	while (out<end)
   111 		{
   112 		// get a huffman code
   113 		{
   114 		TInt val=iBits->HuffmanL(tree)-TEncoding::ELiterals;
   115 		if (val<0)
   116 			{
   117 			*out++=TUint8(val);
   118 			continue;			// another literal/length combo
   119 			}
   120 		if (val==TEncoding::EEos-TEncoding::ELiterals)
   121 			{	// eos marker. we're done
   122 			iLen=-1;
   123 			break;
   124 			}
   125 		// get the extra bits for the code
   126 		TInt code=val&0xff;
   127 		if (code>=8)
   128 			{	// xtra bits
   129 			TInt xtra=(code>>2)-1;
   130 			code-=xtra<<2;
   131 			code<<=xtra;
   132 			code|=iBits->ReadL(xtra);
   133 			}
   134 		if (val<KDeflateDistCodeBase-TEncoding::ELiterals)
   135 			{
   136 			// length code... get the code
   137 			if(TUint(code)>TUint(KDeflateMaxLength-KDeflateMinLength))
   138 				{
   139 				CHECK_FAILURE(KErrCorrupt);
   140 				goto error;
   141 				}
   142 			iLen=code+KDeflateMinLength;
   143 			tree=iEncoding->iDistance;
   144 			continue;			// read the huffman code
   145 			}
   146 		// distance code
   147 		if(TUint(code)>TUint(KDeflateMaxDistance-1))
   148 			{
   149 			CHECK_FAILURE(KErrCorrupt);
   150 			goto error;
   151 			}
   152 		iRptr=out-(code+1);
   153 		if (iRptr+KDeflateMaxDistance<end)
   154 			iRptr+=KDeflateMaxDistance;
   155 		if(!iLen)
   156 			{
   157 			CHECK_FAILURE(KErrCorrupt);
   158 			goto error;
   159 			}
   160 		}
   161 useHistory:
   162 		{
   163 		TInt tfr=Min(end-out,iLen);
   164 		iLen-=tfr;
   165 		const TUint8* from=iRptr;
   166 		do
   167 			{
   168 			*out++=*from++;
   169 			if (from==end)
   170 				from-=KDeflateMaxDistance;
   171 			} while (--tfr!=0);
   172 		iRptr=from;
   173 		tree=iEncoding->iLitLen;
   174 		}
   175 
   176 		};
   177 	return out-iOut;
   178 
   179 error:
   180 	LEAVE_FAILURE(KErrCorrupt);
   181 	return 0;
   182 	}
   183