diff -r 26b6f0522fd8 -r 8110bf1194d1 secureswitools/swisistools/source/rscparser/barscimpl.cpp --- a/secureswitools/swisistools/source/rscparser/barscimpl.cpp Mon May 03 12:38:03 2010 +0300 +++ b/secureswitools/swisistools/source/rscparser/barscimpl.cpp Fri May 14 15:58:48 2010 +0300 @@ -25,25 +25,71 @@ #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(const TInt& aRscIdx) const +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) @@ -52,19 +98,19 @@ } TInt index = aRscIdx/8; - - return (iBitArrayOfResourcesContainingCompressedUnicode)[index]&(1<<(aRscIdx%8)); - } + assert(index < iBitArrayOfResourcesContainingCompressedUnicode->GetLength()); + return (*iBitArrayOfResourcesContainingCompressedUnicode)[index]&(1<<(aRscIdx%8)); +} RResourceFileImpl::RResourceFileImpl() : iResourceContents(NULL), iSizeOfLargestResourceWhenCompletelyUncompressed(0), - iIndex(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 @@ -75,7 +121,7 @@ //Fixed "iOffset" position - because of the BC reasons. assert(offsetof(RResourceFileImpl, iOffset)==12); - } +} RResourceFileImpl::~RResourceFileImpl() @@ -101,7 +147,15 @@ 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, @@ -156,29 +210,49 @@ } -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; - } +/** +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:"; @@ -186,44 +260,105 @@ 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(EAllFlags)); - - // Return the resource data if its not unicode compressed. - if (!iExtra->ContainsCompressedUnicode(resourceIndex)) + if (iFlagsAndNumberOfResources & EFlagGenerate_RSS_SIGNATURE_ForFirstUserResource) + { + assert(iFlagsAndNumberOfResources & EFlagDictionaryCompressed); + assert(iFlagsAndNumberOfResources & EFlagThirdUidIsOffset); + + if (resourceIndex>0) + { + --resourceIndex; + } + else { - return decompressedResourceData; + 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; } + } - // Get the decompressed unicode data. - Ptr8* finalResourceData= DecompressUnicodeL(decompressedResourceData); + + 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; + } - delete decompressedResourceData; - return finalResourceData; + 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. -@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. */ +@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); @@ -312,19 +443,13 @@ 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(). +calling Offset(), AllocReadL() 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. +@leave if 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. @@ -340,23 +465,33 @@ 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) { - - 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; @@ -379,15 +514,28 @@ 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)) // { @@ -396,17 +544,27 @@ const TInt resourceIndex=(aResourceId & EIdBits)-1; TInt numberOfResources=(iFlagsAndNumberOfResources & ~EAllFlags); - - return (resourceIndex >= 0) && (resourceIndex < numberOfResources); + 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); +} -void RResourceFileImpl::ReadL( +TInt RResourceFileImpl::ReadL( const TUint32& aFlags, TInt aPos, TUint8* aData, const TInt& aLength) - { +{ aPos += iExtra->iFileOffset; assert(aPos >= iExtra->iFileOffset); @@ -415,125 +573,557 @@ // Seek to the offset specified by "aPos" iResourceContents->seekg(aPos, std::ios_base::beg); - iResourceContents->read((char*)aData, aLength); - } + iResourceContents->read((char*)aData, aLength); + return iResourceContents->gcount(); +} -void RResourceFileImpl::ReadL(TInt aPos, TUint8* aData, const TInt& aLength) - { - ReadL(iFlagsAndNumberOfResources & static_cast(EAllFlags),aPos,aData,aLength); - } +TInt RResourceFileImpl::ReadL(TInt aPos, TUint8* aData, const TInt& aLength) +{ + return ReadL(iFlagsAndNumberOfResources & static_cast(EAllFlags),aPos,aData,aLength); +} TInt RResourceFileImpl::LittleEndianTwoByteInteger( - TUint8* aBuffer, - const TInt& aIndexOfFirstByte) const - { + const TUint8* aBuffer, + const TInt& aIndexOfFirstByte, TInt aLength) const +{ + assert((aIndexOfFirstByte + 1) < aLength); return aBuffer[aIndexOfFirstByte] | (aBuffer[aIndexOfFirstByte+1]<<8); - } +} -void RResourceFileImpl::ReadHeaderAndResourceIndexL() - { +/** 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. +*/ - // 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) - { +void RResourceFileImpl::ReadHeaderAndResourceIndexL() +{ + SDictionaryCompressionData dictionaryCompressionData; - // 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) + 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) { - iFlagsAndNumberOfResources |= EFlagPotentiallyContainsCompressedUnicode; - iSizeOfLargestResourceWhenCompletelyUncompressed= LittleEndianTwoByteInteger(header,16+1); + // 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; } - else + if (firstByteAfterUids & 0x40) + { + // this flag is only set if the resource file is dictionary-compressed + iFlagsAndNumberOfResources |= EFlagGenerate_RSS_SIGNATURE_ForFirstUserResource; + } + if (firstByteAfterUids & 0x20) { - if (iResourceContents->is_open()) - iResourceContents->close(); - std::string errMsg="Failed : Unsupported RSC file type"; - throw CResourceFileException(errMsg); + 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; + } } } - - TInt numberOfResources= 0; - TUint8* bitArrayOfResourcesContainingCompressedUnicode= NULL; - - if (iFlagsAndNumberOfResources & EFlagPotentiallyContainsCompressedUnicode) + } + 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) { - // 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; + 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; + } + } - 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(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."; + //"-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); - } - - const TInt lengthOfBitArrayInBytes=(numberOfResources+7)/8; - bitArrayOfResourcesContainingCompressedUnicode= - new TUint8(lengthOfBitArrayInBytes); - + } + 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,bitArrayOfResourcesContainingCompressedUnicode,lengthOfBitArrayInBytes); + 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; - assert((numberOfResources & EAllFlags)==0); - assert((iFlagsAndNumberOfResources & ~EAllFlags)==0); - - iFlagsAndNumberOfResources |= (numberOfResources & ~EAllFlags); - iExtra->iUid = uid; - iExtra->iBitArrayOfResourcesContainingCompressedUnicode = bitArrayOfResourcesContainingCompressedUnicode; +} + + +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 + } +} +