|
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 |