secureswitools/swisistools/source/rscparser/barscimpl.cpp
changeset 25 98b66e4fb0be
child 33 8110bf1194d1
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/secureswitools/swisistools/source/rscparser/barscimpl.cpp	Fri Apr 16 15:05:20 2010 +0300
@@ -0,0 +1,539 @@
+// Copyright (c) 2009 - 2010 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:
+//
+/** 
+* @file BaRscImpl.cpp
+*
+* @internalComponent
+* @released
+*/
+#include <iostream>
+#include <fstream>
+#include <cassert>
+#include <sys/stat.h>
+#include <sstream>
+#include "barsc2.h"
+#include "barscimpl.h"
+#include "ucmp.h"
+
+
+RResourceFileImpl::TExtra::TExtra():
+	iBitArrayOfResourcesContainingCompressedUnicode(NULL),
+	iFileOffset(0),
+	iFileSize(0)
+	{
+	}
+
+
+RResourceFileImpl::TExtra::~TExtra()
+	{
+	delete iBitArrayOfResourcesContainingCompressedUnicode;
+	}
+
+
+TInt32 RResourceFileImpl::TExtra::ContainsCompressedUnicode(const TInt& aRscIdx) const
+	{
+	assert(aRscIdx>=0);
+	
+	if (iBitArrayOfResourcesContainingCompressedUnicode==NULL)
+		{
+		return EFalse;
+		}
+	
+	TInt index = aRscIdx/8;
+	
+	return (iBitArrayOfResourcesContainingCompressedUnicode)[index]&(1<<(aRscIdx%8));
+	}
+
+
+RResourceFileImpl::RResourceFileImpl() :
+	iResourceContents(NULL),
+	iSizeOfLargestResourceWhenCompletelyUncompressed(0),
+	iIndex(0),
+	iOffset(0),
+	iExtra(NULL),
+	iFlagsAndNumberOfResources(0)
+	{
+	// Fixed class size - because of the BC reasons.
+	// RResourceFileImpl size must be the same as CResourceFile size.
+	enum
+		{
+		KRscFileImplSize = 24
+		};	
+	assert(sizeof(RResourceFileImpl) == KRscFileImplSize);
+
+	//Fixed "iOffset" position - because of the BC reasons.
+	assert(offsetof(RResourceFileImpl, iOffset)==12);
+	}
+
+
+RResourceFileImpl::~RResourceFileImpl()
+{
+	if(iResourceContents)
+	{
+		if (iResourceContents->is_open())
+		{
+			iResourceContents->close();
+		}
+		delete iResourceContents;
+	}
+	iSizeOfLargestResourceWhenCompletelyUncompressed=0;
+	delete iIndex;
+	iIndex=NULL;
+	if (iExtra)
+	{
+		delete iExtra;
+		iExtra=NULL;
+	}
+
+	iFlagsAndNumberOfResources=0;
+	iOffset=0;
+}
+
+
+void RResourceFileImpl::OpenL(
+						  const std::string& aName, 
+						  TUint32 aFileOffset, 
+						  TInt aFileSize)
+{
+	iResourceContents= new std::ifstream(aName.c_str(), std::ios::in|std::ios::binary);
+		
+	if(!iResourceContents->good())
+	{
+		std::string errMsg= "Unable to open RSC file. " + aName;
+		if (iResourceContents->is_open())
+			iResourceContents->close();
+		if(iResourceContents)
+			delete iResourceContents;
+		throw CResourceFileException(errMsg);
+	}
+
+	iExtra=new TExtra();
+	iExtra->iFileOffset = aFileOffset;
+	
+	TInt fileSize = 0;
+	if (aFileSize)
+		{
+		fileSize = aFileSize;
+		assert(fileSize > TInt(aFileOffset));
+		}
+	else
+		{
+		// Get the resource file size
+		struct stat resourceFileStats;
+    
+		if (stat(aName.c_str(),&resourceFileStats) == 0)
+			{
+			// The size of the file in bytes is in
+			// resourceFileStats.st_size
+			fileSize=resourceFileStats.st_size;
+			assert(fileSize > 0);
+			}   	
+		else
+			{
+			if (iResourceContents->is_open())
+					iResourceContents->close();		
+			std::string errMsg="Invalid RSC File";
+			throw CResourceFileException(errMsg);
+			}		
+		}
+	
+	iExtra->iFileSize = fileSize;	
+	
+	// Verify the header of the RSC and get the resource index
+	ReadHeaderAndResourceIndexL();
+}
+
+
+Ptr8* RResourceFileImpl::GetDecompressedResourceDataL(
+													const TInt& aResourceIndex,			
+													const TUint32& aFlags) 
+	{
+	const TInt positionOfResourceData= iIndex[aResourceIndex];
+	const TInt numberOfBytes= iIndex[aResourceIndex+1]-positionOfResourceData;
+	
+	assert(numberOfBytes >= 0);
+	
+	Ptr8* outputResourceData=new Ptr8(numberOfBytes);
+	ReadL(aFlags, positionOfResourceData, outputResourceData->GetPtr(), numberOfBytes);
+	outputResourceData->UpdateLength(numberOfBytes);
+	
+	return outputResourceData;
+	}
+
+
+Ptr8* RResourceFileImpl::AllocReadL(const TInt& aResourceId) 
+	{
+	
+	// Check if the resource id is present in the RSC file
+	if (!OwnsResourceId(aResourceId))
+		{
+		std::ostringstream errDispStream;
+		
+		errDispStream<<"Resource ID:";
+		errDispStream<<aResourceId;
+		errDispStream<<" is not present in the RSC file";
+		
+		throw CResourceFileException(errDispStream.str());
+		}
+	
+	//"-1" because the first resource has ID 0x*****001 (not 0x*****000)
+	TInt resourceIndex= (aResourceId & EIdBits)-1; 
+	assert(resourceIndex>=0);
+	
+	Ptr8* decompressedResourceData= 
+		GetDecompressedResourceDataL(
+								resourceIndex,
+								iFlagsAndNumberOfResources & static_cast<TUint32>(EAllFlags));
+	
+	// Return the resource data if its not unicode compressed.
+	if (!iExtra->ContainsCompressedUnicode(resourceIndex))
+		{
+		return decompressedResourceData;
+		}
+	
+	// Get the decompressed unicode data.
+	Ptr8* finalResourceData= DecompressUnicodeL(decompressedResourceData);	
+	
+	delete decompressedResourceData;	
+	return finalResourceData;	
+	}
+
+
+Ptr8* RResourceFileImpl::DecompressUnicodeL(const Ptr8* aInputResourceData) const
+	{
+	const TInt numberOfBytesInInput= aInputResourceData->GetLength();
+	assert(iSizeOfLargestResourceWhenCompletelyUncompressed>0);
+							
+	Ptr8* outputResourceData= new Ptr8(iSizeOfLargestResourceWhenCompletelyUncompressed);
+	
+	const TUint8* input= aInputResourceData->GetPtr();
+	TInt index=0;
+	
+	TBool decompressRun=ETrue;
+	while (1)
+		{
+		assert(index<numberOfBytesInInput);
+		
+		TInt runLength=input[index];
+		
+		// The run-length occupies a single byte if it is less than 128, 
+		// otherwise it occupies two bytes (in little-endian byte order), 
+		// with the most significant bit of the first byte set to non-zero 
+		//to indicate that the run-length occupies two bytes.
+		if (runLength & 0x80)
+			{
+			++index;
+			if (index>=numberOfBytesInInput)
+				{
+				std::string errMsg="Invalid Rsc File";
+				throw CResourceFileException(errMsg);
+				}
+			runLength &= ~0x80;
+			runLength <<= 8;
+			runLength |= input[index];
+			}
+		++index;
+		if (runLength>0)
+			{			
+			if (decompressRun)
+				{
+				AppendDecompressedUnicodeL(
+										outputResourceData,				
+										const_cast<unsigned char *>(input+index),
+										runLength);
+				}
+			else
+				{
+				assert(
+					(outputResourceData->GetLength() + runLength) <= 
+					iSizeOfLargestResourceWhenCompletelyUncompressed);
+				
+				memcpy((char*)(outputResourceData->GetPtr()+outputResourceData->GetLength()),(char*)(input+index),runLength);				
+				outputResourceData->UpdateLength(runLength);
+				}
+			index+=runLength;
+			}
+		if (index>numberOfBytesInInput)
+			{
+			std::string errMsg="Invalid Rsc File";
+			throw CResourceFileException(errMsg);
+			}
+		if (index>=numberOfBytesInInput)
+			{
+			break;
+			}
+			decompressRun=!decompressRun;
+		}	
+	return outputResourceData;
+	}
+
+
+
+/** @internalComponent
+@return The first resource record.
+@panic Some BAFL panic codes, if the file is corrupted.
+@leave KErrCorrupt The file is corrupted.
+Some other error codes are possible too.
+The method could panic or leave depending on the state of
+iAssertObj member of RResourceFileImpl::TExtra class. */
+RResourceFileImpl::SSigRecord RResourceFileImpl::FirstRecordL() const
+	{
+	// Added to support reading of rel 6.x resource files.
+	// rel 6.x files do not have signatures!
+	Ptr8* const firstResource=AllocReadL(1);
+
+	// Basic check to test if the signature is of the correct size.
+	if (firstResource->GetLength()!= sizeof(SSigRecord))
+	{
+		std::string errMsg="Invalid RSS Signature";
+		throw CResourceFileException(errMsg);
+	}
+	SSigRecord sigRecord = *reinterpret_cast<const SSigRecord*>(firstResource->GetPtr());
+	delete firstResource;
+	return sigRecord;
+}
+
+/** Initialises the offset value from the first resource.
+
+The function tests to catch cases where the first resource is not an RSS_SIGNATURE.
+It assumes that the first resource in the file consists of
+two 32-bit integers. The first integer contains the version number and
+the second is a self-referencing link whose value is the offset for
+the resources in the file, plus 1.This function must be called before
+calling Offset(), AllocReadL(), AllocReadLC() or ReadL().
+
+@see Offset()
+@see AllocReadL()
+@see AllocReadLC() 
+@see ReadL()
+@internalComponent
+@pre OpenL() is called.
+@panic Some BAFL panic codes, if the file is corrupted.
+@leave KErrCorrupt The file is corrupted.
+Some other error codes are possible too.
+The method could panic or leave depending on the state of
+iAssertObj member of RResourceFileImpl::TExtra class. */
+void RResourceFileImpl::ConfirmSignatureL()
+{
+	// Added to support reading of rel 6.x resource files.
+	SSigRecord firstRecord=FirstRecordL();
+
+	// If the resource offset does not correspond to the first resource
+	// this is not a resource signature.
+	if ((firstRecord.offset & EIdBits) != 1)
+	{
+		std::string errMsg="Failed : Invalid RSS Signature";
+		throw CResourceFileException(errMsg);
+	}
+	iOffset=(firstRecord.offset & EOffsetBits);
+}
+
+void RResourceFileImpl::AppendDecompressedUnicodeL(
+												   Ptr8* aBuffer,
+												   const TUint8*  aCompressedUnicode,
+												   const TInt& aLengthOfCompressedUnicode) const
+	{
+	
+	if (aLengthOfCompressedUnicode>0)
+		{
+		TUint8* startOfDecompressedUnicode= aBuffer->GetPtr() + aBuffer->GetLength();
+		
+		if (reinterpret_cast<TUint32>(startOfDecompressedUnicode) & 0x01)
+			{			
+			TUint8 padChar = 0xab;
+			memcpy(startOfDecompressedUnicode,&padChar,1);
+			++startOfDecompressedUnicode;
+			aBuffer->UpdateLength(1);
+			}
+		
+		const TInt maximumOutputLength= (
+			iSizeOfLargestResourceWhenCompletelyUncompressed - (aBuffer->GetLength()))/2; 
+		
+		TMemoryUnicodeSink decompressedUnicode(reinterpret_cast<TUint16*>(startOfDecompressedUnicode));
+		
+		TInt lengthOfDecompressedUnicode;
+		TInt numberOfInputBytesConsumed;
+		TUnicodeExpander unicodeExpander;
+		
+		unicodeExpander.ExpandL(decompressedUnicode,
+								aCompressedUnicode,
+								maximumOutputLength,
+								aLengthOfCompressedUnicode,
+								&lengthOfDecompressedUnicode,
+								&numberOfInputBytesConsumed);
+		TInt temp;
+		unicodeExpander.FlushL(decompressedUnicode,maximumOutputLength,temp);
+		lengthOfDecompressedUnicode+=temp;
+		aBuffer->UpdateLength(lengthOfDecompressedUnicode*2);
+		
+		assert(numberOfInputBytesConsumed == aLengthOfCompressedUnicode);		
+		}
+	}
+
+
+TBool RResourceFileImpl::OwnsResourceId(const TInt& aResourceId) const
+	{ 
+	// Checks whether Rsc file owns the resource:
+	// does so if offset is 0, or matches that given, 
+	// and id is in index.
+	const TInt offset=(aResourceId & EOffsetBits);
+//	if ((offset!=0) && (offset!=iOffset))
+//		{
+//		return EFalse;
+//		}
+	
+	const TInt resourceIndex=(aResourceId & EIdBits)-1;
+	TInt numberOfResources=(iFlagsAndNumberOfResources & ~EAllFlags);
+	
+	return (resourceIndex >= 0) && (resourceIndex < numberOfResources);
+	}
+
+
+void RResourceFileImpl::ReadL(
+							const TUint32& aFlags, 
+							TInt aPos,
+							TUint8* aData,
+							const TInt& aLength) 
+	{
+	aPos += iExtra->iFileOffset;
+	
+	assert(aPos >= iExtra->iFileOffset);
+	assert(aLength >= 0);
+	assert((aPos + aLength) <= (iExtra->iFileOffset + iExtra->iFileSize));	
+	
+	// Seek to the offset specified by "aPos"
+	iResourceContents->seekg(aPos, std::ios_base::beg);
+	iResourceContents->read((char*)aData, aLength);		
+	}
+
+
+void RResourceFileImpl::ReadL(TInt aPos, TUint8* aData, const TInt& aLength) 
+	{
+	ReadL(iFlagsAndNumberOfResources & static_cast<TUint32>(EAllFlags),aPos,aData,aLength);
+	}
+
+
+TInt RResourceFileImpl::LittleEndianTwoByteInteger(
+													TUint8* aBuffer,
+													const TInt& aIndexOfFirstByte) const
+	{
+	return aBuffer[aIndexOfFirstByte] | (aBuffer[aIndexOfFirstByte+1]<<8);
+	}
+
+
+void RResourceFileImpl::ReadHeaderAndResourceIndexL()
+	{
+	
+	// Unicode compressed RSC file will have 19 bytes header.
+	const TUint8 kHeaderSize= 19;
+	TUint8 header[kHeaderSize];
+			
+	sTUid uid;
+	
+	// Verify the header of the RSC file.
+	if(iExtra->iFileSize >= kHeaderSize)
+		{
+		
+		// Get the RSC header
+		ReadL(0,0,header,kHeaderSize);
+		// Get the first UID
+		memcpy((TUint8*)&uid.iUid1,header,4);
+		
+		// First uid of unicode compressed RSC is "0x101f4a6b"
+		TUint32 unicodeCompressedFirstUid = 0x101f4a6b;
+		
+		if (uid.iUid1 == unicodeCompressedFirstUid)
+			{
+			iFlagsAndNumberOfResources |= EFlagPotentiallyContainsCompressedUnicode;
+			iSizeOfLargestResourceWhenCompletelyUncompressed=	LittleEndianTwoByteInteger(header,16+1);
+			}
+		else
+			{
+				if (iResourceContents->is_open())
+						iResourceContents->close();
+			std::string errMsg="Failed : Unsupported RSC file type";
+			throw CResourceFileException(errMsg);
+			}
+		}
+		
+		TInt numberOfResources= 0;
+		TUint8* bitArrayOfResourcesContainingCompressedUnicode= NULL;
+		
+		if (iFlagsAndNumberOfResources & EFlagPotentiallyContainsCompressedUnicode)
+		{
+			// Cache the resource-index (in iIndex) to minimize disk access.		
+			const TInt KMaximumNumberOfBytesCached= 256;
+			TUint8 cache[KMaximumNumberOfBytesCached];
+			const TInt numberOfBytesCached=
+				((iExtra->iFileSize>KMaximumNumberOfBytesCached) ? KMaximumNumberOfBytesCached : iExtra->iFileSize);
+			
+			ReadL(iExtra->iFileSize-numberOfBytesCached, cache, numberOfBytesCached);
+			
+			const TInt positionOfStartOfIndex=
+				((cache[numberOfBytesCached-1]<<8) | cache[numberOfBytesCached-2]);
+			const TInt numberOfBytesOfIndex=iExtra->iFileSize-positionOfStartOfIndex;
+			
+			assert(numberOfBytesOfIndex%2==0);
+			assert(numberOfBytesOfIndex>=0);
+			
+			const TInt numberOfBytesOfIndexStillToRetrieve = numberOfBytesOfIndex-numberOfBytesCached;
+			
+			if (numberOfBytesOfIndexStillToRetrieve<=0)
+				{
+				iIndex= new TUint16[numberOfBytesOfIndex/2];
+				memcpy(iIndex, cache+(numberOfBytesCached-numberOfBytesOfIndex), numberOfBytesOfIndex);
+				}
+			else
+				{
+				TUint16* index= new TUint16(numberOfBytesOfIndex/2);			
+				ReadL(positionOfStartOfIndex, reinterpret_cast<TUint8*>(index), numberOfBytesOfIndexStillToRetrieve);
+				memcpy((index+numberOfBytesOfIndexStillToRetrieve),cache,numberOfBytesCached); 		
+
+				iIndex=index;			
+				}
+
+			//"-1" because the last thing in the index (which is in fact the last thing in the 
+			//file itself) is the position of the start of the index which is therefore not 
+			//pointing to a resource
+			numberOfResources=(numberOfBytesOfIndex/2) - 1; 
+			
+			if (numberOfResources <= 0)
+				{
+				if (iResourceContents->is_open())
+						iResourceContents->close();
+				std::string errMsg="Failed : Invalid RSC file.";
+				throw CResourceFileException(errMsg);
+				}
+				
+			const TInt lengthOfBitArrayInBytes=(numberOfResources+7)/8;
+			bitArrayOfResourcesContainingCompressedUnicode=
+								new TUint8(lengthOfBitArrayInBytes);
+			
+			//"16+1+2": 16 bytes of checked-UID + 1 byte of flags (these flags are for a 
+			//dictionary-compressing program's use rather than directly for Bafl's use, 
+			//so we ignore them) + 2 bytes containing the size of the largest resource when 
+			//uncompressed
+			ReadL(16+1+2,bitArrayOfResourcesContainingCompressedUnicode,lengthOfBitArrayInBytes); 
+		
+		}
+		
+		assert((numberOfResources & EAllFlags)==0);
+		assert((iFlagsAndNumberOfResources & ~EAllFlags)==0);
+		
+		iFlagsAndNumberOfResources |= (numberOfResources & ~EAllFlags);
+		iExtra->iUid = uid;
+		iExtra->iBitArrayOfResourcesContainingCompressedUnicode = bitArrayOfResourcesContainingCompressedUnicode;
+			
+	}