diff -r 5cc91383ab1e -r 7333d7932ef7 secureswitools/swisistools/source/rscparser/barscimpl.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/secureswitools/swisistools/source/rscparser/barscimpl.cpp Tue Aug 31 15:21:33 2010 +0300 @@ -0,0 +1,1129 @@ +// 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 +#include +#include +#include +#include +#include "barsc2.h" +#include "barscimpl.h" +#include "dictionarycompression.h" +#include "ucmp.h" +#include "util.h" +#include "parse.h" + +#define REINTERPRET_CAST(type,exp) (reinterpret_cast(exp)) +#define CONST_CAST(type,exp) (const_cast(exp)) +#define STATIC_CAST(type,exp) (static_cast(exp)) + +inline TUint8* MemCopy(TAny* aTrg, const TAny* aSrc, TInt aLength) +{ return (TUint8*)memmove(aTrg, aSrc, aLength) + aLength; } + + +/** Cleanup function. +@internalComponent +@param aArrayOfDictionaryCompressionBitStreams Pointer to an vector of +RDictionaryCompressionBitStream objects which have to be closed. */ +void CloseArrayOfDictionaryCompressionBitStreams(TAny* aArray) +{ + typedef std::vector RDictComprBitStream; + RDictComprBitStream* array = static_cast (aArray); + for (TInt i=array->size()-1;i>=0;--i) + { + array[i].clear(); + } + array->clear(); +} + +RResourceFileImpl::TExtra::TExtra(): + iBitArrayOfResourcesContainingCompressedUnicode(NULL), + iFileOffset(0), + iFileSize(0) +{ +} + + +RResourceFileImpl::TExtra::~TExtra() +{ + delete [] iDictionaryCompressionData.iCachedResourceBuffer; + iDictionaryCompressionData.iCachedResourceBuffer = NULL; + delete [] iDictionaryCompressionData.iCachedDictionaryIndex; + iDictionaryCompressionData.iCachedDictionaryIndex = 0; + + delete iBitArrayOfResourcesContainingCompressedUnicode; +} + + +TInt32 RResourceFileImpl::TExtra::ContainsCompressedUnicode(TInt& aRscIdx, TBool aFirstRscIsGen) const +{ + + if (aFirstRscIsGen) + { + // dictionary-compressed resource files can have an automatically generated + //resource which is the bit-array of resources containing compressed Unicode + //(this automatically generated resource does not have a corresponding bit + //for itself in the bit-array as it would be self-referring...) + --aRscIdx; + if (aRscIdx<0) + { + //aRscIdx is referring to the automatically generated resource + //(which is the bit-array of resources containing compressed Unicode) + return EFalse; + } + } + + assert(aRscIdx>=0); + + if (iBitArrayOfResourcesContainingCompressedUnicode==NULL) + { + return EFalse; + } + + TInt index = aRscIdx/8; + assert(index < iBitArrayOfResourcesContainingCompressedUnicode->GetLength()); + return (*iBitArrayOfResourcesContainingCompressedUnicode)[index]&(1<<(aRscIdx%8)); +} + + +RResourceFileImpl::RResourceFileImpl() : + iResourceContents(NULL), + iSizeOfLargestResourceWhenCompletelyUncompressed(0), + iIndex(NULL), + 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; +} + +/** Opens the resource file reader. +The resource file reader must be opened before reading resources or +checking the signature of the resource file. +@internalComponent +@param aName File to open as a resource file. +@param aFileOffset The resource file section offset from the beginning of the file. +@param aFileSize The resource file section size. +@leave - The file is corrupted. +*/ +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(); +} + + +/** +Retrieve the UID tuple of the opened resource file. + +@internalComponent +@pre OpenL() has been called successfully. +@return The UIDs of the loaded resource file. +*/ +TUidType RResourceFileImpl::UidType() const +{ + assert(iExtra!=NULL); + return iExtra->iUidType; +} + +/** Reads a resource into a heap buffer, returns a pointer to that +buffer. + +A heap buffer of appropriate length is allocated for the resource. +Ownership of the heap buffer passes to the caller who must destroy +it. The search for the resource uses the following algorithm:A +resource id in the range 1 to 4095 is looked up in this resource file. +The function leaves if there is no matching resource.If the resource +id is greater than 4095, then the most significant 20 bits of the +resource id is treated as an offset and the least significant 12 bits +is treated as the real resource id. If the offset matches the offset +value defined for this file, then the resource is looked up in this +resource file using the real resource id (i.e. the least significant +12 bits). If the offset does not match, then the function leaves.Note, +do not call this function until a call to +ConfirmSignatureL() has completed successfully. + +@internalComponent +@pre OpenL() is called. +@param aResourceId The numeric id of the resource to be read. +@return Pointer to a heap buffer containing the resource. +@panic Some BAFL panic codes, if the file is corrupted. +@leave - The file is corrupted. +@leave - There is no resource with aResourceId in the file. +*/ +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<0) + { + --resourceIndex; + } + else + { + assert(resourceIndex==0); + + Ptr8* resourceDataFor_RSS_SIGNATURE = new Ptr8(8); + if(NULL==resourceDataFor_RSS_SIGNATURE || NULL==resourceDataFor_RSS_SIGNATURE->GetPtr()) + { + std::string errMsg= "Failed : Error in Reading File. Memory Allocation Failed"; + throw CResourceFileException(errMsg); + } + + resourceDataFor_RSS_SIGNATURE->SetLength(8); + TUint* wordPointer=REINTERPRET_CAST(TUint*,CONST_CAST(TUint8*,resourceDataFor_RSS_SIGNATURE->GetPtr())); + + wordPointer[0]=4; + wordPointer[1]=((iExtra->iUidType[2].iUid << 12) | 1); + return resourceDataFor_RSS_SIGNATURE; + } + } + + + const TBool firstResourceIsGenerated= + (iFlagsAndNumberOfResources & + EFlagFirstResourceIsGeneratedBitArrayOfResourcesContainingCompressedUnicode); + if (firstResourceIsGenerated) + { + assert(iFlagsAndNumberOfResources & EFlagDictionaryCompressed); + //dictionary-compressed resource files can have an automatically generated + //resource which is the bit-array of resources containing compressed Unicode + //(this automatically generated resource does not have a corresponding bit for + //itself in the bit-array as it would be self-referring...) + ++resourceIndex; + } + + assert(resourceIndex>=0); + + Ptr8* const dictionaryDecompressedResourceData = DictionaryDecompressedResourceDataL(resourceIndex, + iFlagsAndNumberOfResources & static_cast(EAllFlags), + iExtra->iDictionaryCompressionData, + iIndex); + + // Return the resource data if its not unicode compressed. + if (!iExtra->ContainsCompressedUnicode(resourceIndex,firstResourceIsGenerated)) + { + return dictionaryDecompressedResourceData; + } + + Ptr8* const finalResourceData=DecompressUnicodeL(dictionaryDecompressedResourceData); + + delete dictionaryDecompressedResourceData; + return finalResourceData; + +} + +/** The method will decompress the unicode data (aInputResourceData argument), allocate enough +memory from the heap for the decompressed data, copy the data there and return a buffer +to the decompressed data. + +The method doesn't own the allocated heap memory for the decompressed data. It's a caller +responsibility to deallocate the allocated memory. + +@internalComponent +@param aInputResourceData Compressed data. +@pre OpenL() is called. +@leave - The file is corrupted. +@leave - There is not enough memory for the decompressed data. +*/ +Ptr8* RResourceFileImpl::DecompressUnicodeL(const Ptr8* aInputResourceData) const +{ + const TInt numberOfBytesInInput= aInputResourceData->GetLength(); + assert(iSizeOfLargestResourceWhenCompletelyUncompressed>0); + + Ptr8* outputResourceData= new Ptr8(iSizeOfLargestResourceWhenCompletelyUncompressed); + if(NULL==outputResourceData || NULL==outputResourceData->GetPtr()) + { + std::string errMsg= "Failed : Error in Reading File. Memory Allocation Failed"; + throw CResourceFileException(errMsg); + } + + const TUint8* input= aInputResourceData->GetPtr(); + TInt index=0; + + TBool decompressRun=ETrue; + while (1) + { + assert(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(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. +@leave - The file is corrupted. +*/ +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(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() or ReadL(). + +@internalComponent +@pre OpenL() is called. +@leave if the file is corrupted. +Some other error codes are possible too. +*/ +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); +} + +/** The method will decomress the unicode data (aCompressedUnicode argument) and append +the decompressed data to the end of aBuffer (aBuffer argument). + +@internalComponent +@pre OpenL() is called. +@param aBuffer Destination buffer. +@param aCompressedUnicode Compressed unicode buffer. +@leave - The file is corrupted. +*/ + +void RResourceFileImpl::AppendDecompressedUnicodeL( + Ptr8* aBuffer, + const TUint8* aCompressedUnicode, + const TInt& aLengthOfCompressedUnicode) const +{ + + if (aLengthOfCompressedUnicode>0) + { + TUint8* startOfDecompressedUnicode= aBuffer->GetPtr() + aBuffer->GetLength(); + + if (reinterpret_cast(startOfDecompressedUnicode) & 0x01) + { + TUint8 padChar = 0xab; + memcpy(startOfDecompressedUnicode,&padChar,1); + ++startOfDecompressedUnicode; + aBuffer->UpdateLength(1); + } + + const TInt maximumOutputLength= ( + iSizeOfLargestResourceWhenCompletelyUncompressed - (aBuffer->GetLength()))/2; + + TMemoryUnicodeSink decompressedUnicode(reinterpret_cast(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); + } +} + +/** Tests whether the resource file owns the specified resource id. + +The resource file owns the resource id if the most significant 20 bits +of the resource id are zero or match the offset value as returned from +a call to the Offset() member function or if the resource id is not out of range. + +@internalComponent +@pre OpenL() is called. +@param aResourceId The resource id to test. +@return True, if the resource file owns the id, false otherwise. +@leave - The file is corrupted. +*/ + +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); + if (iFlagsAndNumberOfResources & EFlagGenerate_RSS_SIGNATURE_ForFirstUserResource) + { + assert(iFlagsAndNumberOfResources & EFlagDictionaryCompressed); + assert(iFlagsAndNumberOfResources & EFlagThirdUidIsOffset); + ++numberOfResources; + } + if (iFlagsAndNumberOfResources & + EFlagFirstResourceIsGeneratedBitArrayOfResourcesContainingCompressedUnicode) + { + assert(iFlagsAndNumberOfResources & EFlagDictionaryCompressed); + --numberOfResources; + } + return (resourceIndex >= 0) && (resourceIndex < numberOfResources); +} + +TInt 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); + return iResourceContents->gcount(); +} + + +TInt RResourceFileImpl::ReadL(TInt aPos, TUint8* aData, const TInt& aLength) +{ + return ReadL(iFlagsAndNumberOfResources & static_cast(EAllFlags),aPos,aData,aLength); +} + + +TInt RResourceFileImpl::LittleEndianTwoByteInteger( + const TUint8* aBuffer, + const TInt& aIndexOfFirstByte, TInt aLength) const +{ + assert((aIndexOfFirstByte + 1) < aLength); + return aBuffer[aIndexOfFirstByte] | (aBuffer[aIndexOfFirstByte+1]<<8); +} + + +/** Function to retrieve the header information of the rsc file and all the + resource index information in the rsc file. This function is created to + handle the common functionality in the two OpenL() method. +@internalComponent +@pre OpenL() is called. +*/ + +void RResourceFileImpl::ReadHeaderAndResourceIndexL() +{ + SDictionaryCompressionData dictionaryCompressionData; + + TUidType uidType; + TInt length =0; + //dictionary-compressed resource files have a 21-byte header, + //16 bytes of checked UIDs followed by a 1-byte field and two 2-byte fields + TUint8 header[21]; + if(iExtra->iFileSize >= 16) + { + length = ReadL(0,header,Min((sizeof(header)/sizeof(header[0])),iExtra->iFileSize)); + uidType=TCheckedUid(header, 16).UidType(); + + if (uidType[0].iUid==0x101f4a6b) + { + iFlagsAndNumberOfResources |= EFlagPotentiallyContainsCompressedUnicode; + assert(length >= 18); + iSizeOfLargestResourceWhenCompletelyUncompressed = LittleEndianTwoByteInteger(header,16+1,length); + } + else if (uidType[0].iUid==0x101f5010) + { + iFlagsAndNumberOfResources |= + EFlagPotentiallyContainsCompressedUnicode | EFlagDictionaryCompressed; + assert(length >= 18); + iSizeOfLargestResourceWhenCompletelyUncompressed = LittleEndianTwoByteInteger(header,16+1,length); + } + else if (uidType[0]!=TUid::Null()) + { + std::string errMsg="Failed : Not Supported. Invalid Registration File."; + throw CResourceFileException(errMsg); + } + //the "signature" of Calypso's resource files + else if (LittleEndianTwoByteInteger(header,0,length)==4) + { + iFlagsAndNumberOfResources |= EFlagDictionaryCompressed | EFlagCalypsoFileFormat; + iSizeOfLargestResourceWhenCompletelyUncompressed = LittleEndianTwoByteInteger(header,8,length); + } + } + + //It seems that the following AssertDebL() call never fails, + //because LittleEndianTwoByteIntegerL always + //returns zero or positive value. + assert(iSizeOfLargestResourceWhenCompletelyUncompressed>=0); + TInt numberOfResources=0; + Ptr8* bitArrayOfResourcesContainingCompressedUnicode=NULL; + if (iFlagsAndNumberOfResources & EFlagDictionaryCompressed) + { + if (iFlagsAndNumberOfResources & EFlagCalypsoFileFormat) + { + assert(length > 10); + numberOfResources=LittleEndianTwoByteInteger(header,2,length); + const TInt numberOfBitsUsedForDictionaryTokens = header[10]; + const TInt numberOfDictionaryEntries = + (1 << numberOfBitsUsedForDictionaryTokens) - header[5]; + assert(numberOfDictionaryEntries >= 0); + // "+2" because the first entry in the dictionary-index in this file format + //is the number of bits from the start of the dictionary data to the start + //of the first dictionary entry which is always zero, and thus unnecessary + const TInt startOfDictionaryData=4+7+2; + // "+2" because the first entry in the resource-index in this file format is + //the number of bits from the start of the resource data to the start of the + //first resource which is always zero, and thus unnecessary + const TInt startOfResourceIndex=LittleEndianTwoByteInteger(header,6,length)+2; + assert(startOfResourceIndex >= 0); + dictionaryCompressionData.iStartOfDictionaryData= + startOfDictionaryData+(numberOfDictionaryEntries*2); + dictionaryCompressionData.iStartOfDictionaryIndex=startOfDictionaryData; + dictionaryCompressionData.iNumberOfDictionaryEntries=numberOfDictionaryEntries; + dictionaryCompressionData.iStartOfResourceData= + startOfResourceIndex+(numberOfResources*2); + dictionaryCompressionData.iStartOfResourceIndex=startOfResourceIndex; + dictionaryCompressionData.iNumberOfBitsUsedForDictionaryTokens= + numberOfBitsUsedForDictionaryTokens; + + if ((iFlagsAndNumberOfResources & static_cast(EFlagIsRomFile)) == 0) + { + // attempt to cache dictionary index + // allocate and populate the dictionary index buffer + dictionaryCompressionData.iCachedDictionaryIndex = new TUint16[numberOfDictionaryEntries]; + if (dictionaryCompressionData.iCachedDictionaryIndex != 0) + { + TInt len = numberOfDictionaryEntries * 2; + + Ptr8* ptr8 = new Ptr8(numberOfDictionaryEntries * 2); + if(NULL==ptr8 || NULL==ptr8->GetPtr()) + { + std::string errMsg= "Failed : Error in Reading File. Memory Allocation Failed"; + throw CResourceFileException(errMsg); + } + ptr8->UpdateLength(numberOfDictionaryEntries * 2); + ReadL( + iFlagsAndNumberOfResources & static_cast(EAllFlags), // aFlags + startOfDictionaryData, // aPos + (TUint8*)ptr8->GetPtr(), + len); // aLength + + memcpy((TUint8*)dictionaryCompressionData.iCachedDictionaryIndex, ptr8->GetPtr(), len); + if(NULL != ptr8) + { + delete ptr8; + } + } + } // if (iFlagsAndNumberOfResources & EFlagIsRomFile) + } + else + { + assert(length==16+1+2+2); + const TUint firstByteAfterUids=header[16]; + if (firstByteAfterUids & 0x80) + { + // this flag is only set if the resource file is dictionary-compressed + iFlagsAndNumberOfResources |= EFlagThirdUidIsOffset; + } + if (firstByteAfterUids & 0x40) + { + // this flag is only set if the resource file is dictionary-compressed + iFlagsAndNumberOfResources |= EFlagGenerate_RSS_SIGNATURE_ForFirstUserResource; + } + if (firstByteAfterUids & 0x20) + { + iFlagsAndNumberOfResources |= + EFlagFirstResourceIsGeneratedBitArrayOfResourcesContainingCompressedUnicode; + } + dictionaryCompressionData.iStartOfResourceData = LittleEndianTwoByteInteger(header,16+1+2,length); + TUint8 temp[2]; + length = ReadL((iExtra->iFileSize)-2,temp,2); + + const TInt numberOfBitsOfResourceData = LittleEndianTwoByteInteger(temp,0,length); + dictionaryCompressionData.iStartOfResourceIndex= + dictionaryCompressionData.iStartOfResourceData+ + ((numberOfBitsOfResourceData+7)/8); + numberOfResources=(iExtra->iFileSize-dictionaryCompressionData.iStartOfResourceIndex)/2; + dictionaryCompressionData.iStartOfDictionaryData=16+5; + if ((numberOfResources>0) && + !(iFlagsAndNumberOfResources & + EFlagFirstResourceIsGeneratedBitArrayOfResourcesContainingCompressedUnicode)) + { + const TInt lengthOfBitArrayInBytes=(numberOfResources+7)/8; + bitArrayOfResourcesContainingCompressedUnicode= new Ptr8(lengthOfBitArrayInBytes); + if(NULL==bitArrayOfResourcesContainingCompressedUnicode || NULL==bitArrayOfResourcesContainingCompressedUnicode->GetPtr()) + { + std::string errMsg= "Failed : Error in Reading File. Memory Allocation Failed"; + throw CResourceFileException(errMsg); + } + bitArrayOfResourcesContainingCompressedUnicode->UpdateLength(lengthOfBitArrayInBytes); + TUint8* asWritable = bitArrayOfResourcesContainingCompressedUnicode->GetPtr(); + ReadL(16+5,asWritable,lengthOfBitArrayInBytes); + dictionaryCompressionData.iStartOfDictionaryData+=lengthOfBitArrayInBytes; + } + length = ReadL(dictionaryCompressionData.iStartOfResourceData-2,temp,2); + const TInt numberOfBitsOfDictionaryData=LittleEndianTwoByteInteger(temp,0,length); + dictionaryCompressionData.iStartOfDictionaryIndex= + dictionaryCompressionData.iStartOfDictionaryData+ + ((numberOfBitsOfDictionaryData+7)/8); + dictionaryCompressionData.iNumberOfDictionaryEntries= + (dictionaryCompressionData.iStartOfResourceData- + dictionaryCompressionData.iStartOfDictionaryIndex)/2; + //the bottom 3 bits of firstByteAfterUids stores the number of bits used for + //dictionary tokens as an offset from 3, e.g. if 2 is stored in these three bits + //then the number of bits per dictionary token would be 3+2=5 - this allows a + //range of 3-11 bits per dictionary token (the maximum number of dictionary + //tokens therefore ranging from 8-2048) - the spec currently only supports 5-9 + //bits per dictionary token, however + dictionaryCompressionData.iNumberOfBitsUsedForDictionaryTokens= + 3 + (firstByteAfterUids & 0x07); + if ((numberOfResources>0) && + (iFlagsAndNumberOfResources & + EFlagFirstResourceIsGeneratedBitArrayOfResourcesContainingCompressedUnicode)) + { + Ptr16* nulldesc = new Ptr16(1); + if(NULL==nulldesc || NULL==nulldesc->GetPtr()) + { + std::string errMsg= "Failed : Error in Reading File. Memory Allocation Failed"; + throw CResourceFileException(errMsg); + } + *(nulldesc->GetPtr()) = 0; + nulldesc->UpdateLength(0); + + bitArrayOfResourcesContainingCompressedUnicode= + DictionaryDecompressedResourceDataL( + 0, + iFlagsAndNumberOfResources & static_cast(EAllFlags), + dictionaryCompressionData, + nulldesc); + if(NULL != nulldesc) + { + delete nulldesc; + } + } + } + } + else + { + assert((iExtra->iFileSize + iExtra->iFileOffset) > 2); + // This format of resource file is likely to be used for non-ROM resource files, + //so cache the resource-index (in iIndex) to minimize disk access. + // Ignore the flags in non-dictionary-compressed resource files - they are to + //be used only by a dictionary-compressing program. + const TInt KMaximumNumberOfBytesCached=256; + TUint8 cache[KMaximumNumberOfBytesCached]; + const TInt numberOfBytesCached=Min(iExtra->iFileSize,KMaximumNumberOfBytesCached); + TInt len = ReadL(iExtra->iFileSize-numberOfBytesCached,cache,numberOfBytesCached); + assert(len==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) + { + Ptr8* indexAsBinaryBuffer = new Ptr8(numberOfBytesOfIndex); + if(NULL==indexAsBinaryBuffer || NULL==indexAsBinaryBuffer->GetPtr()) + { + std::string errMsg= "Failed : Error in Reading File. Memory Allocation Failed"; + throw CResourceFileException(errMsg); + } + + indexAsBinaryBuffer->UpdateLength(numberOfBytesOfIndex); + BufCpy8(indexAsBinaryBuffer->GetPtr(), cache+(numberOfBytesCached - numberOfBytesOfIndex) , numberOfBytesOfIndex); + + iIndex = new Ptr16(numberOfBytesOfIndex/2); + if(NULL==iIndex || NULL==iIndex->GetPtr()) + { + std::string errMsg= "Failed : Error in Reading File. Memory Allocation Failed"; + throw CResourceFileException(errMsg); + } + + MemCopy(CONST_CAST(TUint16*,(TUint16*)iIndex->GetPtr()),indexAsBinaryBuffer->GetPtr(),numberOfBytesOfIndex); + iIndex->UpdateLength(numberOfBytesOfIndex/2); + + if(NULL != indexAsBinaryBuffer) + { + delete indexAsBinaryBuffer; + } + } + else + { + Ptr16* const index=new Ptr16(numberOfBytesOfIndex/2); + if(NULL==index || NULL==index->GetPtr()) + { + std::string errMsg= "Failed : Error in Reading File. Memory Allocation Failed"; + throw CResourceFileException(errMsg); + } + index->UpdateLength(numberOfBytesOfIndex/2); + + Ptr8* indexAsWritableBinaryBuffer = new Ptr8(numberOfBytesOfIndex); + if(NULL==indexAsWritableBinaryBuffer || NULL==indexAsWritableBinaryBuffer->GetPtr()) + { + std::string errMsg= "Failed : Error in Reading File. Memory Allocation Failed"; + throw CResourceFileException(errMsg); + } + indexAsWritableBinaryBuffer->UpdateLength(numberOfBytesOfIndexStillToRetrieve); + + ReadL(positionOfStartOfIndex,indexAsWritableBinaryBuffer->GetPtr(), + numberOfBytesOfIndexStillToRetrieve); + assert(indexAsWritableBinaryBuffer->GetLength()==numberOfBytesOfIndexStillToRetrieve); + indexAsWritableBinaryBuffer->Append(cache, len); + indexAsWritableBinaryBuffer->UpdateLength(len); + assert(indexAsWritableBinaryBuffer->GetLength()==numberOfBytesOfIndex); + assert(indexAsWritableBinaryBuffer->GetLength()==index->GetLength()*2); + memcpy((TUint8*)index->GetPtr(), indexAsWritableBinaryBuffer->GetPtr() , numberOfBytesOfIndex); + + iIndex=index; + if(NULL != indexAsWritableBinaryBuffer) + { + delete indexAsWritableBinaryBuffer; + } + } + + //"-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) && + (iFlagsAndNumberOfResources & EFlagPotentiallyContainsCompressedUnicode)) + { + const TInt lengthOfBitArrayInBytes=(numberOfResources+7)/8; + bitArrayOfResourcesContainingCompressedUnicode= new Ptr8(lengthOfBitArrayInBytes); + if(NULL==bitArrayOfResourcesContainingCompressedUnicode || NULL==bitArrayOfResourcesContainingCompressedUnicode->GetPtr()) + { + std::string errMsg= "Failed : Error in Reading File. Memory Allocation Failed"; + throw CResourceFileException(errMsg); + } + bitArrayOfResourcesContainingCompressedUnicode->UpdateLength(lengthOfBitArrayInBytes); + TUint8* bitArray = bitArrayOfResourcesContainingCompressedUnicode->GetPtr(); + //"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,bitArray,lengthOfBitArrayInBytes); + } + } + assert((numberOfResources & EAllFlags)==0); + assert((iFlagsAndNumberOfResources & ~EAllFlags)==0); + iFlagsAndNumberOfResources |= (numberOfResources & ~EAllFlags); + iExtra->iUidType = uidType; + iExtra->iBitArrayOfResourcesContainingCompressedUnicode = bitArrayOfResourcesContainingCompressedUnicode; + iExtra->iBitArrayOfResourcesContainingCompressedUnicode->SetLength(bitArrayOfResourcesContainingCompressedUnicode->GetLength()); + iExtra->iDictionaryCompressionData = dictionaryCompressionData; + //iOffset is set by calling ConfirmSignatureL + assert(iOffset==0); +} + + +/** @internalComponent +@pre OpenL() is called. +@leave KErrCorrupt The file is corrupted. +@leave KErrNoMemory There is not enough memory for the decompressed data. +Some other error codes are possible too. +*/ +Ptr8* RResourceFileImpl::DictionaryDecompressedResourceDataL( + TInt aResourceIndex, + TUint aFlags, + const SDictionaryCompressionData& aDictionaryCompressionData, + const Ptr16* aIndex) const +{ + if (aFlags & EFlagDictionaryCompressed) + { + assert(iSizeOfLargestResourceWhenCompletelyUncompressed>0); + Ptr8* const outputResourceData = new Ptr8(iSizeOfLargestResourceWhenCompletelyUncompressed); + if(NULL==outputResourceData || NULL==outputResourceData->GetPtr()) + { + std::string errMsg= "Failed : Error in Reading File. Memory Allocation Failed"; + throw CResourceFileException(errMsg); + } + + Ptr8* asWritable = outputResourceData; + std::vector stackOfDictionaryCompressionBitStreams; + AppendDictionaryCompressionBitStreamL( + stackOfDictionaryCompressionBitStreams, + aFlags, + aDictionaryCompressionData, + aDictionaryCompressionData.iStartOfResourceData, + aDictionaryCompressionData.iStartOfResourceIndex, + aResourceIndex); + const TBool calypsoFileFormat=(aFlags & EFlagCalypsoFileFormat); + while(1) + { + const TInt indexOfTopBitStream=stackOfDictionaryCompressionBitStreams.size()-1; + assert(indexOfTopBitStream>=-1); + if (indexOfTopBitStream<0) + { + break; + } + RDictionaryCompressionBitStream& dictionaryCompressionBitStream= + stackOfDictionaryCompressionBitStreams[indexOfTopBitStream]; + + while(1) + { + if (dictionaryCompressionBitStream.EndOfStreamL()) + { + dictionaryCompressionBitStream.Close(); + stackOfDictionaryCompressionBitStreams.erase(indexOfTopBitStream); + break; + } + const TInt indexOfDictionaryEntry= + dictionaryCompressionBitStream.IndexOfDictionaryEntryL(); + if (indexOfDictionaryEntry<0) + { + dictionaryCompressionBitStream.ReadL(asWritable,calypsoFileFormat); + } + else + { + AppendDictionaryCompressionBitStreamL( + stackOfDictionaryCompressionBitStreams, + aFlags, + aDictionaryCompressionData, + aDictionaryCompressionData.iStartOfDictionaryData, + aDictionaryCompressionData.iStartOfDictionaryIndex, + indexOfDictionaryEntry); + break; + } + } + } + stackOfDictionaryCompressionBitStreams.clear(); + return outputResourceData; + } + + assert(aResourceIndex < aIndex->GetLength()); + + const TInt positionOfResourceData=(*aIndex)[aResourceIndex]; + const TInt numberOfBytes=(*aIndex)[aResourceIndex+1]-positionOfResourceData; + + assert(numberOfBytes >= 0); + Ptr8* const outputResourceData= new Ptr8(numberOfBytes); + if(NULL==outputResourceData || NULL==outputResourceData->GetPtr()) + { + std::string errMsg= "Failed : Error in Reading File. Memory Allocation Failed"; + throw CResourceFileException(errMsg); + } + + TUint8* asWritable = outputResourceData->GetPtr(); + ReadL(aFlags,positionOfResourceData,asWritable,numberOfBytes); + outputResourceData->UpdateLength(numberOfBytes); + + return outputResourceData; + +} + + +void RResourceFileImpl::AppendDictionaryCompressionBitStreamL( + std::vector& aStackOfDictionaryCompressionBitStreams, + TUint aFlags, + const SDictionaryCompressionData& aDictionaryCompressionData, + TInt aStartOfBitData, + TInt aStartOfIndex, + TInt aIndexEntry) const +{ + const TBool isRomFile=(aFlags & static_cast(EFlagIsRomFile)); + TUint8 temp[4]; + TInt length = 0; + assert(aIndexEntry>=0); + TInt offsetToFirstBit; + TInt offsetOnePastLastBit; + if ( aDictionaryCompressionData.iStartOfDictionaryIndex == aStartOfIndex + && aDictionaryCompressionData.iCachedDictionaryIndex != 0) + { + assert(!isRomFile); + // indices start at 1 + offsetToFirstBit = (aIndexEntry <= 0) + ? 0 + : aDictionaryCompressionData.iCachedDictionaryIndex[aIndexEntry-1]; + offsetOnePastLastBit = aDictionaryCompressionData.iCachedDictionaryIndex[aIndexEntry]; + } + else + { + TInt len = ReadL(aFlags,aStartOfIndex+((aIndexEntry-1)*2),temp,4); + offsetToFirstBit=(aIndexEntry > 0) ? LittleEndianTwoByteInteger(temp,0,len) : 0; + offsetOnePastLastBit=LittleEndianTwoByteInteger(temp,2,len); + } + TInt rsc_file_size = iExtra->iFileOffset + iExtra->iFileSize; + TInt offset_first = offsetToFirstBit / 8 + iExtra->iFileOffset; + assert(offset_first < rsc_file_size); + TInt offset_last = offsetOnePastLastBit / 8 + iExtra->iFileOffset; + assert(offset_last <= rsc_file_size); + TUint8* buffer = NULL; + TInt start_pos = 0; + if (isRomFile) + { + TInt startOfBitData = aStartOfBitData + iExtra->iFileOffset; + assert(startOfBitData < rsc_file_size); + buffer = startOfBitData; + } + else + { + const TInt offsetToByteContainingFirstBit=offsetToFirstBit/8; + const TInt offsetToOnePastByteContainingLastBit=((offsetOnePastLastBit-1)/8)+1; + const TInt numberOfBytesToLoad= + offsetToOnePastByteContainingLastBit-offsetToByteContainingFirstBit; + assert(numberOfBytesToLoad >= 0); + buffer=new TUint8[numberOfBytesToLoad]; + if(NULL==buffer) + { + std::string errMsg= "Failed : Error in Reading File. Memory Allocation Failed"; + throw CResourceFileException(errMsg); + } + + if( iExtra->iDictionaryCompressionData.iCachedResourceBuffer == 0) + { + iExtra->iDictionaryCompressionData.iCachedResourceBuffer=new TUint8[rsc_file_size]; // reserver buffer for whole file + if(NULL==iExtra->iDictionaryCompressionData.iCachedResourceBuffer) + { + delete buffer; // buffer deleted in RDictionaryCompressionBitStream::close + std::string errMsg= "Failed : Error in Reading File. Memory Allocation Failed"; + throw CResourceFileException(errMsg); + } + + Ptr8* JKasWritable = new Ptr8(rsc_file_size); + if(NULL==JKasWritable || NULL == JKasWritable->GetPtr()) + { + delete buffer; // buffer deleted in RDictionaryCompressionBitStream::close + std::string errMsg= "Failed : Error in Reading File. Memory Allocation Failed"; + throw CResourceFileException(errMsg); + } + JKasWritable->UpdateLength(rsc_file_size); + + try { + length = ReadL(0,(TUint8*)JKasWritable->GetPtr(), rsc_file_size); + } + catch(...) + { + delete buffer; // buffer deleted in RDictionaryCompressionBitStream::close + std::string errMsg= "Failed : Error in Reading File."; + throw CResourceFileException(errMsg); + } + + BufCpy8(iExtra->iDictionaryCompressionData.iCachedResourceBuffer, JKasWritable->GetPtr(), length); + if(NULL != JKasWritable) + { + delete JKasWritable; + } + } + start_pos = aStartOfBitData + offsetToByteContainingFirstBit + iExtra->iFileOffset; + assert(start_pos < rsc_file_size); + assert((start_pos + numberOfBytesToLoad) <= rsc_file_size); + const TInt numberOfBitsFromStartOfBitDataToFirstLoadedByte= + offsetToByteContainingFirstBit*8; + offsetToFirstBit-=numberOfBitsFromStartOfBitDataToFirstLoadedByte; + offsetOnePastLastBit-=numberOfBitsFromStartOfBitDataToFirstLoadedByte; + + MemCopy( buffer, iExtra->iDictionaryCompressionData.iCachedResourceBuffer + start_pos, numberOfBytesToLoad); + } + RDictionaryCompressionBitStream stream; + stream.OpenL( + aDictionaryCompressionData.iNumberOfBitsUsedForDictionaryTokens, + offsetToFirstBit, + offsetOnePastLastBit, + !isRomFile, + buffer); + try { + aStackOfDictionaryCompressionBitStreams.push_back(stream); + } + catch(...) + { + delete buffer; // buffer deleted in RDictionaryCompressionBitStream::close + std::string errMsg= "Failed : Error in Reading File."; + throw CResourceFileException(errMsg); + } + if (!isRomFile) + { + delete buffer; // buffer deleted in RDictionaryCompressionBitStream::close + } +} +