lowlevellibsandfws/apputils/src/BaArchiveImpl.cpp
changeset 0 e4d67989cc36
equal deleted inserted replaced
-1:000000000000 0:e4d67989cc36
       
     1 // Copyright (c) 2004-2009 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 #include <barsc2.h>
       
    17 #include "BaArchiveImpl.h"
       
    18 #include <baflpan.h>
       
    19 #include <bautils.h>
       
    20 
       
    21 /** TCleanupItem function.
       
    22 @internalComponent
       
    23 */
       
    24 LOCAL_C void CloseAndDeleteFile(TAny* aFile)
       
    25 	{
       
    26 	RFile* const file=static_cast<RFile*>(aFile);
       
    27 	if (file!=NULL)
       
    28 		{
       
    29 		file->Close();
       
    30 		delete file;
       
    31 		}
       
    32 	}
       
    33 
       
    34 /** TCleanupItem function.
       
    35 @internalComponent
       
    36 */
       
    37 LOCAL_C void CloseAndDeleteChunk(TAny* aChunk)
       
    38 	{
       
    39 	RChunk* const rchunk=static_cast<RChunk*>(aChunk);
       
    40 	if (rchunk!=NULL)
       
    41 		{
       
    42 		rchunk->Close();
       
    43 		delete rchunk;
       
    44 		}
       
    45 	}
       
    46 
       
    47 /** Default Constructor
       
    48 @internalComponent
       
    49 */
       
    50 CResourceArchiveImpl::CResourceArchiveImpl() :
       
    51 	iCurrentIndex(0),
       
    52 	iSpiFileType(KNullUid)
       
    53 	{}
       
    54 
       
    55 /** Class destructor
       
    56 @internalComponent 
       
    57 */
       
    58 CResourceArchiveImpl::~CResourceArchiveImpl()
       
    59 	{
       
    60 	iRscList.Close();
       
    61 	
       
    62 	for(TInt i=0; i<iSpiChunkBufferArray.Count(); i++)
       
    63 		{
       
    64 		RChunk* const chunk = iSpiChunkBufferArray[i];                     
       
    65 		chunk->Close();
       
    66 		delete chunk;
       
    67 		}
       
    68 	
       
    69 	iSpiChunkBufferArray.Reset();
       
    70 	iSpiChunkBufferArray.Close();
       
    71 
       
    72 	iSpiBufferArray.ResetAndDestroy();
       
    73 	iSpiBufferArray.Close();
       
    74 	iCurrentIndex=0;
       
    75 	iSpiFileType=KNullUid;
       
    76 #ifdef __BASPITEST__
       
    77 	iSpiFileNameArray.Reset();
       
    78 	iSpiFileNameArray.Close();
       
    79 #endif	
       
    80 	}
       
    81 
       
    82 /** Creates a CResourceArchiveImpl instance to read a single spi file
       
    83 @internalComponent
       
    84 */
       
    85 CResourceArchiveImpl* CResourceArchiveImpl::NewL(RFs& aFs,const TDesC& aName)
       
    86 	{
       
    87 	CResourceArchiveImpl* self=new (ELeave) CResourceArchiveImpl;
       
    88 	CleanupStack::PushL(self);
       
    89 	self->ConstructL(aFs,aName);
       
    90 	CleanupStack::Pop();
       
    91 	return self;
       
    92 	}
       
    93 
       
    94 /** Creates a CResourceArchiveImpl instance to read a set of spi files
       
    95 @internalComponent
       
    96 */	
       
    97 CResourceArchiveImpl* CResourceArchiveImpl::NewL(RFs& aFs,const TDesC& aPath,const TDesC& aPattern)
       
    98 	{
       
    99 	CResourceArchiveImpl* self=new (ELeave) CResourceArchiveImpl;
       
   100 	CleanupStack::PushL(self);
       
   101 	self->ConstructL(aFs,aPath,aPattern);
       
   102 	CleanupStack::Pop();
       
   103 	return self;	
       
   104 	}
       
   105 
       
   106 /** ConstructL method of CResourceArchiveImpl
       
   107 @internalComponent
       
   108 */
       
   109 void CResourceArchiveImpl::ConstructL(RFs& aFs,const TDesC& aName)
       
   110 	{
       
   111 	RArray<TPtrC8> hiddenRscList;
       
   112 	CleanupClosePushL(hiddenRscList);
       
   113 	//Open the file and initialise the buffer pointer
       
   114 	TPtr8 bufferPtr(NULL,0,0);
       
   115 	OpenFileL(aFs,aName,bufferPtr);
       
   116 	//Now validate the header
       
   117 	ValidateHeaderL(bufferPtr);
       
   118 	//Process all the rsc entry
       
   119 	ProcessEntryL(bufferPtr,hiddenRscList);	
       
   120 	CleanupStack::PopAndDestroy();
       
   121 	}
       
   122 	
       
   123 
       
   124 /** Function to get the string representation of a language code
       
   125 assume language code has max N digits currently equal to ELangMaximum
       
   126 note that the minimum suffix required is NN so TLang(0-9) needs to have a 0
       
   127 e.g s01...s09, s10, s100 etc
       
   128 @internalComponent
       
   129 */
       
   130 static void GetLangCodeStringRep(TLanguage lang,TDes& aStringRep)
       
   131 {
       
   132 	aStringRep.Zero();
       
   133 	//special case for 0-9 where you need the 0 appended, langcode min two digit
       
   134 	if (lang<10)
       
   135 		aStringRep.AppendNumFixedWidthUC(lang,EDecimal,2);
       
   136 	else
       
   137 		aStringRep.AppendFormat(_L("%d"),lang);
       
   138 }
       
   139 
       
   140 /**
       
   141 Open the file and initialise the aBufferPtr to point at the buffer
       
   142 @internalComponent
       
   143 */
       
   144 void CResourceArchiveImpl::OpenFileL(RFs& aFs,const TDesC& aName,TPtr8& aBufferPtr)
       
   145 	{
       
   146 	#ifdef __WINS__
       
   147 	TUint8* romAddress=NULL;
       
   148 	#else // ! __WINS__
       
   149 	TUint8* romAddress=aFs.IsFileInRom(aName);
       
   150 	#endif // ! __WINS__
       
   151 	
       
   152 	RFile* const file=new(ELeave) RFile;
       
   153 	CleanupStack::PushL(TCleanupItem(CloseAndDeleteFile,file));
       
   154 	User::LeaveIfError(file->Open(aFs, aName, EFileStream | EFileRead | EFileShareReadersOnly));
       
   155 	TInt fileSize=0;
       
   156 	User::LeaveIfError(file->Size(fileSize));						
       
   157 	if (romAddress)
       
   158 		{	
       
   159 		aBufferPtr.Set(romAddress,fileSize,fileSize);
       
   160 		}
       
   161 	else
       
   162 		{
       
   163 		RChunk* rchunk = new(ELeave) RChunk;
       
   164 		
       
   165 		CleanupStack::PushL(TCleanupItem(CloseAndDeleteChunk,rchunk));
       
   166 		
       
   167 		TInt createRet = rchunk->CreateDisconnectedLocal(0, 0, fileSize);
       
   168 		TInt commitRet = rchunk->Commit(0, fileSize);
       
   169 		
       
   170 		// Create a chunk to store the large file contents of which is closed and destroyed in destructor...
       
   171 		if(createRet==KErrNone && commitRet==KErrNone)
       
   172 			{
       
   173 			TUint8* chunkBase = (TUint8*)rchunk->Base();
       
   174 			TPtr8 tempBuffer(chunkBase, fileSize);
       
   175 			User::LeaveIfError(file->Read(0, tempBuffer, fileSize));
       
   176 			aBufferPtr.Set(tempBuffer);
       
   177 			iSpiChunkBufferArray.AppendL(rchunk);
       
   178 			
       
   179 			CleanupStack::Pop(rchunk);
       
   180 			}
       
   181 		else	// Unable to create a chunk so use heap memory...
       
   182 			{
       
   183 			HBufC8* fileBuffer=HBufC8::NewMaxLC(fileSize);
       
   184 			aBufferPtr.Set(fileBuffer->Des());
       
   185 			User::LeaveIfError(file->Read(0,aBufferPtr,fileSize));
       
   186 			iSpiBufferArray.AppendL(fileBuffer);
       
   187 			
       
   188 			CleanupStack::Pop(fileBuffer);
       
   189 			CleanupStack::PopAndDestroy(rchunk);
       
   190 			}
       
   191 		}
       
   192 	//can close the file now
       
   193 	CleanupStack::PopAndDestroy(file);
       
   194 #ifdef __BASPITEST__
       
   195 	iSpiFileNameArray.AppendL(aName);
       
   196 #endif		
       
   197 	}
       
   198 
       
   199 /**
       
   200 Validate the spi header in the file buffer
       
   201 On return it will update the bufferPtr to point to start of the first
       
   202 rsc entry
       
   203 @internalComponent
       
   204 */
       
   205 void CResourceArchiveImpl::ValidateHeaderL(TPtr8& aBufferPtr)
       
   206 	{
       
   207 	//Getting the 32 bytes header information. At the moment maybe we should just buffer 16 bytes
       
   208 	//of the header as the remaining 16 bytes are padding bytes
       
   209 	TUidType uidType=TCheckedUid(aBufferPtr.Left(16)).UidType();			
       
   210 	if (uidType[0]!=KSpiFileUid)
       
   211 		User::Leave(KErrCorrupt);
       
   212 	//now get the spi file type
       
   213 	TUid spiFileType=TUid::Uid(uidType[1].iUid);
       
   214 	if (iSpiFileType==KNullUid)
       
   215 		iSpiFileType=spiFileType;
       
   216 	//also check consistency with previous spi files
       
   217 	__ASSERT_DEBUG(iSpiFileType==spiFileType,::Panic(EBafPanicBadResourceFileFormat));							
       
   218 
       
   219 	//update the bufferPtr to point to start of first rsc entry
       
   220 	aBufferPtr.Set(aBufferPtr.MidTPtr(KSpiFirstRscOffset));	
       
   221 	}
       
   222 
       
   223 /**
       
   224 Process all the entry found in the buffer and update the internal rscList
       
   225 @internalComponent
       
   226 */
       
   227 void CResourceArchiveImpl::ProcessEntryL(TPtr8& aBufferPtr,RArray<TPtrC8>& aHiddenList)
       
   228 	{
       
   229 	//now traverse content of the spi file and build up the hidden list and the TRscEntry array
       
   230 	TRscEntry rscEntry;
       
   231 	while (aBufferPtr.Length()>0)
       
   232 		{
       
   233 		//length(first 4 bytes) and the actual rsc file size(second 4 bytes)
       
   234 		//Retrieving the rscfilename length
       
   235 		TUint32 rscFileNameLength=LittleEndianFourByteInteger(aBufferPtr,0);
       
   236 		TUint32 rscFileSize=LittleEndianFourByteInteger(aBufferPtr,4);
       
   237 		TUint32 paddingbyte=(4-((rscFileNameLength+rscFileSize)%4))%4;
       
   238 		__ASSERT_DEBUG((rscFileNameLength+rscFileSize+paddingbyte)%4==0,::Panic(EBafPanicFileSize));
       
   239 		//construct the TRscEntry				
       
   240 		rscEntry.iRscName.Set(aBufferPtr.Mid(8,rscFileNameLength));
       
   241 		rscEntry.iRscData.Set(aBufferPtr.Mid(8+rscFileNameLength,rscFileSize));
       
   242 #ifdef __BASPITEST__
       
   243 		rscEntry.iFileNamePtr.Set(iSpiFileNameArray[iSpiFileNameArray.Count()-1].Mid(0));
       
   244 #endif				
       
   245 		//update the buffer pointer
       
   246 		aBufferPtr.Set(aBufferPtr.MidTPtr(8+rscFileNameLength+rscFileSize+paddingbyte));
       
   247 
       
   248 		//process the TRscEntry
       
   249 		if (rscEntry.iRscData.Length()==0)
       
   250 			aHiddenList.AppendL(rscEntry.iRscName);
       
   251 		else
       
   252 			{
       
   253 			//if can find a matching resource name entry in the hidden list ignore this entry
       
   254 			TIdentityRelation<TPtrC8> identity(MatchDescriptor);
       
   255 			if (aHiddenList.Find(rscEntry.iRscName,identity)==KErrNotFound)
       
   256 				{
       
   257 				//note no duplicate entry, this implies the lastly mounted resource
       
   258 				//entry is preferred over earlier mounted resource entry.(REPLACING)
       
   259 				TInt ret=iRscList.InsertInOrder(rscEntry,EntryOrder);
       
   260 				if (ret!=KErrNone && ret!=KErrAlreadyExists)
       
   261 					User::Leave(ret);
       
   262 				}		
       
   263 			}
       
   264 		}//end while loop	
       
   265 	}
       
   266 	
       
   267 /** ConstructL method that accepts a spi path and a matching pattern
       
   268 aPath here must end with \\ as well e.g. z:\\private\\10009d8f\\ 
       
   269 aPattern should be the spi file withou rom image id and extension
       
   270 @internalComponent
       
   271 */
       
   272 void CResourceArchiveImpl::ConstructL(RFs& aFs,const TDesC& aPath,const TDesC& aPattern)
       
   273 	{
       
   274 	//Get the downgradepath
       
   275 	RArray<TLanguage> downgradeList;
       
   276 	BaflUtils::GetDowngradePathL(aFs,User::Language(),downgradeList);
       
   277 	CleanupClosePushL(downgradeList);
       
   278 	
       
   279 	//used to check if there is any matching pattern and leave with KErrNotFound if
       
   280 	//no matching spi
       
   281 	TInt spiDiscovered=0;
       
   282 	
       
   283 	//sort out the language specific spi first
       
   284 	for (int i=0;i<=downgradeList.Count();i++)	
       
   285 		{
       
   286 		//list all the files in the directory that matches this language
       
   287 		TFileName matchPattern;
       
   288 		TBuf<5> langExtension;
       
   289 		if (i<downgradeList.Count())
       
   290 			GetLangCodeStringRep(downgradeList[i],langExtension);
       
   291 		else
       
   292 			{
       
   293 			//process the default spi lastly
       
   294 			langExtension.Append(_L("pi"));			
       
   295 			}
       
   296 		matchPattern.AppendFormat(_L("%S%S-*-*.s%S"),&aPath,&aPattern,&langExtension);
       
   297 
       
   298 		//Get all the spis that match the language pattern
       
   299 		CDir* spiList=NULL;
       
   300 		User::LeaveIfError(aFs.GetDir(matchPattern,KEntryAttReadOnly | KEntryAttHidden | KEntryAttSystem | KEntryAttArchive,ESortByName,spiList));
       
   301 		CleanupStack::PushL(spiList);
       
   302 
       
   303 		//the hidden list is only a temporary variable for each language
       
   304 		RArray<TPtrC8> hiddenRscList;
       
   305 		CleanupClosePushL(hiddenRscList);
       
   306 		
       
   307 		//reverse processing
       
   308 		for (TInt i=spiList->Count()-1;i>=0;i--)
       
   309 			{
       
   310 			//reuse the matchPattern buffer to hold the full path of the spi file name
       
   311 			matchPattern.Zero();
       
   312 			matchPattern.Append(aPath);
       
   313 			matchPattern.Append((*spiList)[i].iName);
       
   314 
       
   315 			//Open the file and initialise the buffer pointer
       
   316 			TPtr8 bufferPtr(NULL,0,0);
       
   317 			OpenFileL(aFs,matchPattern,bufferPtr);
       
   318 	
       
   319 			//Now validate the header
       
   320 			ValidateHeaderL(bufferPtr);
       
   321 	
       
   322 			//Process all the rsc entry
       
   323 			ProcessEntryL(bufferPtr,hiddenRscList);
       
   324 			}//end for loop
       
   325 		spiDiscovered+=spiList->Count();
       
   326 		CleanupStack::PopAndDestroy(2);				//hiddenRscList and spiList
       
   327 		}//end for loop
       
   328 	//if no spi files are discovered at all leave with KErrNotFound
       
   329 	if (spiDiscovered==0)
       
   330 		User::Leave(KErrNotFound);
       
   331 	CleanupStack::PopAndDestroy(&downgradeList);
       
   332 	}
       
   333 
       
   334 /** Create the next CResourceFile that correponds to the next resource file
       
   335 in the resource archive(SPI) file
       
   336 @internalComponent
       
   337 */
       
   338 CResourceFile* CResourceArchiveImpl::NextL(HBufC*& aRscFileName)
       
   339 	{
       
   340 	//if end of list return nothing
       
   341 	if (iCurrentIndex==iRscList.Count())
       
   342 		return NULL;
       
   343 	//Construct the resource file name buffer
       
   344 	TRscEntry currentEntry=iRscList[iCurrentIndex];
       
   345 	HBufC* rscFileName=HBufC::NewLC(currentEntry.iRscName.Length());
       
   346 	TPtr modifiable(rscFileName->Des());
       
   347 	modifiable.Copy(currentEntry.iRscName);
       
   348 	//Construct the CResourceFile object	
       
   349 	CResourceFile* resourceFile=CResourceFile::NewL(currentEntry.iRscData);
       
   350 	CleanupStack::Pop(rscFileName);
       
   351 	//update the index
       
   352 	iCurrentIndex++;
       
   353 	aRscFileName=rscFileName;
       
   354 	return resourceFile;
       
   355 	}
       
   356 
       
   357 /** Reset the archive reader to start reading from the first resource
       
   358 @internalComponent 
       
   359 */
       
   360 void CResourceArchiveImpl::Reset()
       
   361 	{
       
   362 	iCurrentIndex=0;
       
   363 	}
       
   364 
       
   365 /** Return the type of the resource archive(SPI) file being read
       
   366 @internalComponent 
       
   367 */
       
   368 TUid CResourceArchiveImpl::Type()
       
   369 	{
       
   370 	return iSpiFileType;
       
   371 	}
       
   372 
       
   373 /** Function to look ahead whether next resource exists in the resource archive
       
   374 @internalComponent
       
   375 */
       
   376 TBool CResourceArchiveImpl::NextResourceExist() const
       
   377 	{
       
   378 	return (iCurrentIndex<iRscList.Count());
       
   379 	}
       
   380 
       
   381 /** Function used to retrieve a 4 bytes signed integer stored in Little Endian Format
       
   382 @internalComponent
       
   383 */
       
   384 TInt32 CResourceArchiveImpl::LittleEndianFourByteInteger(const TDesC8& aBuffer,TInt aIndexOfFirstByte) const
       
   385 	{
       
   386 	__ASSERT_DEBUG((aIndexOfFirstByte + 3) < aBuffer.Length(), ::Panic(EBafPanicBadIndex));
       
   387 	return aBuffer[aIndexOfFirstByte] | (aBuffer[aIndexOfFirstByte+1]<<8) | (aBuffer[aIndexOfFirstByte+2]<<16) | (aBuffer[aIndexOfFirstByte+3]<<24);
       
   388 	}
       
   389 
       
   390 
       
   391 
       
   392 
       
   393 
       
   394 
       
   395 
       
   396 
       
   397 
       
   398 
       
   399 
       
   400 
       
   401 
       
   402 
       
   403 
       
   404 
       
   405 
       
   406 
       
   407 
       
   408 
       
   409