secureswitools/swisistools/source/rscparser/barscimpl.cpp
changeset 25 98b66e4fb0be
child 33 8110bf1194d1
equal deleted inserted replaced
24:84a16765cd86 25:98b66e4fb0be
       
     1 // Copyright (c) 2009 - 2010 Nokia Corporation and/or its subsidiary(-ies).
       
     2 // All rights reserved.
       
     3 // This component and the accompanying materials are made available
       
     4 // under the terms of "Eclipse Public License v1.0"
       
     5 // which accompanies this distribution, and is available
       
     6 // at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     7 //
       
     8 // Initial Contributors:
       
     9 // Nokia Corporation - initial contribution.
       
    10 //
       
    11 // Contributors:
       
    12 //
       
    13 // Description:
       
    14 //
       
    15 /** 
       
    16 * @file BaRscImpl.cpp
       
    17 *
       
    18 * @internalComponent
       
    19 * @released
       
    20 */
       
    21 #include <iostream>
       
    22 #include <fstream>
       
    23 #include <cassert>
       
    24 #include <sys/stat.h>
       
    25 #include <sstream>
       
    26 #include "barsc2.h"
       
    27 #include "barscimpl.h"
       
    28 #include "ucmp.h"
       
    29 
       
    30 
       
    31 RResourceFileImpl::TExtra::TExtra():
       
    32 	iBitArrayOfResourcesContainingCompressedUnicode(NULL),
       
    33 	iFileOffset(0),
       
    34 	iFileSize(0)
       
    35 	{
       
    36 	}
       
    37 
       
    38 
       
    39 RResourceFileImpl::TExtra::~TExtra()
       
    40 	{
       
    41 	delete iBitArrayOfResourcesContainingCompressedUnicode;
       
    42 	}
       
    43 
       
    44 
       
    45 TInt32 RResourceFileImpl::TExtra::ContainsCompressedUnicode(const TInt& aRscIdx) const
       
    46 	{
       
    47 	assert(aRscIdx>=0);
       
    48 	
       
    49 	if (iBitArrayOfResourcesContainingCompressedUnicode==NULL)
       
    50 		{
       
    51 		return EFalse;
       
    52 		}
       
    53 	
       
    54 	TInt index = aRscIdx/8;
       
    55 	
       
    56 	return (iBitArrayOfResourcesContainingCompressedUnicode)[index]&(1<<(aRscIdx%8));
       
    57 	}
       
    58 
       
    59 
       
    60 RResourceFileImpl::RResourceFileImpl() :
       
    61 	iResourceContents(NULL),
       
    62 	iSizeOfLargestResourceWhenCompletelyUncompressed(0),
       
    63 	iIndex(0),
       
    64 	iOffset(0),
       
    65 	iExtra(NULL),
       
    66 	iFlagsAndNumberOfResources(0)
       
    67 	{
       
    68 	// Fixed class size - because of the BC reasons.
       
    69 	// RResourceFileImpl size must be the same as CResourceFile size.
       
    70 	enum
       
    71 		{
       
    72 		KRscFileImplSize = 24
       
    73 		};	
       
    74 	assert(sizeof(RResourceFileImpl) == KRscFileImplSize);
       
    75 
       
    76 	//Fixed "iOffset" position - because of the BC reasons.
       
    77 	assert(offsetof(RResourceFileImpl, iOffset)==12);
       
    78 	}
       
    79 
       
    80 
       
    81 RResourceFileImpl::~RResourceFileImpl()
       
    82 {
       
    83 	if(iResourceContents)
       
    84 	{
       
    85 		if (iResourceContents->is_open())
       
    86 		{
       
    87 			iResourceContents->close();
       
    88 		}
       
    89 		delete iResourceContents;
       
    90 	}
       
    91 	iSizeOfLargestResourceWhenCompletelyUncompressed=0;
       
    92 	delete iIndex;
       
    93 	iIndex=NULL;
       
    94 	if (iExtra)
       
    95 	{
       
    96 		delete iExtra;
       
    97 		iExtra=NULL;
       
    98 	}
       
    99 
       
   100 	iFlagsAndNumberOfResources=0;
       
   101 	iOffset=0;
       
   102 }
       
   103 
       
   104 
       
   105 void RResourceFileImpl::OpenL(
       
   106 						  const std::string& aName, 
       
   107 						  TUint32 aFileOffset, 
       
   108 						  TInt aFileSize)
       
   109 {
       
   110 	iResourceContents= new std::ifstream(aName.c_str(), std::ios::in|std::ios::binary);
       
   111 		
       
   112 	if(!iResourceContents->good())
       
   113 	{
       
   114 		std::string errMsg= "Unable to open RSC file. " + aName;
       
   115 		if (iResourceContents->is_open())
       
   116 			iResourceContents->close();
       
   117 		if(iResourceContents)
       
   118 			delete iResourceContents;
       
   119 		throw CResourceFileException(errMsg);
       
   120 	}
       
   121 
       
   122 	iExtra=new TExtra();
       
   123 	iExtra->iFileOffset = aFileOffset;
       
   124 	
       
   125 	TInt fileSize = 0;
       
   126 	if (aFileSize)
       
   127 		{
       
   128 		fileSize = aFileSize;
       
   129 		assert(fileSize > TInt(aFileOffset));
       
   130 		}
       
   131 	else
       
   132 		{
       
   133 		// Get the resource file size
       
   134 		struct stat resourceFileStats;
       
   135     
       
   136 		if (stat(aName.c_str(),&resourceFileStats) == 0)
       
   137 			{
       
   138 			// The size of the file in bytes is in
       
   139 			// resourceFileStats.st_size
       
   140 			fileSize=resourceFileStats.st_size;
       
   141 			assert(fileSize > 0);
       
   142 			}   	
       
   143 		else
       
   144 			{
       
   145 			if (iResourceContents->is_open())
       
   146 					iResourceContents->close();		
       
   147 			std::string errMsg="Invalid RSC File";
       
   148 			throw CResourceFileException(errMsg);
       
   149 			}		
       
   150 		}
       
   151 	
       
   152 	iExtra->iFileSize = fileSize;	
       
   153 	
       
   154 	// Verify the header of the RSC and get the resource index
       
   155 	ReadHeaderAndResourceIndexL();
       
   156 }
       
   157 
       
   158 
       
   159 Ptr8* RResourceFileImpl::GetDecompressedResourceDataL(
       
   160 													const TInt& aResourceIndex,			
       
   161 													const TUint32& aFlags) 
       
   162 	{
       
   163 	const TInt positionOfResourceData= iIndex[aResourceIndex];
       
   164 	const TInt numberOfBytes= iIndex[aResourceIndex+1]-positionOfResourceData;
       
   165 	
       
   166 	assert(numberOfBytes >= 0);
       
   167 	
       
   168 	Ptr8* outputResourceData=new Ptr8(numberOfBytes);
       
   169 	ReadL(aFlags, positionOfResourceData, outputResourceData->GetPtr(), numberOfBytes);
       
   170 	outputResourceData->UpdateLength(numberOfBytes);
       
   171 	
       
   172 	return outputResourceData;
       
   173 	}
       
   174 
       
   175 
       
   176 Ptr8* RResourceFileImpl::AllocReadL(const TInt& aResourceId) 
       
   177 	{
       
   178 	
       
   179 	// Check if the resource id is present in the RSC file
       
   180 	if (!OwnsResourceId(aResourceId))
       
   181 		{
       
   182 		std::ostringstream errDispStream;
       
   183 		
       
   184 		errDispStream<<"Resource ID:";
       
   185 		errDispStream<<aResourceId;
       
   186 		errDispStream<<" is not present in the RSC file";
       
   187 		
       
   188 		throw CResourceFileException(errDispStream.str());
       
   189 		}
       
   190 	
       
   191 	//"-1" because the first resource has ID 0x*****001 (not 0x*****000)
       
   192 	TInt resourceIndex= (aResourceId & EIdBits)-1; 
       
   193 	assert(resourceIndex>=0);
       
   194 	
       
   195 	Ptr8* decompressedResourceData= 
       
   196 		GetDecompressedResourceDataL(
       
   197 								resourceIndex,
       
   198 								iFlagsAndNumberOfResources & static_cast<TUint32>(EAllFlags));
       
   199 	
       
   200 	// Return the resource data if its not unicode compressed.
       
   201 	if (!iExtra->ContainsCompressedUnicode(resourceIndex))
       
   202 		{
       
   203 		return decompressedResourceData;
       
   204 		}
       
   205 	
       
   206 	// Get the decompressed unicode data.
       
   207 	Ptr8* finalResourceData= DecompressUnicodeL(decompressedResourceData);	
       
   208 	
       
   209 	delete decompressedResourceData;	
       
   210 	return finalResourceData;	
       
   211 	}
       
   212 
       
   213 
       
   214 Ptr8* RResourceFileImpl::DecompressUnicodeL(const Ptr8* aInputResourceData) const
       
   215 	{
       
   216 	const TInt numberOfBytesInInput= aInputResourceData->GetLength();
       
   217 	assert(iSizeOfLargestResourceWhenCompletelyUncompressed>0);
       
   218 							
       
   219 	Ptr8* outputResourceData= new Ptr8(iSizeOfLargestResourceWhenCompletelyUncompressed);
       
   220 	
       
   221 	const TUint8* input= aInputResourceData->GetPtr();
       
   222 	TInt index=0;
       
   223 	
       
   224 	TBool decompressRun=ETrue;
       
   225 	while (1)
       
   226 		{
       
   227 		assert(index<numberOfBytesInInput);
       
   228 		
       
   229 		TInt runLength=input[index];
       
   230 		
       
   231 		// The run-length occupies a single byte if it is less than 128, 
       
   232 		// otherwise it occupies two bytes (in little-endian byte order), 
       
   233 		// with the most significant bit of the first byte set to non-zero 
       
   234 		//to indicate that the run-length occupies two bytes.
       
   235 		if (runLength & 0x80)
       
   236 			{
       
   237 			++index;
       
   238 			if (index>=numberOfBytesInInput)
       
   239 				{
       
   240 				std::string errMsg="Invalid Rsc File";
       
   241 				throw CResourceFileException(errMsg);
       
   242 				}
       
   243 			runLength &= ~0x80;
       
   244 			runLength <<= 8;
       
   245 			runLength |= input[index];
       
   246 			}
       
   247 		++index;
       
   248 		if (runLength>0)
       
   249 			{			
       
   250 			if (decompressRun)
       
   251 				{
       
   252 				AppendDecompressedUnicodeL(
       
   253 										outputResourceData,				
       
   254 										const_cast<unsigned char *>(input+index),
       
   255 										runLength);
       
   256 				}
       
   257 			else
       
   258 				{
       
   259 				assert(
       
   260 					(outputResourceData->GetLength() + runLength) <= 
       
   261 					iSizeOfLargestResourceWhenCompletelyUncompressed);
       
   262 				
       
   263 				memcpy((char*)(outputResourceData->GetPtr()+outputResourceData->GetLength()),(char*)(input+index),runLength);				
       
   264 				outputResourceData->UpdateLength(runLength);
       
   265 				}
       
   266 			index+=runLength;
       
   267 			}
       
   268 		if (index>numberOfBytesInInput)
       
   269 			{
       
   270 			std::string errMsg="Invalid Rsc File";
       
   271 			throw CResourceFileException(errMsg);
       
   272 			}
       
   273 		if (index>=numberOfBytesInInput)
       
   274 			{
       
   275 			break;
       
   276 			}
       
   277 			decompressRun=!decompressRun;
       
   278 		}	
       
   279 	return outputResourceData;
       
   280 	}
       
   281 
       
   282 
       
   283 
       
   284 /** @internalComponent
       
   285 @return The first resource record.
       
   286 @panic Some BAFL panic codes, if the file is corrupted.
       
   287 @leave KErrCorrupt The file is corrupted.
       
   288 Some other error codes are possible too.
       
   289 The method could panic or leave depending on the state of
       
   290 iAssertObj member of RResourceFileImpl::TExtra class. */
       
   291 RResourceFileImpl::SSigRecord RResourceFileImpl::FirstRecordL() const
       
   292 	{
       
   293 	// Added to support reading of rel 6.x resource files.
       
   294 	// rel 6.x files do not have signatures!
       
   295 	Ptr8* const firstResource=AllocReadL(1);
       
   296 
       
   297 	// Basic check to test if the signature is of the correct size.
       
   298 	if (firstResource->GetLength()!= sizeof(SSigRecord))
       
   299 	{
       
   300 		std::string errMsg="Invalid RSS Signature";
       
   301 		throw CResourceFileException(errMsg);
       
   302 	}
       
   303 	SSigRecord sigRecord = *reinterpret_cast<const SSigRecord*>(firstResource->GetPtr());
       
   304 	delete firstResource;
       
   305 	return sigRecord;
       
   306 }
       
   307 
       
   308 /** Initialises the offset value from the first resource.
       
   309 
       
   310 The function tests to catch cases where the first resource is not an RSS_SIGNATURE.
       
   311 It assumes that the first resource in the file consists of
       
   312 two 32-bit integers. The first integer contains the version number and
       
   313 the second is a self-referencing link whose value is the offset for
       
   314 the resources in the file, plus 1.This function must be called before
       
   315 calling Offset(), AllocReadL(), AllocReadLC() or ReadL().
       
   316 
       
   317 @see Offset()
       
   318 @see AllocReadL()
       
   319 @see AllocReadLC() 
       
   320 @see ReadL()
       
   321 @internalComponent
       
   322 @pre OpenL() is called.
       
   323 @panic Some BAFL panic codes, if the file is corrupted.
       
   324 @leave KErrCorrupt The file is corrupted.
       
   325 Some other error codes are possible too.
       
   326 The method could panic or leave depending on the state of
       
   327 iAssertObj member of RResourceFileImpl::TExtra class. */
       
   328 void RResourceFileImpl::ConfirmSignatureL()
       
   329 {
       
   330 	// Added to support reading of rel 6.x resource files.
       
   331 	SSigRecord firstRecord=FirstRecordL();
       
   332 
       
   333 	// If the resource offset does not correspond to the first resource
       
   334 	// this is not a resource signature.
       
   335 	if ((firstRecord.offset & EIdBits) != 1)
       
   336 	{
       
   337 		std::string errMsg="Failed : Invalid RSS Signature";
       
   338 		throw CResourceFileException(errMsg);
       
   339 	}
       
   340 	iOffset=(firstRecord.offset & EOffsetBits);
       
   341 }
       
   342 
       
   343 void RResourceFileImpl::AppendDecompressedUnicodeL(
       
   344 												   Ptr8* aBuffer,
       
   345 												   const TUint8*  aCompressedUnicode,
       
   346 												   const TInt& aLengthOfCompressedUnicode) const
       
   347 	{
       
   348 	
       
   349 	if (aLengthOfCompressedUnicode>0)
       
   350 		{
       
   351 		TUint8* startOfDecompressedUnicode= aBuffer->GetPtr() + aBuffer->GetLength();
       
   352 		
       
   353 		if (reinterpret_cast<TUint32>(startOfDecompressedUnicode) & 0x01)
       
   354 			{			
       
   355 			TUint8 padChar = 0xab;
       
   356 			memcpy(startOfDecompressedUnicode,&padChar,1);
       
   357 			++startOfDecompressedUnicode;
       
   358 			aBuffer->UpdateLength(1);
       
   359 			}
       
   360 		
       
   361 		const TInt maximumOutputLength= (
       
   362 			iSizeOfLargestResourceWhenCompletelyUncompressed - (aBuffer->GetLength()))/2; 
       
   363 		
       
   364 		TMemoryUnicodeSink decompressedUnicode(reinterpret_cast<TUint16*>(startOfDecompressedUnicode));
       
   365 		
       
   366 		TInt lengthOfDecompressedUnicode;
       
   367 		TInt numberOfInputBytesConsumed;
       
   368 		TUnicodeExpander unicodeExpander;
       
   369 		
       
   370 		unicodeExpander.ExpandL(decompressedUnicode,
       
   371 								aCompressedUnicode,
       
   372 								maximumOutputLength,
       
   373 								aLengthOfCompressedUnicode,
       
   374 								&lengthOfDecompressedUnicode,
       
   375 								&numberOfInputBytesConsumed);
       
   376 		TInt temp;
       
   377 		unicodeExpander.FlushL(decompressedUnicode,maximumOutputLength,temp);
       
   378 		lengthOfDecompressedUnicode+=temp;
       
   379 		aBuffer->UpdateLength(lengthOfDecompressedUnicode*2);
       
   380 		
       
   381 		assert(numberOfInputBytesConsumed == aLengthOfCompressedUnicode);		
       
   382 		}
       
   383 	}
       
   384 
       
   385 
       
   386 TBool RResourceFileImpl::OwnsResourceId(const TInt& aResourceId) const
       
   387 	{ 
       
   388 	// Checks whether Rsc file owns the resource:
       
   389 	// does so if offset is 0, or matches that given, 
       
   390 	// and id is in index.
       
   391 	const TInt offset=(aResourceId & EOffsetBits);
       
   392 //	if ((offset!=0) && (offset!=iOffset))
       
   393 //		{
       
   394 //		return EFalse;
       
   395 //		}
       
   396 	
       
   397 	const TInt resourceIndex=(aResourceId & EIdBits)-1;
       
   398 	TInt numberOfResources=(iFlagsAndNumberOfResources & ~EAllFlags);
       
   399 	
       
   400 	return (resourceIndex >= 0) && (resourceIndex < numberOfResources);
       
   401 	}
       
   402 
       
   403 
       
   404 void RResourceFileImpl::ReadL(
       
   405 							const TUint32& aFlags, 
       
   406 							TInt aPos,
       
   407 							TUint8* aData,
       
   408 							const TInt& aLength) 
       
   409 	{
       
   410 	aPos += iExtra->iFileOffset;
       
   411 	
       
   412 	assert(aPos >= iExtra->iFileOffset);
       
   413 	assert(aLength >= 0);
       
   414 	assert((aPos + aLength) <= (iExtra->iFileOffset + iExtra->iFileSize));	
       
   415 	
       
   416 	// Seek to the offset specified by "aPos"
       
   417 	iResourceContents->seekg(aPos, std::ios_base::beg);
       
   418 	iResourceContents->read((char*)aData, aLength);		
       
   419 	}
       
   420 
       
   421 
       
   422 void RResourceFileImpl::ReadL(TInt aPos, TUint8* aData, const TInt& aLength) 
       
   423 	{
       
   424 	ReadL(iFlagsAndNumberOfResources & static_cast<TUint32>(EAllFlags),aPos,aData,aLength);
       
   425 	}
       
   426 
       
   427 
       
   428 TInt RResourceFileImpl::LittleEndianTwoByteInteger(
       
   429 													TUint8* aBuffer,
       
   430 													const TInt& aIndexOfFirstByte) const
       
   431 	{
       
   432 	return aBuffer[aIndexOfFirstByte] | (aBuffer[aIndexOfFirstByte+1]<<8);
       
   433 	}
       
   434 
       
   435 
       
   436 void RResourceFileImpl::ReadHeaderAndResourceIndexL()
       
   437 	{
       
   438 	
       
   439 	// Unicode compressed RSC file will have 19 bytes header.
       
   440 	const TUint8 kHeaderSize= 19;
       
   441 	TUint8 header[kHeaderSize];
       
   442 			
       
   443 	sTUid uid;
       
   444 	
       
   445 	// Verify the header of the RSC file.
       
   446 	if(iExtra->iFileSize >= kHeaderSize)
       
   447 		{
       
   448 		
       
   449 		// Get the RSC header
       
   450 		ReadL(0,0,header,kHeaderSize);
       
   451 		// Get the first UID
       
   452 		memcpy((TUint8*)&uid.iUid1,header,4);
       
   453 		
       
   454 		// First uid of unicode compressed RSC is "0x101f4a6b"
       
   455 		TUint32 unicodeCompressedFirstUid = 0x101f4a6b;
       
   456 		
       
   457 		if (uid.iUid1 == unicodeCompressedFirstUid)
       
   458 			{
       
   459 			iFlagsAndNumberOfResources |= EFlagPotentiallyContainsCompressedUnicode;
       
   460 			iSizeOfLargestResourceWhenCompletelyUncompressed=	LittleEndianTwoByteInteger(header,16+1);
       
   461 			}
       
   462 		else
       
   463 			{
       
   464 				if (iResourceContents->is_open())
       
   465 						iResourceContents->close();
       
   466 			std::string errMsg="Failed : Unsupported RSC file type";
       
   467 			throw CResourceFileException(errMsg);
       
   468 			}
       
   469 		}
       
   470 		
       
   471 		TInt numberOfResources= 0;
       
   472 		TUint8* bitArrayOfResourcesContainingCompressedUnicode= NULL;
       
   473 		
       
   474 		if (iFlagsAndNumberOfResources & EFlagPotentiallyContainsCompressedUnicode)
       
   475 		{
       
   476 			// Cache the resource-index (in iIndex) to minimize disk access.		
       
   477 			const TInt KMaximumNumberOfBytesCached= 256;
       
   478 			TUint8 cache[KMaximumNumberOfBytesCached];
       
   479 			const TInt numberOfBytesCached=
       
   480 				((iExtra->iFileSize>KMaximumNumberOfBytesCached) ? KMaximumNumberOfBytesCached : iExtra->iFileSize);
       
   481 			
       
   482 			ReadL(iExtra->iFileSize-numberOfBytesCached, cache, numberOfBytesCached);
       
   483 			
       
   484 			const TInt positionOfStartOfIndex=
       
   485 				((cache[numberOfBytesCached-1]<<8) | cache[numberOfBytesCached-2]);
       
   486 			const TInt numberOfBytesOfIndex=iExtra->iFileSize-positionOfStartOfIndex;
       
   487 			
       
   488 			assert(numberOfBytesOfIndex%2==0);
       
   489 			assert(numberOfBytesOfIndex>=0);
       
   490 			
       
   491 			const TInt numberOfBytesOfIndexStillToRetrieve = numberOfBytesOfIndex-numberOfBytesCached;
       
   492 			
       
   493 			if (numberOfBytesOfIndexStillToRetrieve<=0)
       
   494 				{
       
   495 				iIndex= new TUint16[numberOfBytesOfIndex/2];
       
   496 				memcpy(iIndex, cache+(numberOfBytesCached-numberOfBytesOfIndex), numberOfBytesOfIndex);
       
   497 				}
       
   498 			else
       
   499 				{
       
   500 				TUint16* index= new TUint16(numberOfBytesOfIndex/2);			
       
   501 				ReadL(positionOfStartOfIndex, reinterpret_cast<TUint8*>(index), numberOfBytesOfIndexStillToRetrieve);
       
   502 				memcpy((index+numberOfBytesOfIndexStillToRetrieve),cache,numberOfBytesCached); 		
       
   503 
       
   504 				iIndex=index;			
       
   505 				}
       
   506 
       
   507 			//"-1" because the last thing in the index (which is in fact the last thing in the 
       
   508 			//file itself) is the position of the start of the index which is therefore not 
       
   509 			//pointing to a resource
       
   510 			numberOfResources=(numberOfBytesOfIndex/2) - 1; 
       
   511 			
       
   512 			if (numberOfResources <= 0)
       
   513 				{
       
   514 				if (iResourceContents->is_open())
       
   515 						iResourceContents->close();
       
   516 				std::string errMsg="Failed : Invalid RSC file.";
       
   517 				throw CResourceFileException(errMsg);
       
   518 				}
       
   519 				
       
   520 			const TInt lengthOfBitArrayInBytes=(numberOfResources+7)/8;
       
   521 			bitArrayOfResourcesContainingCompressedUnicode=
       
   522 								new TUint8(lengthOfBitArrayInBytes);
       
   523 			
       
   524 			//"16+1+2": 16 bytes of checked-UID + 1 byte of flags (these flags are for a 
       
   525 			//dictionary-compressing program's use rather than directly for Bafl's use, 
       
   526 			//so we ignore them) + 2 bytes containing the size of the largest resource when 
       
   527 			//uncompressed
       
   528 			ReadL(16+1+2,bitArrayOfResourcesContainingCompressedUnicode,lengthOfBitArrayInBytes); 
       
   529 		
       
   530 		}
       
   531 		
       
   532 		assert((numberOfResources & EAllFlags)==0);
       
   533 		assert((iFlagsAndNumberOfResources & ~EAllFlags)==0);
       
   534 		
       
   535 		iFlagsAndNumberOfResources |= (numberOfResources & ~EAllFlags);
       
   536 		iExtra->iUid = uid;
       
   537 		iExtra->iBitArrayOfResourcesContainingCompressedUnicode = bitArrayOfResourcesContainingCompressedUnicode;
       
   538 			
       
   539 	}