diff -r 3f419852be07 -r 364021cecc90 smartinstaller/adm/src/ADMXmlParser.cpp --- /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 +#include +#include +#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 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; iElement(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 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;iElement(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 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; iElement(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) ); + }