installationservices/refswinstallationplugin/source/sifrefbinpkgextractor.cpp
changeset 24 84a16765cd86
equal deleted inserted replaced
6:aba6b8104af3 24:84a16765cd86
       
     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