sl@0: // Copyright (c) 2003-2009 Nokia Corporation and/or its subsidiary(-ies). sl@0: // All rights reserved. sl@0: // This component and the accompanying materials are made available sl@0: // under the terms of "Eclipse Public License v1.0" sl@0: // which accompanies this distribution, and is available sl@0: // at the URL "http://www.eclipse.org/legal/epl-v10.html". sl@0: // sl@0: // Initial Contributors: sl@0: // Nokia Corporation - initial contribution. sl@0: // sl@0: // Contributors: sl@0: // sl@0: // Description: sl@0: // sl@0: sl@0: #include sl@0: #include "BADICTIONARYCOMPRESSION.H" sl@0: #include "BaRscImpl.h" sl@0: #include "BaAssert.h" sl@0: #include "BaCompileAssert.h" sl@0: sl@0: /** TCleanupItem function. sl@0: @internalComponent sl@0: @param aFile Pointer to the RFile instance which has to be closed. */ sl@0: LOCAL_C void CloseAndDeleteFile(TAny* aFile) sl@0: { sl@0: RFile* const file=STATIC_CAST(RFile*,aFile); sl@0: if (file!=NULL) sl@0: { sl@0: file->Close(); sl@0: delete file; sl@0: } sl@0: } sl@0: sl@0: /** TCleanupItem function. sl@0: @internalComponent sl@0: @param aArrayOfDictionaryCompressionBitStreams Pointer to an array (RArray) of sl@0: RDictionaryCompressionBitStream objects which have to be closed. */ sl@0: LOCAL_C void CloseArrayOfDictionaryCompressionBitStreams(TAny* aArray) sl@0: { sl@0: typedef RArray RDictComprBitStream; sl@0: RDictComprBitStream* array = static_cast (aArray); sl@0: for (TInt i=array->Count()-1;i>=0;--i) sl@0: { sl@0: array[i].Close(); sl@0: } sl@0: array->Close(); sl@0: } sl@0: sl@0: /** @internalComponent */ sl@0: struct SDictionaryCompressionData sl@0: { sl@0: inline SDictionaryCompressionData() : sl@0: iStartOfDictionaryData(0), sl@0: iStartOfDictionaryIndex(0), sl@0: iNumberOfDictionaryEntries(0), sl@0: iStartOfResourceData(0), sl@0: iStartOfResourceIndex(0), sl@0: iNumberOfBitsUsedForDictionaryTokens(0), sl@0: iCachedDictionaryIndex(0), sl@0: iCachedResourceBuffer(0)// = NULL; sl@0: { sl@0: } sl@0: TInt iStartOfDictionaryData; sl@0: TInt iStartOfDictionaryIndex; sl@0: TInt iNumberOfDictionaryEntries; sl@0: TInt iStartOfResourceData; sl@0: TInt iStartOfResourceIndex; sl@0: TInt iNumberOfBitsUsedForDictionaryTokens; sl@0: TUint16* iCachedDictionaryIndex; sl@0: TUint8* iCachedResourceBuffer; sl@0: sl@0: }; sl@0: sl@0: /** @internalComponent */ sl@0: class RResourceFileImpl::TExtra sl@0: { sl@0: public: sl@0: TExtra(const TBaAssert& aAssertObj); sl@0: ~TExtra(); sl@0: TBool ContainsCompressedUnicodeL(TInt aRscIdx, TBool aFirstRscIsGen) const; sl@0: private: sl@0: TExtra(const TExtra&);//prevent default copy constructor sl@0: TExtra& operator=(const TExtra&);//prevent default "=" operator sl@0: public: sl@0: TUidType iUidType; sl@0: HBufC8* iBitArrayOfResourcesContainingCompressedUnicode; // an array of bits, one for each resource in the resource file sl@0: SDictionaryCompressionData iDictionaryCompressionData; sl@0: TInt iFileOffset; // offset of RSC chunk in new AIF file format sl@0: TBaAssert iAssertObj; sl@0: TInt iFileSize; // RSC chunc size - in new AIF file format, file size otherwise sl@0: }; sl@0: sl@0: /** @internalComponent sl@0: @param aAssertObj Object which will determine RResourceFileImpl::TExtra sl@0: instance's behaviour if something goes wrong - depending on aAssertObj state sl@0: RResourceFileImpl::TExtra methods will leave or panic. */ sl@0: RResourceFileImpl::TExtra::TExtra(const TBaAssert& aAssertObj) : sl@0: iUidType(), sl@0: iBitArrayOfResourcesContainingCompressedUnicode(NULL), sl@0: iDictionaryCompressionData(), sl@0: iFileOffset(0), sl@0: iAssertObj(aAssertObj), sl@0: iFileSize(0) sl@0: { sl@0: } sl@0: sl@0: /** @internalComponent */ sl@0: RResourceFileImpl::TExtra::~TExtra() sl@0: { sl@0: delete iBitArrayOfResourcesContainingCompressedUnicode; sl@0: } sl@0: sl@0: /** @internalComponent */ sl@0: TBool RResourceFileImpl::TExtra::ContainsCompressedUnicodeL(TInt aRscIdx, TBool aFirstRscIsGen) const sl@0: { sl@0: if (aFirstRscIsGen) sl@0: { sl@0: // dictionary-compressed resource files can have an automatically generated sl@0: //resource which is the bit-array of resources containing compressed Unicode sl@0: //(this automatically generated resource does not have a corresponding bit sl@0: //for itself in the bit-array as it would be self-referring...) sl@0: --aRscIdx; sl@0: if (aRscIdx<0) sl@0: { sl@0: //aRscIdx is referring to the automatically generated resource sl@0: //(which is the bit-array of resources containing compressed Unicode) sl@0: return EFalse; sl@0: } sl@0: } sl@0: iAssertObj.AssertDebL(aRscIdx>=0, EBafPanicNegativeResourceIndex1); sl@0: if (iBitArrayOfResourcesContainingCompressedUnicode==NULL) sl@0: { sl@0: return EFalse; sl@0: } sl@0: TInt index = aRscIdx / 8; sl@0: iAssertObj.AssertDebL(index < iBitArrayOfResourcesContainingCompressedUnicode->Length(), EBafPanicBadIndex); sl@0: return (*iBitArrayOfResourcesContainingCompressedUnicode)[index]&(1<<(aRscIdx%8)); sl@0: } sl@0: sl@0: /** @internalComponent */ sl@0: RResourceFileImpl::RResourceFileImpl() : sl@0: iFile(NULL), sl@0: iSizeOfLargestResourceWhenCompletelyUncompressed(0), sl@0: iIndex(NULL), sl@0: iOffset(0), sl@0: iExtra(NULL), sl@0: iFlagsAndNumberOfResources(0) sl@0: { sl@0: //Fixed class size - because of the BC reasons. sl@0: //RResourceFileImpl size must be the same as RResourceFile size. sl@0: enum sl@0: { sl@0: KRscFileImplSize = 24 sl@0: }; sl@0: COMPILE_TIME_ASSERT(sizeof(RResourceFileImpl)==KRscFileImplSize); sl@0: // MSVC++ & GCCE can't handle this template instantiation sl@0: #if !defined(__VC32__) && !defined(__GCCE__) && !defined(__X86GCC__) sl@0: //Fixed "iOffset" position - because of the BC reasons. sl@0: COMPILE_TIME_ASSERT(_FOFF(RResourceFileImpl, iOffset)==12); sl@0: #endif sl@0: } sl@0: sl@0: /** Closes the resource file reader. sl@0: This function is called after finishing reading all resources. sl@0: @internalComponent */ sl@0: void RResourceFileImpl::Close() sl@0: { sl@0: if ((iFile!=NULL) && ((iFlagsAndNumberOfResources & static_cast(EFlagIsRomFile))==0 sl@0: && (iFlagsAndNumberOfResources & static_cast(EFlagIsBufferRscFile))==0)) sl@0: { sl@0: RFile* const file=STATIC_CAST(RFile*,iFile); sl@0: file->Close(); sl@0: delete file; sl@0: } sl@0: //Here it indicates that it is reading from a HBufC8 rsc file buffer so we need to free the heap here sl@0: if ((iFile!=NULL) && ((iFlagsAndNumberOfResources & static_cast(EFlagIsBufferRscFile))!=0)) sl@0: { sl@0: HBufC8* buffer=STATIC_CAST(HBufC8*,iFile); sl@0: delete buffer; sl@0: } sl@0: iFile=NULL; sl@0: iSizeOfLargestResourceWhenCompletelyUncompressed=0; sl@0: delete iIndex; sl@0: iIndex=NULL; sl@0: if (iExtra) sl@0: { sl@0: delete [] iExtra->iDictionaryCompressionData.iCachedResourceBuffer; sl@0: iExtra->iDictionaryCompressionData.iCachedResourceBuffer = NULL; sl@0: delete [] iExtra->iDictionaryCompressionData.iCachedDictionaryIndex; sl@0: iExtra->iDictionaryCompressionData.iCachedDictionaryIndex = 0; sl@0: delete iExtra; sl@0: iExtra=NULL; sl@0: } sl@0: iFlagsAndNumberOfResources=0; sl@0: iOffset=0; sl@0: } sl@0: sl@0: /** Opens the resource file reader. sl@0: The resource file reader must be opened before reading resources or sl@0: checking the signature of the resource file. This function initially sl@0: closes the resource-file object if it is currently open. If a leave sl@0: occurs during the function, the object is reverted to its closed state. sl@0: @internalComponent sl@0: @param aFs Handle to a file server session. sl@0: @param aName File to open as a resource file. sl@0: @param aAssert Object which will be used to determine panic/leave behaviour sl@0: of the "L" methods. sl@0: @param aFileOffset The resource file section offset from the beginning of the file. sl@0: @param aFileSize The resource file section size. sl@0: @panic Some BAFL panic codes. sl@0: @leave KErrCorrupt The file is corrupted. sl@0: The method could panic or leave depending on the state of sl@0: iAssertObj member of RResourceFileImpl::TExtra class. */ sl@0: void RResourceFileImpl::OpenL(RFs &aFs, const TDesC &aName, const TBaAssert& aAssert, sl@0: TUint aFileOffset/* = 0 */, TInt aFileSize/* = 0 */) sl@0: { sl@0: Close(); sl@0: CleanupClosePushL(*this); sl@0: RFile* const file=new(ELeave) RFile; sl@0: CleanupStack::PushL(TCleanupItem(CloseAndDeleteFile,file)); sl@0: User::LeaveIfError(file->Open(aFs, aName, EFileStream | EFileRead | EFileShareReadersOnly)); sl@0: iExtra=new (ELeave) TExtra(aAssert); sl@0: const TBaAssert& assert_obj = iExtra->iAssertObj; sl@0: iExtra->iFileOffset = aFileOffset; sl@0: TInt fileSize = 0; sl@0: if (aFileSize) sl@0: { sl@0: // With new format AIF, the RSC file is part of a larger file, so we need to set the sl@0: // size of the RSC file here. sl@0: fileSize = aFileSize; sl@0: assert_obj.AssertDebL(fileSize > TInt(aFileOffset), EBafPanicBadOpenArg); sl@0: } sl@0: else sl@0: { sl@0: User::LeaveIfError(file->Size(fileSize)); sl@0: assert_obj.AssertDebL(fileSize > 0, EBafPanicFileSize2); sl@0: } sl@0: TUint8* romAddress=NULL; sl@0: TInt seekRc(KErrNotSupported); sl@0: sl@0: // ESeekAddress in emulator will just get -5 and NULL romAddress. sl@0: // On emulator there is also undesirable effect that after the call the ROM sl@0: // resource file cannot be deleted while emulator is running. Seems base has sl@0: // some kind of handle open on the rsc. One licensee has a use case to sl@0: // re-compile resources while emulator is running. Hence Seek only in hw. sl@0: #ifndef __WINSCW__ sl@0: seekRc = file->Seek(ESeekAddress,REINTERPRET_CAST(TInt&,romAddress)); sl@0: #endif sl@0: sl@0: if (romAddress==NULL || seekRc !=KErrNone) sl@0: { sl@0: iFile=file; sl@0: // At the 1st line of this function we call Close() which sets sl@0: // iFlagsAndNUmberOfResources to zero. Nothing between Close() and here changes sl@0: // iFlagsAndNumberOfResources. So no need to assert EFlagIsRomFile is cleared. sl@0: // assert_obj.AssertDebL((iFlagsAndNumberOfResources & static_cast(EFlagIsRomFile))==0, sl@0: // EBafPanicBadInitialization1); sl@0: CleanupStack::Pop(file); sl@0: } sl@0: else sl@0: { sl@0: iFile=CONST_CAST(TUint8*,romAddress); sl@0: iFlagsAndNumberOfResources |= static_cast(EFlagIsRomFile); sl@0: CleanupStack::PopAndDestroy(file); sl@0: } sl@0: iExtra->iFileSize = fileSize; sl@0: ReadHeaderAndResourceIndexL(); sl@0: CleanupStack::Pop(this); sl@0: } sl@0: sl@0: /** Opens the resource file reader. sl@0: The resource file reader must be opened before reading resources or sl@0: checking the signature of the resource file. This function initially sl@0: closes the resource-file object if it is currently open. If a leave sl@0: occurs during the function, the object is reverted to its closed state. sl@0: @internalComponent sl@0: @param aRscArchive buffer containing a full rsc file sl@0: @param aAssert Object which will be used to determine panic/leave behaviour sl@0: of the "L" methods. sl@0: @panic Some BAFL panic codes. sl@0: @leave KErrCorrupt The file is corrupted. sl@0: The method could panic or leave depending on the state of sl@0: iAssertObj member of RResourceFileImpl::TExtra class. */ sl@0: sl@0: void RResourceFileImpl::OpenL(const TDesC8& aRscArchive,const TBaAssert& aAssert) sl@0: { sl@0: Close(); sl@0: CleanupClosePushL(*this); sl@0: sl@0: iExtra=new (ELeave) TExtra(aAssert); sl@0: sl@0: //Since we are getting the entire buffer of the rsc file, we can treat sl@0: //this equivalent to a ROM rsc file by pointing the iFile to sl@0: //the start of the aRscArchive. We can depend directly on existing ReadL sl@0: //to retrive the bytes directly from memory. No file open is required sl@0: //and the handling of the rest of the rsc file is an exact copy of the sl@0: //previous OpenL().A good way to reduce ROM size is to split the reading sl@0: //part of the resource file into one separate function.//TODO sl@0: //We also dont care about any fileOffset as the aRscArchive contains only sl@0: //the buffer for one entire rsc file. sl@0: //Get the length of the rsc file sl@0: TInt fileSize=aRscArchive.Length(); sl@0: //iFile=STATIC_CAST(TAny*,(aRscArchive.AllocL())->Des()).Ptr()); sl@0: iFile = aRscArchive.AllocL(); sl@0: iExtra->iFileSize=fileSize; sl@0: iFlagsAndNumberOfResources |= static_cast(EFlagIsBufferRscFile); sl@0: sl@0: ReadHeaderAndResourceIndexL(); sl@0: CleanupStack::Pop(this); sl@0: } sl@0: sl@0: /** sl@0: Retrieve the UID tuple of the opened resource file. sl@0: sl@0: @internalComponent sl@0: @pre OpenL() has been called successfully. sl@0: @return The UIDs of the loaded resource file. sl@0: @panic BAFL 36 - data members are not initialized(probably - OpenL() hasn't been called). */ sl@0: TUidType RResourceFileImpl::UidType() const sl@0: { sl@0: __ASSERT_ALWAYS(iExtra!=NULL,Panic(EBafPanicNotOpened)); sl@0: return iExtra->iUidType; sl@0: } sl@0: sl@0: /** Reads a resource specified by resource id into the specified descriptor. sl@0: The descriptor must be long enough to contain the entire resource. The sl@0: search for the resource uses the following algorithm: A resource id in sl@0: the range 1 to 4095 is looked up in this resource file. The function sl@0: leaves if there is no matching resource. If the resource id is greater sl@0: than 4095, then the most significant 20 bits of the resource id is sl@0: treated as an offset and the least significant 12 bits is treated as sl@0: the real resource id. If the offset matches the offset value defined sl@0: for this file, then the resource is looked up in this resource file sl@0: using the real resource id (i.e. the least significant 12 bits). If sl@0: the offset does not match, then the function leaves. Note, do not call sl@0: this function until a call to ConfirmSignatureL() has sl@0: completed successfully. sl@0: @internalComponent sl@0: @pre OpenL() is called. sl@0: @param aDes On return, contains the resource that has been read. sl@0: The function leaves if the descriptor is not long sl@0: enough to contain the entire resource. sl@0: @param aResourceId The numeric id of the resource to be read. The sl@0: function leaves if this resource id is not in this resource file. sl@0: @see ConfirmSignatureL() sl@0: @panic Some BAFL panic codes, if the file is corrupted. sl@0: @leave KErrCorrupt The file is corrupted. Some other error codes sl@0: are possible too. sl@0: The method could panic or leave depending on the state of sl@0: iAssertObj member of RResourceFileImpl::TExtra class. */ sl@0: void RResourceFileImpl::ReadL(TDes8 &aDes,TInt aResourceId) const sl@0: { sl@0: HBufC8* const resource=AllocReadLC(aResourceId); sl@0: aDes=*resource; sl@0: CleanupStack::PopAndDestroy(resource); sl@0: } sl@0: sl@0: /** Reads a resource into a heap descriptor, returns a pointer to that sl@0: descriptor and pushes the pointer onto the cleanup stack. sl@0: sl@0: A heap descriptor of appropriate length is allocated for the resource. sl@0: Ownership of the heap descriptor passes to the caller who must destroy sl@0: it and pop its pointer off the cleanup stack when it is no longer sl@0: needed.The search for the resource uses the following algorithm:A sl@0: resource id in the range 1 to 4095 is looked up in this resource file. sl@0: The function leaves if there is no matching resource.If the resource sl@0: id is greater than 4095, then the most significant 20 bits of the sl@0: resource id is treated as an offset and the least significant 12 bits sl@0: is treated as the real resource id. If the offset matches the offset sl@0: value defined for this file, then the resource is looked up in this sl@0: resource file using the real resource id (i.e. the least significant sl@0: 12 bits). If the offset does not match, then the function leaves.Note, sl@0: do not call this function until a call to sl@0: ConfirmSignatureL() has completed successfully. sl@0: sl@0: @internalComponent sl@0: @pre OpenL() is called. sl@0: @param aResourceId The numeric id of the resource to be read. sl@0: @return Pointer to a heap descriptor containing the resource. sl@0: @see ConfirmSignatureL() sl@0: @panic Some BAFL panic codes, if the file is corrupted. sl@0: @leave KErrCorrupt The file is corrupted. sl@0: @leave KErrNotFound There is no resource with aResourceId in the file. sl@0: Some other error codes are possible too. sl@0: The method could panic or leave depending on the state of sl@0: iAssertObj member of RResourceFileImpl::TExtra class. */ sl@0: HBufC8* RResourceFileImpl::AllocReadLC(TInt aResourceId) const sl@0: { sl@0: if (!OwnsResourceIdL(aResourceId)) sl@0: { sl@0: User::Leave(KErrNotFound); sl@0: } sl@0: const TBaAssert& assert_obj = iExtra->iAssertObj; sl@0: //"-1" because the first resource has ID 0x*****001 (not 0x*****000) sl@0: TInt resourceIndex=(aResourceId & EIdBits)-1; sl@0: if (iFlagsAndNumberOfResources & EFlagGenerate_RSS_SIGNATURE_ForFirstUserResource) sl@0: { sl@0: assert_obj.AssertDebL(iFlagsAndNumberOfResources & EFlagDictionaryCompressed, sl@0: EBafPanicBadFlags1); sl@0: assert_obj.AssertDebL(iFlagsAndNumberOfResources & EFlagThirdUidIsOffset, sl@0: EBafPanicBadFlags2); sl@0: if (resourceIndex>0) sl@0: { sl@0: --resourceIndex; sl@0: } sl@0: else sl@0: { sl@0: assert_obj.AssertDebL(resourceIndex==0, EBafPanicNegativeResourceIndex2); sl@0: HBufC8* const resourceDataFor_RSS_SIGNATURE=HBufC8::NewMaxLC(8); sl@0: TUint* wordPointer=REINTERPRET_CAST(TUint*,CONST_CAST( sl@0: TUint8*,resourceDataFor_RSS_SIGNATURE->Ptr())); sl@0: wordPointer[0]=4; sl@0: wordPointer[1]=((iExtra->iUidType[2].iUid << 12) | 1); sl@0: return resourceDataFor_RSS_SIGNATURE; sl@0: } sl@0: } sl@0: const TBool firstResourceIsGenerated= sl@0: (iFlagsAndNumberOfResources & sl@0: EFlagFirstResourceIsGeneratedBitArrayOfResourcesContainingCompressedUnicode); sl@0: if (firstResourceIsGenerated) sl@0: { sl@0: assert_obj.AssertDebL(iFlagsAndNumberOfResources & sl@0: EFlagDictionaryCompressed, EBafPanicBadFlags6); sl@0: //dictionary-compressed resource files can have an automatically generated sl@0: //resource which is the bit-array of resources containing compressed Unicode sl@0: //(this automatically generated resource does not have a corresponding bit for sl@0: //itself in the bit-array as it would be self-referring...) sl@0: ++resourceIndex; sl@0: } sl@0: assert_obj.AssertDebL(resourceIndex>=0, EBafPanicNegativeResourceIndex3); sl@0: HBufC8* const dictionaryDecompressedResourceData=DictionaryDecompressedResourceDataLC( sl@0: resourceIndex, sl@0: iFlagsAndNumberOfResources & static_cast(EAllFlags), sl@0: iExtra->iDictionaryCompressionData, sl@0: *iIndex); sl@0: if (!iExtra->ContainsCompressedUnicodeL(resourceIndex,firstResourceIsGenerated)) sl@0: { sl@0: return dictionaryDecompressedResourceData; sl@0: } sl@0: HBufC8* const finalResourceData=DecompressUnicodeL( sl@0: *dictionaryDecompressedResourceData, sl@0: iSizeOfLargestResourceWhenCompletelyUncompressed); sl@0: CleanupStack::PopAndDestroy(dictionaryDecompressedResourceData); sl@0: CleanupStack::PushL(finalResourceData); sl@0: return finalResourceData; sl@0: } sl@0: sl@0: /** @internalComponent sl@0: @return The first resource record. sl@0: @panic Some BAFL panic codes, if the file is corrupted. sl@0: @leave KErrCorrupt The file is corrupted. sl@0: Some other error codes are possible too. sl@0: The method could panic or leave depending on the state of sl@0: iAssertObj member of RResourceFileImpl::TExtra class. */ sl@0: RResourceFileImpl::SSigRecord RResourceFileImpl::FirstRecordL() const sl@0: { sl@0: // Added to support reading of rel 6.x resource files. sl@0: // rel 6.x files do not have signatures! sl@0: sl@0: HBufC8* const firstResource=AllocReadLC(1); sl@0: sl@0: // Basic check to test if the signature is of the correct size. sl@0: if (firstResource->Size() != sizeof(SSigRecord)) sl@0: { sl@0: User::Leave(KErrCorrupt); sl@0: } sl@0: SSigRecord sigRecord = *reinterpret_cast(firstResource->Ptr()); sl@0: CleanupStack::PopAndDestroy(firstResource); sl@0: return sigRecord; sl@0: } sl@0: sl@0: /** Initialises the offset value from the first resource. sl@0: The function assumes that the first resource in the file consists of sl@0: two 32-bit integers. The first integer contains the version number and sl@0: the second is a self-referencing link whose value is the offset for sl@0: the resources in the file, plus 1.This function must be called before sl@0: calling Offset(), AllocReadL(), AllocReadLC() or ReadL(). sl@0: @internalComponent sl@0: @pre OpenL() is called. sl@0: @param aSignature This argument value is not used by the function. sl@0: @see Offset() sl@0: @see AllocReadL() sl@0: @see AllocReadLC() sl@0: @see ReadL() sl@0: @panic Some BAFL panic codes, if the file is corrupted. sl@0: @leave KErrCorrupt The file is corrupted. sl@0: Some other error codes are possible too. sl@0: The method could panic or leave depending on the state of sl@0: iAssertObj member of RResourceFileImpl::TExtra class. */ sl@0: void RResourceFileImpl::ConfirmSignatureL(TInt /*aSignature*/) sl@0: { sl@0: SSigRecord first_record=FirstRecordL(); sl@0: // test removed by SC 29/09/98 - assume that existing resource layout and structures sl@0: //are fixed now sl@0: // if (first_record.signature!=aSignature) sl@0: // Leave(KErrBaflWrongResourceFileSignature); sl@0: iOffset=first_record.offset & EOffsetBits; sl@0: } sl@0: sl@0: /** Initialises the offset value from the first resource. sl@0: sl@0: The function tests to catch cases where the first resource is not an RSS_SIGNATURE. sl@0: It assumes that the first resource in the file consists of sl@0: two 32-bit integers. The first integer contains the version number and sl@0: the second is a self-referencing link whose value is the offset for sl@0: the resources in the file, plus 1.This function must be called before sl@0: calling Offset(), AllocReadL(), AllocReadLC() or ReadL(). sl@0: sl@0: @see Offset() sl@0: @see AllocReadL() sl@0: @see AllocReadLC() sl@0: @see ReadL() sl@0: @internalComponent sl@0: @pre OpenL() is called. sl@0: @panic Some BAFL panic codes, if the file is corrupted. sl@0: @leave KErrCorrupt The file is corrupted. sl@0: Some other error codes are possible too. sl@0: The method could panic or leave depending on the state of sl@0: iAssertObj member of RResourceFileImpl::TExtra class. */ sl@0: void RResourceFileImpl::ConfirmSignatureL() sl@0: { sl@0: // Added to support reading of rel 6.x resource files. sl@0: sl@0: SSigRecord firstRecord=FirstRecordL(); sl@0: sl@0: // If the resource offset does not correspond to the first resource sl@0: // this is not a resource signature. sl@0: if ((firstRecord.offset & EIdBits) != 1) sl@0: { sl@0: User::Leave(KErrCorrupt); sl@0: } sl@0: iOffset=(firstRecord.offset & EOffsetBits); sl@0: } sl@0: sl@0: /** @internalComponent sl@0: @pre OpenL() is called. sl@0: @panic Some BAFL panic codes, if the file is corrupted. sl@0: @leave KErrCorrupt The file is corrupted. sl@0: Some other error codes are possible too. sl@0: The method could panic or leave depending on the state of sl@0: iAssertObj member of RResourceFileImpl::TExtra class. */ sl@0: TInt RResourceFileImpl::SignatureL() const sl@0: { sl@0: SSigRecord first_record=FirstRecordL(); sl@0: return first_record.signature; sl@0: } sl@0: sl@0: /** Tests whether the resource file owns the specified resource id. sl@0: sl@0: The resource file owns the resource id if the most significant 20 bits sl@0: of the resource id are zero or match the offset value as returned from sl@0: a call to the Offset() member function or if the resource id is not out of range. sl@0: sl@0: @internalComponent sl@0: @see Offset() sl@0: @pre OpenL() is called. sl@0: @param aResourceId The resource id to test. sl@0: @return True, if the resource file owns the id, false otherwise. sl@0: @panic Some BAFL panic codes, if the file is corrupted. sl@0: @leave KErrCorrupt The file is corrupted. sl@0: Some other error codes are possible too. sl@0: The method could panic or leave depending on the state of sl@0: iAssertObj member of RResourceFileImpl::TExtra class. */ sl@0: TBool RResourceFileImpl::OwnsResourceIdL(TInt aResourceId) const sl@0: { sl@0: // whether owns resource: does so if offset 0, or matches that given, sl@0: //and id is in index sl@0: const TInt offset=(aResourceId & EOffsetBits); sl@0: if ((offset!=0) && (offset!=iOffset)) sl@0: { sl@0: return EFalse; sl@0: } sl@0: const TBaAssert& assert_obj = iExtra->iAssertObj; sl@0: const TInt resourceIndex=(aResourceId & EIdBits)-1; sl@0: TInt numberOfResources=(iFlagsAndNumberOfResources & ~EAllFlags); sl@0: if (iFlagsAndNumberOfResources & EFlagGenerate_RSS_SIGNATURE_ForFirstUserResource) sl@0: { sl@0: assert_obj.AssertDebL(iFlagsAndNumberOfResources & EFlagDictionaryCompressed, sl@0: EBafPanicBadFlags3); sl@0: assert_obj.AssertDebL(iFlagsAndNumberOfResources & EFlagThirdUidIsOffset, sl@0: EBafPanicBadFlags4); sl@0: ++numberOfResources; sl@0: } sl@0: if (iFlagsAndNumberOfResources & sl@0: EFlagFirstResourceIsGeneratedBitArrayOfResourcesContainingCompressedUnicode) sl@0: { sl@0: iExtra->iAssertObj.AssertDebL(iFlagsAndNumberOfResources & EFlagDictionaryCompressed, sl@0: EBafPanicBadFlags5); sl@0: --numberOfResources; sl@0: } sl@0: return (resourceIndex >= 0) && (resourceIndex < numberOfResources); sl@0: } sl@0: sl@0: /** The method will decomress the unicode data (aCompressedUnicode argument) and append sl@0: the decompressed data to the end of aBuffer (aBuffer argument). sl@0: sl@0: @internalComponent sl@0: @pre OpenL() is called. sl@0: @param aBuffer Destination buffer. sl@0: @param aCompressedUnicode Compressed unicode buffer. sl@0: @panic Some BAFL panic codes, if the file is corrupted. sl@0: @leave KErrCorrupt The file is corrupted. sl@0: Some other error codes are possible too. sl@0: The method could panic or leave depending on the state of sl@0: iAssertObj member of RResourceFileImpl::TExtra class. */ sl@0: void RResourceFileImpl::AppendDecompressedUnicodeL( sl@0: TDes8& aBuffer, sl@0: const TDesC8& aCompressedUnicode) const sl@0: { sl@0: const TBaAssert& assert_obj = iExtra->iAssertObj; sl@0: const TInt lengthOfCompressedUnicode=aCompressedUnicode.Length(); sl@0: if (lengthOfCompressedUnicode>0) sl@0: { sl@0: const TUint8* startOfDecompressedUnicode=aBuffer.Ptr()+aBuffer.Length(); sl@0: if (REINTERPRET_CAST(TUint,startOfDecompressedUnicode) & 0x01) sl@0: { sl@0: assert_obj.AssertDebL(aBuffer.MaxLength() >= (aBuffer.Length() + 1), sl@0: EBafPanicMaxLength2); sl@0: aBuffer.Append(0xab); sl@0: ++startOfDecompressedUnicode; sl@0: } sl@0: //works correctly, even if aBuffer.MaxLength()-aBuffer.Length() is an odd number sl@0: const TInt maximumOutputLength=(aBuffer.MaxLength()-aBuffer.Length())/2; sl@0: TMemoryUnicodeSink decompressedUnicode(REINTERPRET_CAST(TUint16*,CONST_CAST( sl@0: TUint8*,startOfDecompressedUnicode))); sl@0: TInt lengthOfDecompressedUnicode; sl@0: TInt numberOfInputBytesConsumed; sl@0: TUnicodeExpander unicodeExpander; sl@0: unicodeExpander.ExpandL(decompressedUnicode, sl@0: aCompressedUnicode.Ptr(), sl@0: maximumOutputLength, sl@0: lengthOfCompressedUnicode, sl@0: &lengthOfDecompressedUnicode, sl@0: &numberOfInputBytesConsumed); sl@0: TInt temp; sl@0: unicodeExpander.FlushL(decompressedUnicode,maximumOutputLength,temp); sl@0: lengthOfDecompressedUnicode+=temp; sl@0: assert_obj.AssertRelL(numberOfInputBytesConsumed==lengthOfCompressedUnicode, sl@0: EBafPanicBadDecompression); sl@0: aBuffer.SetLength(aBuffer.Length()+(lengthOfDecompressedUnicode*2)); sl@0: } sl@0: } sl@0: sl@0: /** The method will decompress the unicode data (aInputResourceData argument), allocate enough sl@0: memory from the heap for the decompressed data, copy the data there and return a descriptor sl@0: to the decompressed data. sl@0: sl@0: The method doesn't own the allocated heap memory for the decompressed data. It's a caller sl@0: responsibility to deallocate the allocated memory. sl@0: sl@0: @internalComponent sl@0: @param aInputResourceData Compressed data. sl@0: @param aSizeOfLargestResourceWhenCompletelyUncompressed The size of decomressed data. sl@0: @pre OpenL() is called. sl@0: @panic Some BAFL panic codes, if the file is corrupted. sl@0: @leave KErrCorrupt The file is corrupted. sl@0: @leave KErrNoMemory There is not enough memory for the decompressed data. sl@0: Some other error codes are possible too. sl@0: The method could panic or leave depending on the state of sl@0: iAssertObj member of RResourceFileImpl::TExtra class. */ sl@0: HBufC8* RResourceFileImpl::DecompressUnicodeL(const TDesC8& aInputResourceData, sl@0: TInt aSizeOfLargestResourceWhenCompletelyUncompressed) const sl@0: { sl@0: const TBaAssert& assert_obj = iExtra->iAssertObj; sl@0: const TInt numberOfBytesInInput=aInputResourceData.Length(); sl@0: assert_obj.AssertDebL(aSizeOfLargestResourceWhenCompletelyUncompressed>0, sl@0: EBafPanicBadSizeOfLargestResourceWhenCompletelyUncompressed2); sl@0: HBufC8* const outputResourceData= sl@0: HBufC8::NewLC(aSizeOfLargestResourceWhenCompletelyUncompressed); sl@0: TPtr8 asWritable(outputResourceData->Des()); sl@0: const TUint8* input=aInputResourceData.Ptr(); sl@0: TInt index=0; sl@0: for (TBool decompressRun=ETrue; ; decompressRun=!decompressRun) sl@0: { sl@0: assert_obj.AssertDebL(index=numberOfBytesInInput) sl@0: { sl@0: User::Leave(KErrCorrupt); sl@0: } sl@0: runLength &= ~0x80; sl@0: runLength <<= 8; sl@0: runLength |= input[index]; sl@0: } sl@0: ++index; sl@0: if (runLength>0) sl@0: { sl@0: const TPtrC8 run(input+index,runLength); sl@0: if (decompressRun) sl@0: { sl@0: AppendDecompressedUnicodeL(asWritable,run); sl@0: } sl@0: else sl@0: { sl@0: assert_obj.AssertDebL( sl@0: (asWritable.Length() + runLength) <= asWritable.MaxLength(), sl@0: EBafPanicOverflow); sl@0: asWritable.Append(run); sl@0: } sl@0: index+=runLength; sl@0: } sl@0: if (index>numberOfBytesInInput) sl@0: { sl@0: User::Leave(KErrCorrupt); sl@0: } sl@0: if (index>=numberOfBytesInInput) sl@0: { sl@0: break; sl@0: } sl@0: } sl@0: CleanupStack::Pop(outputResourceData); sl@0: return outputResourceData; sl@0: } sl@0: sl@0: /** @internalComponent sl@0: @pre OpenL() is called. sl@0: @panic Some BAFL panic codes, if the file is corrupted. sl@0: @leave KErrCorrupt The file is corrupted. sl@0: @leave KErrNoMemory There is not enough memory for the decompressed data. sl@0: Some other error codes are possible too. sl@0: The method could panic or leave depending on the state of sl@0: iAssertObj member of RResourceFileImpl::TExtra class. */ sl@0: HBufC8* RResourceFileImpl::DictionaryDecompressedResourceDataLC( sl@0: TInt aResourceIndex, sl@0: TUint aFlags, sl@0: const SDictionaryCompressionData& aDictionaryCompressionData, sl@0: const TDesC16& aIndex) const sl@0: { sl@0: const TBaAssert& assert_obj = iExtra->iAssertObj; sl@0: if (aFlags & EFlagDictionaryCompressed) sl@0: { sl@0: assert_obj.AssertDebL(iSizeOfLargestResourceWhenCompletelyUncompressed>0, sl@0: EBafPanicBadSizeOfLargestResourceWhenCompletelyUncompressed3); sl@0: HBufC8* const outputResourceData= sl@0: HBufC8::NewLC(iSizeOfLargestResourceWhenCompletelyUncompressed); sl@0: TPtr8 asWritable(outputResourceData->Des()); sl@0: RArray stackOfDictionaryCompressionBitStreams; sl@0: CleanupStack::PushL( sl@0: TCleanupItem(CloseArrayOfDictionaryCompressionBitStreams, sl@0: &stackOfDictionaryCompressionBitStreams)); sl@0: AppendDictionaryCompressionBitStreamL( sl@0: stackOfDictionaryCompressionBitStreams, sl@0: aFlags, sl@0: aDictionaryCompressionData, sl@0: aDictionaryCompressionData.iStartOfResourceData, sl@0: aDictionaryCompressionData.iStartOfResourceIndex, sl@0: aResourceIndex); sl@0: const TBool calypsoFileFormat=(aFlags & EFlagCalypsoFileFormat); sl@0: FOREVER sl@0: { sl@0: const TInt indexOfTopBitStream=stackOfDictionaryCompressionBitStreams.Count()-1; sl@0: assert_obj.AssertDebL(indexOfTopBitStream>=-1, EBafPanicNegativeArrayIndex); sl@0: if (indexOfTopBitStream<0) sl@0: { sl@0: break; sl@0: } sl@0: RDictionaryCompressionBitStream& dictionaryCompressionBitStream= sl@0: stackOfDictionaryCompressionBitStreams[indexOfTopBitStream]; sl@0: FOREVER sl@0: { sl@0: if (dictionaryCompressionBitStream.EndOfStreamL()) sl@0: { sl@0: dictionaryCompressionBitStream.Close(); sl@0: stackOfDictionaryCompressionBitStreams.Remove(indexOfTopBitStream); sl@0: break; sl@0: } sl@0: const TInt indexOfDictionaryEntry= sl@0: dictionaryCompressionBitStream.IndexOfDictionaryEntryL(); sl@0: if (indexOfDictionaryEntry<0) sl@0: { sl@0: dictionaryCompressionBitStream.ReadL(asWritable,calypsoFileFormat); sl@0: } sl@0: else sl@0: { sl@0: AppendDictionaryCompressionBitStreamL( sl@0: stackOfDictionaryCompressionBitStreams, sl@0: aFlags, sl@0: aDictionaryCompressionData, sl@0: aDictionaryCompressionData.iStartOfDictionaryData, sl@0: aDictionaryCompressionData.iStartOfDictionaryIndex, sl@0: indexOfDictionaryEntry); sl@0: break; sl@0: } sl@0: } sl@0: } sl@0: CleanupStack::PopAndDestroy(&stackOfDictionaryCompressionBitStreams); sl@0: return outputResourceData; sl@0: } sl@0: assert_obj.AssertDebL(aResourceIndex < aIndex.Length(), EBafPanicBadIndex2); sl@0: const TInt positionOfResourceData=aIndex[aResourceIndex]; sl@0: const TInt numberOfBytes=aIndex[aResourceIndex+1]-positionOfResourceData; sl@0: assert_obj.AssertDebL(numberOfBytes >= 0, EBafPanicNegativeNumber3); sl@0: HBufC8* const outputResourceData=HBufC8::NewLC(numberOfBytes); sl@0: TPtr8 asWritable(outputResourceData->Des()); sl@0: ReadL(aFlags,positionOfResourceData,asWritable,numberOfBytes); sl@0: return outputResourceData; sl@0: } sl@0: sl@0: /** @internalComponent sl@0: @pre OpenL() is called. sl@0: @panic Some BAFL panic codes, if the file is corrupted. sl@0: @leave KErrCorrupt The file is corrupted. sl@0: Some other error codes are possible too. sl@0: The method could panic or leave depending on the state of sl@0: iAssertObj member of RResourceFileImpl::TExtra class. */ sl@0: void RResourceFileImpl::AppendDictionaryCompressionBitStreamL( sl@0: RArray& aStackOfDictionaryCompressionBitStreams, sl@0: TUint aFlags, sl@0: const SDictionaryCompressionData& aDictionaryCompressionData, sl@0: TInt aStartOfBitData, sl@0: TInt aStartOfIndex, sl@0: TInt aIndexEntry) const sl@0: { sl@0: const TBaAssert& assert_obj = iExtra->iAssertObj; sl@0: const TBool isRomFile=(aFlags & static_cast(EFlagIsRomFile)); sl@0: TBuf8<4> temp; sl@0: assert_obj.AssertDebL(aIndexEntry>=0, EBafPanicNegativeIndexEntry); sl@0: TInt offsetToFirstBit; sl@0: TInt offsetOnePastLastBit; sl@0: if ( aDictionaryCompressionData.iStartOfDictionaryIndex == aStartOfIndex sl@0: && aDictionaryCompressionData.iCachedDictionaryIndex != 0) sl@0: { sl@0: __ASSERT_DEBUG(!isRomFile,User::Invariant()); sl@0: // indices start at 1 sl@0: offsetToFirstBit = (aIndexEntry <= 0) sl@0: ? 0 sl@0: : aDictionaryCompressionData.iCachedDictionaryIndex[aIndexEntry-1]; sl@0: offsetOnePastLastBit = aDictionaryCompressionData.iCachedDictionaryIndex[aIndexEntry]; sl@0: } sl@0: else sl@0: { sl@0: ReadL(aFlags,aStartOfIndex+((aIndexEntry-1)*2),temp,4); sl@0: offsetToFirstBit=(aIndexEntry > 0) ? LittleEndianTwoByteIntegerL(temp,0) : 0; sl@0: offsetOnePastLastBit=LittleEndianTwoByteIntegerL(temp,2); sl@0: } sl@0: TInt rsc_file_size = iExtra->iFileOffset + iExtra->iFileSize; sl@0: TInt offset_first = offsetToFirstBit / 8 + iExtra->iFileOffset; sl@0: assert_obj.AssertDebL(offset_first < rsc_file_size, EBafPanicBadOffset); sl@0: TInt offset_last = offsetOnePastLastBit / 8 + iExtra->iFileOffset; sl@0: assert_obj.AssertDebL(offset_last <= rsc_file_size, EBafPanicBadOffset2); sl@0: TUint8* buffer = NULL; sl@0: TInt start_pos = 0; sl@0: if (isRomFile) sl@0: { sl@0: TInt startOfBitData = aStartOfBitData + iExtra->iFileOffset; sl@0: assert_obj.AssertDebL(startOfBitData < rsc_file_size, EBafPanicStartPos); sl@0: //for some reason, GCC gives a warning if the sl@0: //STATIC_CAST(const TUint8*,aFile) is used instead of STATIC_CAST(TUint8*,aFile) sl@0: buffer = STATIC_CAST(TUint8*,iFile) + startOfBitData; sl@0: } sl@0: else sl@0: { sl@0: const TInt offsetToByteContainingFirstBit=offsetToFirstBit/8; sl@0: const TInt offsetToOnePastByteContainingLastBit=((offsetOnePastLastBit-1)/8)+1; sl@0: const TInt numberOfBytesToLoad= sl@0: offsetToOnePastByteContainingLastBit-offsetToByteContainingFirstBit; sl@0: assert_obj.AssertDebL(numberOfBytesToLoad >= 0, EBafPanicNegativeNumber2); sl@0: buffer=new(ELeave) TUint8[numberOfBytesToLoad]; sl@0: CleanupArrayDeletePushL(buffer); sl@0: if( iExtra->iDictionaryCompressionData.iCachedResourceBuffer == 0) sl@0: { sl@0: iExtra->iDictionaryCompressionData.iCachedResourceBuffer=new(ELeave) TUint8[rsc_file_size]; // reserver buffer for whole file sl@0: TPtr8 JKasWritable(iExtra->iDictionaryCompressionData.iCachedResourceBuffer,rsc_file_size); sl@0: User::LeaveIfError( sl@0: STATIC_CAST(RFile*,iFile)->Read( sl@0: 0, sl@0: JKasWritable, sl@0: rsc_file_size)); sl@0: } sl@0: start_pos = aStartOfBitData + offsetToByteContainingFirstBit + iExtra->iFileOffset; sl@0: assert_obj.AssertDebL(start_pos < rsc_file_size, EBafPanicStartPos2); sl@0: assert_obj.AssertDebL((start_pos + numberOfBytesToLoad) <= rsc_file_size, EBafPanicFileSize4); sl@0: const TInt numberOfBitsFromStartOfBitDataToFirstLoadedByte= sl@0: offsetToByteContainingFirstBit*8; sl@0: offsetToFirstBit-=numberOfBitsFromStartOfBitDataToFirstLoadedByte; sl@0: offsetOnePastLastBit-=numberOfBitsFromStartOfBitDataToFirstLoadedByte; sl@0: sl@0: Mem::Copy( buffer, iExtra->iDictionaryCompressionData.iCachedResourceBuffer + start_pos, numberOfBytesToLoad); sl@0: } sl@0: RDictionaryCompressionBitStream stream; sl@0: stream.OpenL( sl@0: aDictionaryCompressionData.iNumberOfBitsUsedForDictionaryTokens, sl@0: offsetToFirstBit, sl@0: offsetOnePastLastBit, sl@0: !isRomFile, sl@0: buffer, sl@0: assert_obj); sl@0: User::LeaveIfError(aStackOfDictionaryCompressionBitStreams.Append(stream)); sl@0: if (!isRomFile) sl@0: { sl@0: CleanupStack::Pop(buffer); // buffer deleted in RDictionaryCompressionBitStream::close sl@0: } sl@0: } sl@0: sl@0: /** @internalComponent sl@0: @pre OpenL() is called. */ sl@0: TInt RResourceFileImpl::LittleEndianTwoByteIntegerL( sl@0: const TDesC8& aBuffer, sl@0: TInt aIndexOfFirstByte) const sl@0: { sl@0: iExtra->iAssertObj.AssertDebL((aIndexOfFirstByte + 1) < aBuffer.Length(), EBafPanicBadIndex3); sl@0: return aBuffer[aIndexOfFirstByte] | (aBuffer[aIndexOfFirstByte+1]<<8); sl@0: } sl@0: sl@0: /** @internalComponent sl@0: @pre OpenL() is called. */ sl@0: void RResourceFileImpl::ReadL(TUint aFlags,TInt aPos,TDes8& aDes,TInt aLength) const sl@0: { sl@0: aPos += iExtra->iFileOffset; sl@0: const TBaAssert& assert_obj = iExtra->iAssertObj; sl@0: assert_obj.AssertDebL(aPos >= iExtra->iFileOffset, EBafPanicNegativePos); sl@0: assert_obj.AssertDebL(aLength >= 0, EBafPanicNegativeLength); sl@0: assert_obj.AssertDebL(aLength <= aDes.MaxLength(), EBafPanicMaxLength); sl@0: assert_obj.AssertDebL((aPos + aLength) <= (iExtra->iFileOffset + iExtra->iFileSize), EBafPanicFileSize3); sl@0: if (aFlags & static_cast(EFlagIsRomFile)) sl@0: { sl@0: //for some reason, GCC gives a warning if the sl@0: //STATIC_CAST(const TUint8*,aFile) is used instead of STATIC_CAST(TUint8*,aFile) sl@0: aDes.Copy(STATIC_CAST(TUint8*,iFile)+aPos,aLength); sl@0: } sl@0: else if (aFlags & static_cast(EFlagIsBufferRscFile)) sl@0: { sl@0: HBufC8* buffer=STATIC_CAST(HBufC8*,iFile); sl@0: aDes.Copy(CONST_CAST(TUint8*,buffer->Ptr())+aPos,aLength); sl@0: } sl@0: else sl@0: { sl@0: User::LeaveIfError(STATIC_CAST(RFile*,iFile)->Read(aPos,aDes,aLength)); sl@0: } sl@0: } sl@0: sl@0: /** @internalComponent sl@0: @pre OpenL() is called. */ sl@0: void RResourceFileImpl::ReadL(TInt aPos,TDes8& aDes,TInt aLength) const sl@0: { sl@0: ReadL(iFlagsAndNumberOfResources & static_cast(EAllFlags),aPos,aDes,aLength); sl@0: } sl@0: sl@0: /** Returns the offset value defined for this resource file. sl@0: sl@0: This function must not be called until a call to sl@0: ConfirmSignatureL() has completed successfully, otherwise sl@0: the value returned by this function may be meaningless. sl@0: sl@0: @see ConfirmSignatureL() sl@0: @internalComponent sl@0: @pre OpenL() is called. sl@0: @return The offset value defined for this resource file. sl@0: */ sl@0: TInt RResourceFileImpl::Offset() const sl@0: { sl@0: return iOffset; sl@0: } sl@0: sl@0: /** Function to retrieve the header information of the rsc file and all the sl@0: resource index information in the rsc file. This function is created to sl@0: handle the common functionality in the two OpenL() method. sl@0: @internalComponent sl@0: @pre OpenL() is called. sl@0: */ sl@0: void RResourceFileImpl::ReadHeaderAndResourceIndexL() sl@0: { sl@0: SDictionaryCompressionData dictionaryCompressionData; sl@0: const TBaAssert& assert_obj = iExtra->iAssertObj; sl@0: TUidType uidType; sl@0: //dictionary-compressed resource files have a 21-byte header, sl@0: //16 bytes of checked UIDs followed by a 1-byte field and two 2-byte fields sl@0: TBuf8<21> header; sl@0: if(iExtra->iFileSize >= 16) sl@0: { sl@0: ReadL(0,header,Min(header.MaxLength(),iExtra->iFileSize)); sl@0: uidType=TCheckedUid(header.Left(16)).UidType(); sl@0: if (uidType[0].iUid==0x101f4a6b) sl@0: { sl@0: iFlagsAndNumberOfResources |= EFlagPotentiallyContainsCompressedUnicode; sl@0: assert_obj.AssertDebL(header.Length() >= 18, EBafPanicBadHeader1); sl@0: iSizeOfLargestResourceWhenCompletelyUncompressed= sl@0: LittleEndianTwoByteIntegerL(header,16+1); sl@0: } sl@0: else if (uidType[0].iUid==0x101f5010) sl@0: { sl@0: iFlagsAndNumberOfResources |= sl@0: EFlagPotentiallyContainsCompressedUnicode | EFlagDictionaryCompressed; sl@0: assert_obj.AssertDebL(header.Length() >= 18, EBafPanicBadHeader2); sl@0: iSizeOfLargestResourceWhenCompletelyUncompressed= sl@0: LittleEndianTwoByteIntegerL(header,16+1); sl@0: } sl@0: else if (uidType[0]!=TUid::Null()) sl@0: { sl@0: User::Leave(KErrNotSupported); sl@0: } sl@0: //the "signature" of Calypso's resource files sl@0: else if (LittleEndianTwoByteIntegerL(header,0)==4) sl@0: { sl@0: iFlagsAndNumberOfResources |= EFlagDictionaryCompressed | EFlagCalypsoFileFormat; sl@0: iSizeOfLargestResourceWhenCompletelyUncompressed= sl@0: LittleEndianTwoByteIntegerL(header,8); sl@0: } sl@0: } sl@0: sl@0: //It seems that the following AssertDebL() call never fails, sl@0: //because LittleEndianTwoByteIntegerL always sl@0: //returns zero or positive value. sl@0: assert_obj.AssertDebL(iSizeOfLargestResourceWhenCompletelyUncompressed>=0, sl@0: EBafPanicBadSizeOfLargestResourceWhenCompletelyUncompressed1); sl@0: TInt numberOfResources=0; sl@0: HBufC8* bitArrayOfResourcesContainingCompressedUnicode=NULL; sl@0: if (iFlagsAndNumberOfResources & EFlagDictionaryCompressed) sl@0: { sl@0: if (iFlagsAndNumberOfResources & EFlagCalypsoFileFormat) sl@0: { sl@0: assert_obj.AssertDebL(header.Length() > 10, EBafPanicBadHeader3); sl@0: numberOfResources=LittleEndianTwoByteIntegerL(header,2); sl@0: const TInt numberOfBitsUsedForDictionaryTokens = header[10]; sl@0: const TInt numberOfDictionaryEntries = sl@0: (1 << numberOfBitsUsedForDictionaryTokens) - header[5]; sl@0: assert_obj.AssertDebL(numberOfDictionaryEntries >= 0, EBafPanicBadHeader4); sl@0: // "+2" because the first entry in the dictionary-index in this file format sl@0: //is the number of bits from the start of the dictionary data to the start sl@0: //of the first dictionary entry which is always zero, and thus unnecessary sl@0: const TInt startOfDictionaryData=4+7+2; sl@0: // "+2" because the first entry in the resource-index in this file format is sl@0: //the number of bits from the start of the resource data to the start of the sl@0: //first resource which is always zero, and thus unnecessary sl@0: const TInt startOfResourceIndex=LittleEndianTwoByteIntegerL(header,6)+2; sl@0: assert_obj.AssertDebL(startOfResourceIndex >= 0, EBafPanicBadHeader5); sl@0: dictionaryCompressionData.iStartOfDictionaryData= sl@0: startOfDictionaryData+(numberOfDictionaryEntries*2); sl@0: dictionaryCompressionData.iStartOfDictionaryIndex=startOfDictionaryData; sl@0: dictionaryCompressionData.iNumberOfDictionaryEntries=numberOfDictionaryEntries; sl@0: dictionaryCompressionData.iStartOfResourceData= sl@0: startOfResourceIndex+(numberOfResources*2); sl@0: dictionaryCompressionData.iStartOfResourceIndex=startOfResourceIndex; sl@0: dictionaryCompressionData.iNumberOfBitsUsedForDictionaryTokens= sl@0: numberOfBitsUsedForDictionaryTokens; sl@0: sl@0: if ((iFlagsAndNumberOfResources & static_cast(EFlagIsRomFile)) == 0) sl@0: { sl@0: // attempt to cache dictionary index sl@0: // allocate and populate the dictionary index buffer sl@0: dictionaryCompressionData.iCachedDictionaryIndex = new TUint16[numberOfDictionaryEntries]; sl@0: if (dictionaryCompressionData.iCachedDictionaryIndex != 0) sl@0: { sl@0: TInt length = numberOfDictionaryEntries * 2; sl@0: TPtr8 ptr8((TUint8*)dictionaryCompressionData.iCachedDictionaryIndex, 0, length); sl@0: ReadL( sl@0: iFlagsAndNumberOfResources & static_cast(EAllFlags), // aFlags sl@0: startOfDictionaryData, // aPos sl@0: ptr8, sl@0: length); // aLength sl@0: } sl@0: } // if (iFlagsAndNumberOfResources & EFlagIsRomFile) sl@0: } sl@0: else sl@0: { sl@0: assert_obj.AssertDebL(header.Length()==16+1+2+2, EBafPanicBadHeaderLength); sl@0: const TUint firstByteAfterUids=header[16]; sl@0: if (firstByteAfterUids & 0x80) sl@0: { sl@0: // this flag is only set if the resource file is dictionary-compressed sl@0: iFlagsAndNumberOfResources |= EFlagThirdUidIsOffset; sl@0: } sl@0: if (firstByteAfterUids & 0x40) sl@0: { sl@0: // this flag is only set if the resource file is dictionary-compressed sl@0: iFlagsAndNumberOfResources |= EFlagGenerate_RSS_SIGNATURE_ForFirstUserResource; sl@0: } sl@0: if (firstByteAfterUids & 0x20) sl@0: { sl@0: iFlagsAndNumberOfResources |= sl@0: EFlagFirstResourceIsGeneratedBitArrayOfResourcesContainingCompressedUnicode; sl@0: } sl@0: dictionaryCompressionData.iStartOfResourceData= sl@0: LittleEndianTwoByteIntegerL(header,16+1+2); sl@0: TBuf8<2> temp; sl@0: ReadL((iExtra->iFileSize)-2,temp,2); sl@0: const TInt numberOfBitsOfResourceData=LittleEndianTwoByteIntegerL(temp,0); sl@0: dictionaryCompressionData.iStartOfResourceIndex= sl@0: dictionaryCompressionData.iStartOfResourceData+ sl@0: ((numberOfBitsOfResourceData+7)/8); sl@0: numberOfResources=(iExtra->iFileSize-dictionaryCompressionData.iStartOfResourceIndex)/2; sl@0: dictionaryCompressionData.iStartOfDictionaryData=16+5; sl@0: if ((numberOfResources>0) && sl@0: !(iFlagsAndNumberOfResources & sl@0: EFlagFirstResourceIsGeneratedBitArrayOfResourcesContainingCompressedUnicode)) sl@0: { sl@0: const TInt lengthOfBitArrayInBytes=(numberOfResources+7)/8; sl@0: bitArrayOfResourcesContainingCompressedUnicode= sl@0: HBufC8::NewLC(lengthOfBitArrayInBytes); sl@0: TPtr8 asWritable(bitArrayOfResourcesContainingCompressedUnicode->Des()); sl@0: ReadL(16+5,asWritable,lengthOfBitArrayInBytes); sl@0: dictionaryCompressionData.iStartOfDictionaryData+=lengthOfBitArrayInBytes; sl@0: } sl@0: ReadL(dictionaryCompressionData.iStartOfResourceData-2,temp,2); sl@0: const TInt numberOfBitsOfDictionaryData=LittleEndianTwoByteIntegerL(temp,0); sl@0: dictionaryCompressionData.iStartOfDictionaryIndex= sl@0: dictionaryCompressionData.iStartOfDictionaryData+ sl@0: ((numberOfBitsOfDictionaryData+7)/8); sl@0: dictionaryCompressionData.iNumberOfDictionaryEntries= sl@0: (dictionaryCompressionData.iStartOfResourceData- sl@0: dictionaryCompressionData.iStartOfDictionaryIndex)/2; sl@0: //the bottom 3 bits of firstByteAfterUids stores the number of bits used for sl@0: //dictionary tokens as an offset from 3, e.g. if 2 is stored in these three bits sl@0: //then the number of bits per dictionary token would be 3+2=5 - this allows a sl@0: //range of 3-11 bits per dictionary token (the maximum number of dictionary sl@0: //tokens therefore ranging from 8-2048) - the spec currently only supports 5-9 sl@0: //bits per dictionary token, however sl@0: dictionaryCompressionData.iNumberOfBitsUsedForDictionaryTokens= sl@0: 3 + (firstByteAfterUids & 0x07); sl@0: if ((numberOfResources>0) && sl@0: (iFlagsAndNumberOfResources & sl@0: EFlagFirstResourceIsGeneratedBitArrayOfResourcesContainingCompressedUnicode)) sl@0: { sl@0: bitArrayOfResourcesContainingCompressedUnicode= sl@0: DictionaryDecompressedResourceDataLC( sl@0: 0, sl@0: iFlagsAndNumberOfResources & static_cast(EAllFlags), sl@0: dictionaryCompressionData, sl@0: KNullDesC16); sl@0: } sl@0: } sl@0: } sl@0: else sl@0: { sl@0: assert_obj.AssertDebL((iExtra->iFileSize + iExtra->iFileOffset) > 2, EBafPanicFileSize); sl@0: // This format of resource file is likely to be used for non-ROM resource files, sl@0: //so cache the resource-index (in iIndex) to minimize disk access. sl@0: // Ignore the flags in non-dictionary-compressed resource files - they are to sl@0: //be used only by a dictionary-compressing program rather than to be used directly sl@0: //by Bafl when reading non-dictionary-compressed resource files (as output by Rcomp). sl@0: const TInt KMaximumNumberOfBytesCached=256; sl@0: TBuf8 cache; sl@0: const TInt numberOfBytesCached=Min(iExtra->iFileSize,KMaximumNumberOfBytesCached); sl@0: ReadL(iExtra->iFileSize-numberOfBytesCached,cache,numberOfBytesCached); sl@0: assert_obj.AssertDebL(cache.Length()==numberOfBytesCached, EBafPanicBadCacheLength); sl@0: const TInt positionOfStartOfIndex= sl@0: ((cache[numberOfBytesCached-1]<<8) | cache[numberOfBytesCached-2]); sl@0: const TInt numberOfBytesOfIndex=iExtra->iFileSize-positionOfStartOfIndex; sl@0: assert_obj.AssertDebL(numberOfBytesOfIndex%2==0, EBafPanicIndexIsOddNumberOfBytes); sl@0: assert_obj.AssertDebL(numberOfBytesOfIndex>=0, EBafPanicNegativeNumber); sl@0: const TInt numberOfBytesOfIndexStillToRetrieve= sl@0: numberOfBytesOfIndex-numberOfBytesCached; sl@0: if (numberOfBytesOfIndexStillToRetrieve<=0) sl@0: { sl@0: const TPtrC8 indexAsBinaryBuffer(cache.Right(numberOfBytesOfIndex)); sl@0: iIndex=HBufC16::NewMaxL(numberOfBytesOfIndex/2); sl@0: //indexAsBinaryBuffer.Ptr() may not be 2-byte aligned, hence why we can't do sl@0: //iIndex=TPtrC16(REINTERPRET_CAST(const TUint16*,indexAsBinaryBuffer.Ptr()), sl@0: //numberOfBytesOfIndex/2).AllocL() sl@0: Mem::Copy(CONST_CAST(TUint16*,iIndex->Ptr()),indexAsBinaryBuffer.Ptr(), sl@0: numberOfBytesOfIndex); sl@0: } sl@0: else sl@0: { sl@0: HBufC16* const index=HBufC16::NewMaxLC(numberOfBytesOfIndex/2); sl@0: TPtr8 indexAsWritableBinaryBuffer(REINTERPRET_CAST(TUint8*,CONST_CAST sl@0: (TUint16*,index->Ptr())),numberOfBytesOfIndex); sl@0: ReadL(positionOfStartOfIndex,indexAsWritableBinaryBuffer, sl@0: numberOfBytesOfIndexStillToRetrieve); sl@0: assert_obj.AssertDebL( sl@0: indexAsWritableBinaryBuffer.Length()==numberOfBytesOfIndexStillToRetrieve, sl@0: EBafPanicBadIndexLength1); sl@0: indexAsWritableBinaryBuffer.Append(cache); sl@0: assert_obj.AssertDebL(indexAsWritableBinaryBuffer.Length()==numberOfBytesOfIndex, sl@0: EBafPanicBadIndexLength2); sl@0: assert_obj.AssertDebL(indexAsWritableBinaryBuffer.Length()==index->Length()*2, sl@0: EBafPanicBadIndexLength3); sl@0: iIndex=index; sl@0: CleanupStack::Pop(index); sl@0: } sl@0: //"-1" because the last thing in the index (which is in fact the last thing in the sl@0: //file itself) is the position of the start of the index which is therefore not sl@0: //pointing to a resource sl@0: numberOfResources=(numberOfBytesOfIndex/2) - 1; sl@0: if ((numberOfResources>0) && sl@0: (iFlagsAndNumberOfResources & EFlagPotentiallyContainsCompressedUnicode)) sl@0: { sl@0: const TInt lengthOfBitArrayInBytes=(numberOfResources+7)/8; sl@0: bitArrayOfResourcesContainingCompressedUnicode= sl@0: HBufC8::NewLC(lengthOfBitArrayInBytes); sl@0: TPtr8 bitArray(bitArrayOfResourcesContainingCompressedUnicode->Des()); sl@0: //"16+1+2": 16 bytes of checked-UID + 1 byte of flags (these flags are for a sl@0: //dictionary-compressing program's use rather than directly for Bafl's use, sl@0: //so we ignore them) + 2 bytes containing the size of the largest resource when sl@0: //uncompressed sl@0: ReadL(16+1+2,bitArray,lengthOfBitArrayInBytes); sl@0: } sl@0: } sl@0: assert_obj.AssertDebL((numberOfResources & EAllFlags)==0, EBafPanicBadNumberOfResources); sl@0: assert_obj.AssertDebL((iFlagsAndNumberOfResources & ~EAllFlags)==0, sl@0: EBafPanicBadInitialization2); sl@0: iFlagsAndNumberOfResources |= (numberOfResources & ~EAllFlags); sl@0: iExtra->iUidType = uidType; sl@0: iExtra->iBitArrayOfResourcesContainingCompressedUnicode = bitArrayOfResourcesContainingCompressedUnicode; sl@0: iExtra->iDictionaryCompressionData = dictionaryCompressionData; sl@0: if (bitArrayOfResourcesContainingCompressedUnicode!=NULL) sl@0: { sl@0: CleanupStack::Pop(bitArrayOfResourcesContainingCompressedUnicode); sl@0: } sl@0: //iOffset is set by calling ConfirmSignatureL sl@0: assert_obj.AssertDebL(iOffset==0, EBafPanicBadInitialization3); sl@0: }