smartinstaller/adm/src/ADMXmlParser.cpp
branchADM
changeset 48 364021cecc90
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/smartinstaller/adm/src/ADMXmlParser.cpp	Wed Jun 30 11:01:26 2010 +0530
@@ -0,0 +1,594 @@
+/*
+* Copyright (c) 2009-2010 Nokia Corporation and/or its subsidiary(-ies).
+* All rights reserved.
+* This component and the accompanying materials are made available
+* under the terms of "Eclipse Public License v1.0"
+* which accompanies this distribution, and is available
+* at the URL "http://www.eclipse.org/legal/epl-v10.html".
+*
+* Initial Contributors:
+* Nokia Corporation - initial contribution.
+*
+* Contributors:
+*
+* Description: 
+*     CXmlParser implementation
+*
+*
+*/
+
+
+#include <SenDomFragment.h>
+#include <SenXmlReader.h>
+#include <SenElement.h>
+#include "ADMXmlParser.h"
+#include "ADMPackageInfo.h"
+#include "macros.h"
+#include "config.h"
+
+_LIT(KSisExtension,".sis");
+
+CXmlParser* CXmlParser::NewLC()
+	{
+	CXmlParser* object = new ( ELeave ) CXmlParser();
+	CleanupStack::PushL( object );
+	object->ConstructL();
+	return object;
+	}
+
+CXmlParser* CXmlParser::NewL()
+	{
+	CXmlParser* object = CXmlParser::NewLC();
+	CleanupStack::Pop();
+	return object;
+	}
+
+CXmlParser::CXmlParser()
+	:iXmlReader(NULL),
+	iDomFragment(NULL)
+	{
+	}
+
+CXmlParser::~CXmlParser()
+	{
+	iRfs.Close();
+
+	if ( iXmlReader )
+		{
+		delete iXmlReader;
+		iXmlReader = NULL;
+		}
+	if ( iDomFragment )
+		{
+		delete iDomFragment;
+		iDomFragment = NULL;
+		}
+	}
+
+void CXmlParser::ConstructL()
+	{
+	User::LeaveIfError(iRfs.Connect());
+	}
+
+void CXmlParser::InitL()
+	{
+	// Do the cleanup as this function could be
+	// called multiple times.
+	if ( iXmlReader )
+	   {
+	   delete iXmlReader;
+	   iXmlReader = NULL;
+	   }
+
+	if ( iDomFragment )
+	   {
+	   delete iDomFragment;
+	   iDomFragment = NULL;
+	   }
+
+	iXmlReader = CSenXmlReader::NewL(EErrorOnUnrecognisedTags);
+	iDomFragment = CSenDomFragment::NewL();
+
+	iXmlReader->SetContentHandler(*iDomFragment);
+	iDomFragment->SetReader(*iXmlReader);
+	}
+
+void CXmlParser::GetChangesInfoL(const TDesC& aChangesFileName, CPackageInfo *packageInfo,CDepTree* mainTree)
+	{
+	InitL();
+
+	iXmlReader->ParseL(iRfs, aChangesFileName);
+
+	// Get package uid
+	// Leave if package uid not present
+	CSenElement* packageElement;
+	packageElement = iDomFragment->AsElement().Element(KFieldDepPackageUid);
+	if (packageElement == NULL)
+		{
+		User::Leave(EMissingPackageUid);
+		}
+	TPtrC8 packageUidPtr = packageElement->Content();
+	TUint32 packageUid=0;
+	if (StringToInt(packageUidPtr,packageUid) != KErrNone)
+		{
+		User::Leave(EInvalidPackageUid);
+		}
+
+	//Check whether the packageId received in changes file is same as the one already stored in the packageinfo from dependency info.
+	//If there is mismatch, exit. If it matches, proceed further.
+	if(packageUid != packageInfo->iPackageUid)
+		{
+		User::Leave(EIncorrectPackageUid);
+		}
+
+	packageElement = iDomFragment->AsElement().Element(KFieldDepPackageName);
+	if (packageElement)
+		{
+		DELETE_IF_NONNULL( packageInfo->iPackageName );
+		packageInfo->iPackageName = packageElement->ContentUnicodeL();
+		}
+	else
+		{
+		User::Leave(EMissingPackageName);
+		}
+
+	// Get dependent package vendor
+	packageElement = iDomFragment->AsElement().Element(KFieldDepVendor);
+	if (packageElement)
+		{
+		DELETE_IF_NONNULL( packageInfo->iVendor );
+		packageInfo->iVendor = packageElement->ContentUnicodeL();
+		}
+	else
+		{
+		User::Leave(EMissingVendorName);
+		}
+
+	// Get Priority for the drive
+	//This is optional.Hence no Leave for Missing Priority.
+	//Default is 0.
+	packageElement = iDomFragment->AsElement().Element(KFieldDrivePriority);
+	if(packageElement)
+		{
+		TPtrC8 drivePtr = packageElement->Content();
+		if (StringToInt(drivePtr,packageInfo->iDrivePriority) != KErrNone)
+			{
+			User::Leave(EInvalidDrivePriority);
+			}
+		}
+
+	// Get the mandatory drive.
+	//This is optional.Hence no Leave for Missing info.
+	//Default is none.
+	packageElement = iDomFragment->AsElement().Element(KFieldMandatoryInstallDrive);
+	if(packageElement)
+		{
+		packageInfo->iMandatoryInstallDrive = packageElement->ContentUnicodeL()->Des()[0];
+		}
+
+	GetVersionInfoL(packageInfo,mainTree->GetMachineId());
+	}
+
+void CXmlParser::GetVersionInfoL(CPackageInfo *packageInfo,TUint32 machineId)
+	{
+	RPointerArray<CSenElement> versionInfo;
+	CleanupClosePushL(versionInfo);
+
+	iDomFragment->AsElement().ElementsL(versionInfo,KFieldVersionInformation);
+	const TInt versionInfoCount(versionInfo.Count());
+	TVersion latestVersion(0,0,0);
+	TInt latestVersionCount = -1;
+	CSenElement* packageElement;
+
+	//Changes file will contain different versions of the package along
+	//with the list of supporrted devices for that perticular version.
+
+	//If no version was specified in the dep file, then the latest should be read.
+	//While reading the latest, it should be confirmed whether the same supports the given device.
+
+	for (TInt i=0; i<versionInfoCount; ++i)
+		{
+		packageElement = versionInfo[i]->Element(KFieldDepPackageVersion);
+		if (packageElement == NULL)
+			{
+			User::Leave(EMissingDepVersion);
+			}
+
+		TPtrC8 versionPtr = packageElement->Content();
+		TVersion ver;
+		if (SetVersion(versionPtr, ver) == EFalse)
+			{
+			User::Leave(EInvalidVersion);
+			}
+
+		//Check whether the MachineID of this device is supported for this corresponding version in the changes file.
+		if(checkMachineIdL(versionInfo[i],machineId))
+			{
+			if((CompareVersions(packageInfo->iVersion,ver) == EEqualVersion)||(CompareVersions(packageInfo->iVersion,ver) == EGreaterSecondVersion))
+				{
+				//Version specified in the dep file of parent matches the version in the changes file which inturn matches to the MachineID. :)
+				//Or there exists a greater version in changes file.
+				latestVersion = ver;
+				latestVersionCount = i;
+				}
+			}
+		}//end of for loop
+
+	if(latestVersionCount == -1)
+		{
+		//No matching Machine IDs at all for any version specified in the changes file.
+		User::Leave(EUnsupportedDevice);
+		}
+	else
+		{
+		packageInfo->iVersion = latestVersion;
+		}
+
+	// Get dependent package URL
+	packageElement= versionInfo[latestVersionCount]->Element(KFieldDepUrl);
+	if (packageElement)
+		{
+		DELETE_IF_NONNULL( packageInfo->iUrl );
+		TPtrC8 urlPtr = packageElement->Content();
+
+		HBufC8* url = urlPtr.AllocL();
+
+		packageInfo->iUrl = url;
+		}
+	else
+		{
+		User::Leave(EMissingPackageUrl);
+		}
+
+
+	packageElement = versionInfo[latestVersionCount]->Element(KFieldDepFileName);
+	if (packageElement)
+		{
+		DELETE_IF_NONNULL( packageInfo->iDepFileName );
+		packageInfo->iDepFileName = packageElement->ContentUnicodeL();
+		}
+	else
+		{
+		User::Leave(EMissingDepFileName);
+		}
+
+	packageElement = versionInfo[latestVersionCount]->Element(KFieldInstallPackageName);
+	if (packageElement)
+		{
+		DELETE_IF_NONNULL( packageInfo->iSisPackageName );
+		packageInfo->iSisPackageName = packageElement->ContentUnicodeL();
+		}
+	else
+		{
+		User::Leave(EMissingSisFileName);
+		}
+
+	packageElement = versionInfo[latestVersionCount]->Element(KFieldDateOfSubmission);
+	if (packageElement)
+		{
+		DELETE_IF_NONNULL( packageInfo->iDateOfSubmission );
+		packageInfo->iDateOfSubmission = packageElement->ContentUnicodeL();
+		}
+	else
+		{
+		User::Leave(EMissingSubmissionDate);
+		}
+	//TODO: There needs to be a separate function to convert the Date format into a string format.
+	//Call that function here.
+	packageElement = versionInfo[latestVersionCount]->Element(KFieldDateOfModification);
+	if (packageElement)
+		{
+		DELETE_IF_NONNULL( packageInfo->iDateOfModification );
+		packageInfo->iDateOfModification = packageElement->ContentUnicodeL();
+		}
+	else
+		{
+		User::Leave(EMissingModificationDate);
+		}
+
+	packageElement = versionInfo[latestVersionCount]->Element(KFieldDownloadSize);
+	TPtrC8 downloadSizePtr = packageElement->Content();
+	TUint32 downloadSize=0;
+	if (StringToInt(downloadSizePtr,downloadSize) != KErrNone)
+		{
+		User::Leave(EInvalidPackageUid);
+		}
+	if(downloadSize)
+		{
+		packageInfo->iDownloadSize = downloadSize;
+		}
+	else
+		{
+		User::Leave(EMissingDownloadSize);
+		}
+
+	packageElement = versionInfo[latestVersionCount]->Element(KFieldInstalledSize);
+	TPtrC8 installedSizePtr = packageElement->Content();
+	TUint32 installedSize=0;
+	if (StringToInt(installedSizePtr,installedSize) != KErrNone)
+		{
+		User::Leave(EInvalidPackageUid);
+		}
+	if(installedSize)
+		{
+		packageInfo->iInstalledSize = installedSize;
+		}
+	else
+		{
+		User::Leave(EMissingInstalledSize);
+		}
+	CleanupStack::PopAndDestroy(&versionInfo);
+}
+
+TBool CXmlParser::checkMachineIdL(CSenElement *versionInfo, TUint32 machineId)
+	{
+	RPointerArray<CSenElement> deviceInfo;
+	CleanupClosePushL(deviceInfo);
+
+	versionInfo->ElementsL(deviceInfo,KFieldSupportedDevice);
+	const TInt deviceInfoCount(deviceInfo.Count());
+
+	CSenElement* packageElement;
+
+	// See if the device is supported by this
+	// particular version, by comparing the list
+	// of machine ids supported by the version
+	// with the machine id of device. .
+	for(TInt i=0;i<deviceInfoCount;i++)
+		{
+		packageElement = deviceInfo[i]->Element(KFieldDeviceMachineId);
+
+		if (packageElement == NULL)
+			{
+			User::Leave(EMissingMachineID);
+			}
+		TPtrC8 packageUidPtr = packageElement->Content();
+		TUint32 changesMachineId = 0;
+		if (StringToInt(packageUidPtr,changesMachineId) != KErrNone)
+			{
+			User::Leave(EInvalidMachineID);
+			}
+		if(changesMachineId == machineId)
+			{
+			CleanupStack::PopAndDestroy(&deviceInfo);
+			return ETrue;
+			}
+		}
+	CleanupStack::PopAndDestroy(&deviceInfo);
+	return EFalse;
+	}
+
+CPackageInfo* CXmlParser::GetDepContentsL(const TDesC& aDepFileName, CPackageInfo *packageInfo, CDepTree* aMainTree)
+	{
+	InitL();
+
+	iXmlReader->ParseL(iRfs, aDepFileName);
+
+	// Get package uid
+	// Leave if package uid not present
+	CSenElement* packageElement;
+	packageElement = iDomFragment->AsElement().Element(KFieldPackageUid);
+	if (packageElement == NULL)
+		{
+		User::Leave(EMissingPackageUid);
+		}
+	TPtrC8 packageUidPtr = packageElement->Content();
+	TUint32 packageUid=0;
+	if (StringToInt(packageUidPtr,packageUid) != KErrNone)
+		{
+		User::Leave(EInvalidPackageUid);
+		}
+
+	User::LeaveIfNull(aMainTree);
+	if(aMainTree->IsDepTreeEmpty())
+		{
+		// Add root package(first package) to the list
+		packageInfo = CPackageInfo::NewL();
+		packageInfo->iPackageUid = packageUid;
+		packageInfo->iPackageStatus = EPackageRootToBeInstalled;
+		aMainTree->AddPackageInfo(packageInfo);
+		}
+	else
+		{
+		User::LeaveIfNull(packageInfo);
+		if(packageInfo->iPackageUid != packageUid)
+			{
+			//the package pointer doesn't match the depfile
+			User::Leave(EInvalidPackageUid);
+			}
+		}
+
+	// Get Dep version
+	// Leave if Dep version is not present
+	packageElement = iDomFragment->AsElement().Element(KFieldDepVersion);
+	if (packageElement == NULL)
+		{
+		User::Leave(EMissingDepVersion);
+		}
+	else
+		{
+		TPtrC8 versionPtr = packageElement->Content();
+		TVersion ver;
+		if (SetVersion(versionPtr, ver) == EFalse)
+			{
+			User::Leave(EInvalidVersion);
+			}
+		packageInfo->iDepVersion = ver;
+		}
+
+	// Parse the dependencies
+	SetDependenciesL(packageInfo, aMainTree);
+
+	return packageInfo;
+	}
+
+void CXmlParser::SetDependenciesL(CPackageInfo* aPackageInfo, CDepTree* aMainTree)
+	{
+	// Get dependencies
+	RPointerArray<CSenElement> dependency;
+	CleanupClosePushL(dependency);
+
+	iDomFragment->AsElement().ElementsL(dependency,KFieldDependency);
+	const TInt DependencyCount(dependency.Count());
+
+	User::LeaveIfNull(aMainTree);
+	User::LeaveIfNull(aPackageInfo);
+
+
+	TBool IsNonRootNodeDep = 1;
+
+	// Check if the dependencies are of the root node.
+	// If yes, then clear the flag
+	if (aMainTree->GetRootNode() == aPackageInfo)
+		{
+		IsNonRootNodeDep = 0;
+		}
+
+	for (TInt i=0; i<DependencyCount; ++i)
+		{
+		// Get dependency UID
+		CSenElement* packageElement;
+		TUint32 depPackageUid = 0;
+		packageElement = dependency[i]->Element(KFieldDepPackageUid);
+		if (packageElement == NULL)
+			{
+			User::Leave(EMissingPackageUid);
+			}
+		TPtrC8 depPackageUidPtr = packageElement->Content();
+		if ( StringToInt(depPackageUidPtr,depPackageUid) != KErrNone )
+			{
+			User::Leave(EInvalidPackageUid);
+			}
+
+		// Check if the dependency already present in the tree.
+		CPackageInfo* depPackageInfo = aMainTree->LocatePackageInDepTree(depPackageUid);
+
+		// If dependency is listed in the tree,
+		// create a new edge for it
+		if (depPackageInfo != NULL)
+			{
+			aPackageInfo->AddEdgeL(depPackageInfo);
+			continue;
+			}
+
+		// Dependency is not already present, so create a new node
+		depPackageInfo = CPackageInfo::NewL();
+		aMainTree->AddPackageInfo(depPackageInfo);
+
+		depPackageInfo->iPackageUid = depPackageUid;
+		aPackageInfo->AddEdgeL(depPackageInfo);
+
+		// Get dependent package name
+		packageElement = dependency[i]->Element(KFieldDepPackageName);
+		if (packageElement)
+			{
+			depPackageInfo->iPackageName = packageElement->ContentUnicodeL();
+			}
+		else if(IsNonRootNodeDep)
+			{
+			User::Leave(EMissingPackageName);
+			}
+		else
+			{
+			depPackageInfo->iPackageName = HBufC::NewL(
+												depPackageUidPtr.Length() +
+												KSisExtension().Length());
+
+			TPtr depPackageName(depPackageInfo->iPackageName->Des());
+			depPackageName.Copy(depPackageUidPtr);
+			depPackageName.Append(KSisExtension);
+			}
+
+
+		// Get dependent package version
+		packageElement = dependency[i]->Element(KFieldDepPackageVersion);
+
+		if(packageElement)
+			{
+			TPtrC8 versionPtr = packageElement->Content();
+			TVersion ver;
+			if (SetVersion(versionPtr, ver) == EFalse)
+				{
+				User::Leave(EInvalidVersion);
+				}
+			depPackageInfo->iVersion = ver;
+			}
+		else if(IsNonRootNodeDep)
+			{
+			User::Leave(EMissingPackageVersion);
+			}
+
+		// Get dependent package vendor
+		packageElement = dependency[i]->Element(KFieldDepVendor);
+		if (packageElement)
+			{
+			depPackageInfo->iVendor = packageElement->ContentUnicodeL();
+			}
+		else if(IsNonRootNodeDep)
+			{
+			User::Leave(EMissingVendorName);
+			}
+
+#ifdef url_support
+		// Get dependent package URL
+		packageElement = dependency[i]->Element(KFieldDepUrl);
+
+		if (packageElement)
+			{
+			TPtrC8 urlPtr = packageElement->Content();
+			HBufC8* url = urlPtr.AllocL();
+
+			TPtr8 urlPtr2 = url->Des();
+			urlPtr2.Copy(urlPtr);
+
+			depPackageInfo->iUrl = url;
+			}
+		else if(IsNonRootNodeDep)
+			{
+			User::Leave(EMissingPackageUrl);
+			}
+#else
+		// Ignore the Url(if specified) for the root node.
+		if(IsNonRootNodeDep)
+			{
+			// Get dependent package URL
+			packageElement = dependency[i]->Element(KFieldDepUrl);
+			if (packageElement)
+				{
+				depPackageInfo->iUrl = packageElement->Content().AllocL();
+				}
+			else
+				{
+				User::Leave(EMissingPackageUrl);
+				}
+			}
+#endif
+		//Set the changes file name
+		depPackageInfo->SetChangesFileNameL();
+		}
+	CleanupStack::PopAndDestroy(&dependency);
+	}
+
+TInt CXmlParser::StringToInt(const TDesC8& aString, TUint32& aInt)
+	{
+	 // Function will return EFalse if string conversion fails.
+	 TLex8 lex(aString);
+	 lex.SkipSpace();
+
+	 if (lex.Peek() == '0')
+		 {
+		 lex.Inc();
+		 TChar c( lex.Peek() );
+		 c.LowerCase();
+		 if (c == 'x')
+			 {
+			 lex.Inc();
+			 return ( lex.Val(aInt,EHex) );
+			 }
+		 else
+			 {
+			 lex.UnGet();
+			 }
+		 }
+	 return ( lex.Val(aInt,EDecimal) );
+	}