|
1 /* |
|
2 * Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies). |
|
3 * All rights reserved. |
|
4 * This component and the accompanying materials are made available |
|
5 * under the terms of the License "Eclipse Public License v1.0" |
|
6 * which accompanies this distribution, and is available |
|
7 * at the URL "http://www.eclipse.org/legal/epl-v10.html". |
|
8 * |
|
9 * Initial Contributors: |
|
10 * Nokia Corporation - initial contribution. |
|
11 * |
|
12 * Contributors: |
|
13 * |
|
14 * Description: |
|
15 * filemerger.cpp |
|
16 * |
|
17 */ |
|
18 |
|
19 |
|
20 #include <e32cons.h> |
|
21 #include <scs/cleanuputils.h> |
|
22 #include <apmstd.h> |
|
23 #include <apgcli.h> |
|
24 #include "usiflog.h" |
|
25 #include "sifrefbinpkgextractor.h" |
|
26 |
|
27 _LIT8(KCompoundPackageHeader, "_SifReferenceInstallerPackageHeader_"); |
|
28 _LIT8(KCompoundPackageFooter, "_SifReferenceInstallerPackageFooter_"); |
|
29 _LIT(KPkgFileExt, ".sifrefpkg"); |
|
30 _LIT(KRefBinPkgMimeType, "binary/sif-refpkg"); |
|
31 _LIT(KEmbCompMidDir, "children\\"); |
|
32 _LIT(KDirSeparator, "\\"); |
|
33 |
|
34 const TInt KBufferLength = 0x3FFC; // 16kB |
|
35 const TInt KMaxNumFiles = 16; |
|
36 const TInt KMaxEmbCompSize = 0xFFFFFF; // 16MB |
|
37 |
|
38 using namespace Usif; |
|
39 |
|
40 namespace |
|
41 { |
|
42 TInt ReadInt32L(RFile& file) |
|
43 { |
|
44 TBuf8<4> buf; |
|
45 User::LeaveIfError(file.Read(buf, sizeof(TInt))); |
|
46 return buf[0] | buf[1]<<8 | buf[2]<<16 | buf[3]<<24; |
|
47 } |
|
48 |
|
49 HBufC* BuildPkgFileNameLC(const TDesC& aTempDir, const TDesC& aBinPkgPath) |
|
50 { |
|
51 TParsePtrC parser(aBinPkgPath); |
|
52 TPtrC binPkgfileName = parser.Name(); |
|
53 HBufC* pkgfileName = HBufC::NewLC(aTempDir.Length() + binPkgfileName.Length() + KPkgFileExt.iTypeLength); |
|
54 TPtr pkgfileNamePtr = pkgfileName->Des(); |
|
55 pkgfileNamePtr += aTempDir; |
|
56 pkgfileNamePtr += binPkgfileName; |
|
57 pkgfileNamePtr += KPkgFileExt; |
|
58 |
|
59 return pkgfileName; |
|
60 } |
|
61 |
|
62 HBufC* BuildPkgFileNameLC(const TDesC& aTempDir, const RFile& aFile) |
|
63 { |
|
64 HBufC* name = HBufC::NewLC(KMaxFileName); |
|
65 TPtr namePtr(name->Des()); |
|
66 User::LeaveIfError(aFile.Name(namePtr)); |
|
67 |
|
68 HBufC* pkgName = BuildPkgFileNameLC(aTempDir, *name); |
|
69 |
|
70 CleanupStack::Pop(pkgName); |
|
71 CleanupStack::PopAndDestroy(name); |
|
72 CleanupStack::PushL(pkgName); |
|
73 |
|
74 return pkgName; |
|
75 } |
|
76 |
|
77 void ExtractBinPkgFileL(RStsSession& aSts, RFile& aInFile, const TDesC& aOutPath, RPointerArray<HBufC>& aOutFiles) |
|
78 { |
|
79 // Check file size |
|
80 TInt size(0); |
|
81 User::LeaveIfError(aInFile.Size(size)); |
|
82 if (size < KCompoundPackageHeader.iTypeLength+KCompoundPackageFooter.iTypeLength+sizeof(TInt)) |
|
83 { |
|
84 User::Leave(KErrCorrupt); |
|
85 } |
|
86 |
|
87 // Create a buffer |
|
88 HBufC8* buffer = HBufC8::NewLC(KBufferLength); |
|
89 TPtr8 bufPtr = buffer->Des(); |
|
90 |
|
91 // Read header |
|
92 User::LeaveIfError(aInFile.Read(bufPtr, KCompoundPackageHeader.iTypeLength)); |
|
93 if (bufPtr != KCompoundPackageHeader) |
|
94 { |
|
95 User::Leave(KErrCorrupt); |
|
96 } |
|
97 bufPtr.Zero(); |
|
98 |
|
99 // Read the size of a pkg content |
|
100 const TInt pkgSize = ReadInt32L(aInFile); |
|
101 if (pkgSize > KBufferLength) |
|
102 { |
|
103 User::Leave(KErrCorrupt); |
|
104 } |
|
105 |
|
106 // Build the name of the pkg file |
|
107 HBufC* inFileNameWithExt = HBufC::NewLC(KMaxFileName); |
|
108 TPtr inFileNameWithExtPtr = inFileNameWithExt->Des(); |
|
109 User::LeaveIfError(aInFile.Name(inFileNameWithExtPtr)); |
|
110 HBufC* pkgFileName = BuildPkgFileNameLC(aOutPath, *inFileNameWithExt); |
|
111 |
|
112 // Create the pkg file |
|
113 RFile pkgFile; |
|
114 aSts.CreateTemporaryL(*pkgFileName, pkgFile, EFileWrite); |
|
115 CleanupClosePushL(pkgFile); |
|
116 |
|
117 // Copy the content of the pkg file |
|
118 User::LeaveIfError(aInFile.Read(bufPtr, pkgSize)); |
|
119 User::LeaveIfError(pkgFile.Write(bufPtr)); |
|
120 CleanupStack::PopAndDestroy(&pkgFile); |
|
121 bufPtr.Zero(); |
|
122 |
|
123 // Read the number of embedded components |
|
124 const TInt numEmbComps = ReadInt32L(aInFile); |
|
125 if (numEmbComps > KMaxNumFiles) |
|
126 { |
|
127 User::Leave(KErrCorrupt); |
|
128 } |
|
129 |
|
130 // Create a directory for embedded components |
|
131 HBufC* embCompPath = NULL; |
|
132 if (numEmbComps > 0) |
|
133 { |
|
134 embCompPath = HBufC::NewLC(aOutPath.Length() + KEmbCompMidDir.iTypeLength); |
|
135 embCompPath->Des().Copy(aOutPath); |
|
136 embCompPath->Des().Append(KEmbCompMidDir); |
|
137 } |
|
138 |
|
139 // Iterate over the components and extract them |
|
140 for (TInt i=0; i<numEmbComps; ++i) |
|
141 { |
|
142 // Read the length of the name of an embedded component |
|
143 const TInt strLen = ReadInt32L(aInFile); |
|
144 if (strLen > KMaxPath) |
|
145 { |
|
146 User::Leave(KErrCorrupt); |
|
147 } |
|
148 |
|
149 // Read the name of an embedded component and build its target path |
|
150 User::LeaveIfError(aInFile.Read(bufPtr, strLen)); |
|
151 HBufC* embFileName = ConvertBufferTo16bitL(bufPtr); |
|
152 CleanupStack::PushL(embFileName); |
|
153 bufPtr.Zero(); |
|
154 HBufC* embFileTargetPath = HBufC::NewLC(embCompPath->Length() + 2*embFileName->Length() + KDirSeparator.iTypeLength); |
|
155 TPtr embFileTargetPathPtr(embFileTargetPath->Des()); |
|
156 embFileTargetPathPtr.Copy(*embCompPath); |
|
157 embFileTargetPathPtr += *embFileName; |
|
158 embFileTargetPathPtr += KDirSeparator; |
|
159 embFileTargetPathPtr += *embFileName; |
|
160 |
|
161 // Read the size of an embedded component |
|
162 const TInt fileSize = ReadInt32L(aInFile); |
|
163 if (fileSize > KMaxEmbCompSize) |
|
164 { |
|
165 User::Leave(KErrCorrupt); |
|
166 } |
|
167 |
|
168 // Create an output file |
|
169 RFile outFile; |
|
170 aSts.CreateTemporaryL(*embFileTargetPath, outFile, EFileWrite); |
|
171 CleanupClosePushL(outFile); |
|
172 |
|
173 // Copy the content of the output file |
|
174 const TInt numChunks = fileSize / KBufferLength; |
|
175 for (TInt c=0; c<numChunks; ++c) |
|
176 { |
|
177 User::LeaveIfError(aInFile.Read(bufPtr, KBufferLength)); |
|
178 User::LeaveIfError(outFile.Write(bufPtr)); |
|
179 bufPtr.Zero(); |
|
180 } |
|
181 const TInt remainder = fileSize % KBufferLength; |
|
182 User::LeaveIfError(aInFile.Read(bufPtr, remainder)); |
|
183 User::LeaveIfError(outFile.Write(bufPtr)); |
|
184 bufPtr.Zero(); |
|
185 |
|
186 CleanupStack::PopAndDestroy(&outFile); |
|
187 aOutFiles.AppendL(embFileTargetPath); |
|
188 CleanupStack::Pop(embFileTargetPath); |
|
189 CleanupStack::PopAndDestroy(embFileName); |
|
190 } |
|
191 |
|
192 if (embCompPath != NULL) |
|
193 { |
|
194 CleanupStack::PopAndDestroy(embCompPath); |
|
195 } |
|
196 |
|
197 // Read footer |
|
198 User::LeaveIfError(aInFile.Read(bufPtr, KCompoundPackageFooter.iTypeLength)); |
|
199 if (bufPtr != KCompoundPackageFooter) |
|
200 { |
|
201 User::Leave(KErrCorrupt); |
|
202 } |
|
203 bufPtr.Zero(); |
|
204 |
|
205 CleanupStack::PopAndDestroy(3, buffer); // inFileNameWithExt, pkgFileName |
|
206 } |
|
207 |
|
208 void ExtractBinPkgFileL(RStsSession& aSts, const TDesC& aInFileName, const TDesC& aOutPath, RPointerArray<HBufC>& aOutFiles) |
|
209 { |
|
210 RFs fs; |
|
211 RFile file; |
|
212 User::LeaveIfError(fs.Connect()); |
|
213 CleanupClosePushL(fs); |
|
214 TInt err = file.Open(fs, aInFileName, EFileShareReadersOnly); |
|
215 if (err != KErrNone) |
|
216 { |
|
217 DEBUG_PRINTF3(_L8("Failed to open file: %S with error: %d"), &aInFileName, err); |
|
218 User::Leave(err); |
|
219 } |
|
220 CleanupClosePushL(file); |
|
221 |
|
222 ExtractBinPkgFileL(aSts, file, aOutPath, aOutFiles); |
|
223 |
|
224 CleanupStack::PopAndDestroy(2, &fs); |
|
225 } |
|
226 |
|
227 TBool IsForeignL(RFile& aFileHandle) |
|
228 { |
|
229 // Get the MIME type of the component to be installed from AppArc |
|
230 TDataType dataType; |
|
231 RApaLsSession apa; |
|
232 User::LeaveIfError(apa.Connect()); |
|
233 CleanupClosePushL(apa); |
|
234 TUid appUid = TUid::Null(); |
|
235 User::LeaveIfError(apa.AppForDocument(aFileHandle, appUid, dataType)); |
|
236 // A possible problem with recognizers is returning a successful result, but forgetting to set the MIME type |
|
237 if (dataType.Des8().Ptr() == NULL) |
|
238 { |
|
239 User::Leave(KErrCompletion); |
|
240 } |
|
241 CleanupStack::PopAndDestroy(&apa); |
|
242 |
|
243 return dataType.Des() != KRefBinPkgMimeType; |
|
244 } |
|
245 |
|
246 TBool IsForeignL(const TDesC& aFileName) |
|
247 { |
|
248 RFs fs; |
|
249 RFile file; |
|
250 User::LeaveIfError(fs.Connect()); |
|
251 CleanupClosePushL(fs); |
|
252 User::LeaveIfError(fs.ShareProtected()); |
|
253 TInt err = file.Open(fs, aFileName, EFileShareReadersOnly); |
|
254 if (err != KErrNone) |
|
255 { |
|
256 DEBUG_PRINTF3(_L8("Failed to open file: %S with error: %d"), &aFileName, err); |
|
257 User::Leave(err); |
|
258 } |
|
259 CleanupClosePushL(file); |
|
260 |
|
261 const TBool result = IsForeignL(file); |
|
262 |
|
263 CleanupStack::PopAndDestroy(2, &fs); // file |
|
264 |
|
265 return result; |
|
266 } |
|
267 } |
|
268 |
|
269 namespace Usif |
|
270 { |
|
271 namespace SifRefBinPkgExtractor |
|
272 { |
|
273 CAuxNode* CAuxNode::NewLC(const TDesC& aFileName, TBool aForeign, CAuxNode& aParent) |
|
274 { |
|
275 CAuxNode* self = new (ELeave) CAuxNode; |
|
276 CleanupStack::PushL(self); |
|
277 |
|
278 self->iFileName = aFileName.AllocL(); |
|
279 self->iForeign = aForeign; |
|
280 self->iParent = &aParent; |
|
281 |
|
282 return self; |
|
283 } |
|
284 CAuxNode* CAuxNode::NewLC(const RFile& aFile, TBool aForeign, CAuxNode& aParent) |
|
285 { |
|
286 CAuxNode* self = new (ELeave) CAuxNode; |
|
287 CleanupStack::PushL(self); |
|
288 |
|
289 HBufC* name = HBufC::NewLC(KMaxFileName); |
|
290 TPtr namePtr(name->Des()); |
|
291 User::LeaveIfError(aFile.Name(namePtr)); |
|
292 |
|
293 self->iFileName = name->AllocL(); |
|
294 self->iForeign = aForeign; |
|
295 self->iParent = &aParent; |
|
296 |
|
297 CleanupStack::PopAndDestroy(name); |
|
298 return self; |
|
299 } |
|
300 |
|
301 CAuxNode::CAuxNode() |
|
302 { |
|
303 } |
|
304 |
|
305 CAuxNode::~CAuxNode() |
|
306 { |
|
307 delete iFileName; |
|
308 delete iNode; |
|
309 delete iCompInfo; |
|
310 } |
|
311 |
|
312 void CAuxNode::SetNodeL(CComponentInfo::CNode* aNode) |
|
313 { |
|
314 if (iNode != NULL) |
|
315 { |
|
316 User::Leave(KErrAlreadyExists); |
|
317 } |
|
318 iNode = aNode; |
|
319 } |
|
320 |
|
321 void CAuxNode::SetCompInfoL(CComponentInfo* aCompInfo) |
|
322 { |
|
323 if (iCompInfo != NULL) |
|
324 { |
|
325 User::Leave(KErrAlreadyExists); |
|
326 } |
|
327 iCompInfo = aCompInfo; |
|
328 } |
|
329 |
|
330 void CAuxNode::RegisterChildToParentL() |
|
331 { |
|
332 ASSERT (iCompInfo != NULL || iNode != NULL); |
|
333 |
|
334 if (iCompInfo != NULL) |
|
335 { |
|
336 iCompInfo->SetRootNodeAsChildL(*iParent->iNode); |
|
337 delete iCompInfo; |
|
338 iCompInfo = NULL; |
|
339 } |
|
340 else |
|
341 { |
|
342 iParent->iNode->AddChildL(iNode); |
|
343 iNode = NULL; |
|
344 } |
|
345 } |
|
346 |
|
347 void CAuxNode::SetAsRootNodeL(CComponentInfo& aCompInfo) |
|
348 { |
|
349 if (iNode == NULL) |
|
350 { |
|
351 User::Leave(KErrNotFound); |
|
352 } |
|
353 aCompInfo.SetRootNodeL(iNode); |
|
354 iNode = NULL; |
|
355 } |
|
356 |
|
357 //------------------------------------------------------------------------------------------------------- |
|
358 |
|
359 void BuildPkgTreeImplL(RStsSession& aSts, const TDesC* aInFileName, RFile* aInFile, const TDesC& aTempDir, RPointerArray<CAuxNode>& aFlatTree, CAuxNode* aParent) |
|
360 { |
|
361 __ASSERT_ALWAYS(aInFileName != NULL || aInFile != NULL, User::Leave(KErrArgument)); |
|
362 |
|
363 RCPointerArray<HBufC> embFiles; |
|
364 CleanupClosePushL(embFiles); |
|
365 CAuxNode* node = NULL; |
|
366 HBufC* pkgFileName = NULL; |
|
367 const TBool foreign = aInFile ? IsForeignL(*aInFile) : IsForeignL(*aInFileName); |
|
368 if (!foreign) |
|
369 { |
|
370 if (aInFile != NULL) |
|
371 { |
|
372 ExtractBinPkgFileL(aSts, *aInFile, aTempDir, embFiles); |
|
373 } |
|
374 else |
|
375 { |
|
376 ExtractBinPkgFileL(aSts, *aInFileName, aTempDir, embFiles); |
|
377 } |
|
378 |
|
379 pkgFileName = aInFile ? BuildPkgFileNameLC(aTempDir, *aInFile) : BuildPkgFileNameLC(aTempDir, *aInFileName); |
|
380 node = CAuxNode::NewLC(*pkgFileName, EFalse, *aParent); |
|
381 aFlatTree.AppendL(node); |
|
382 CleanupStack::Pop(node); |
|
383 for (TInt i=0; i<embFiles.Count(); ++i) |
|
384 { |
|
385 const TDesC& fileName = *embFiles[i]; |
|
386 TParsePtrC parser(fileName); |
|
387 BuildPkgTreeImplL(aSts, &fileName, NULL, parser.DriveAndPath(), aFlatTree, node); |
|
388 } |
|
389 } |
|
390 else |
|
391 { |
|
392 if (aParent == NULL) |
|
393 { |
|
394 User::Leave(KErrCorrupt); |
|
395 } |
|
396 if (aInFileName != NULL) |
|
397 { |
|
398 node = CAuxNode::NewLC(*aInFileName, ETrue, *aParent); |
|
399 } |
|
400 else |
|
401 { |
|
402 node = CAuxNode::NewLC(*aInFile, ETrue, *aParent); |
|
403 } |
|
404 aFlatTree.AppendL(node); |
|
405 CleanupStack::Pop(node); |
|
406 } |
|
407 |
|
408 if (pkgFileName != NULL) |
|
409 { |
|
410 CleanupStack::PopAndDestroy(pkgFileName); |
|
411 } |
|
412 |
|
413 CleanupStack::PopAndDestroy(&embFiles); |
|
414 } |
|
415 |
|
416 void BuildPkgTreeL(RStsSession& aSts, RFile& aInFile, const TDesC& aTempDir, RPointerArray<CAuxNode>& aFlatTree, CAuxNode* aParent) |
|
417 { |
|
418 BuildPkgTreeImplL(aSts, NULL, &aInFile, aTempDir, aFlatTree, aParent); |
|
419 } |
|
420 |
|
421 void BuildPkgTreeL(RStsSession& aSts, const TDesC& aInFileName, const TDesC& aTempDir, RPointerArray<CAuxNode>& aFlatTree, CAuxNode* aParent) |
|
422 { |
|
423 BuildPkgTreeImplL(aSts, &aInFileName, NULL, aTempDir, aFlatTree, aParent); |
|
424 } |
|
425 } // namespace SifRefBinPkgExtractor |
|
426 } //namespace Usif |