secureswitools/swisistools/source/interpretsislib/expressionevaluator.cpp
changeset 0 ba25891c3a9e
child 34 741e5bba2bd1
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/secureswitools/swisistools/source/interpretsislib/expressionevaluator.cpp	Thu Dec 17 08:51:10 2009 +0200
@@ -0,0 +1,625 @@
+/*
+* Copyright (c) 2006-2009 Nokia Corporation and/or its subsidiary(-ies).
+* All rights reserved.
+* This component and the accompanying materials are made available
+* under the terms of the License "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: 
+*
+*/
+
+#include <iostream>
+#include <sstream>
+
+// User includes
+#include "sisexpression.h"
+#include "expressionevaluator.h"
+#include "sisstring.h"
+#include "is_utils.h"
+#include "errors.h"
+#include "symbiantypes.h"
+#include "stringutils.h"
+#include "rommanager.h"
+#include "configmanager.h"
+#include "sisfile.h"
+#include "sisregistryobject.h"
+#include "logger.h"
+#include "version.h"
+#include "is_utils.h"
+
+// ExpressionResult
+using namespace Utils;
+ExpressionResult::ExpressionResult(const std::wstring& aString)
+:   iType(EString), iString(&aString)
+    {
+    }
+
+
+ExpressionResult::ExpressionResult(TUint32 aInt)
+:   iType(EInt), iInt(aInt)
+    {
+    }
+
+
+TUint32 ExpressionResult::IntegerValue() const
+    {
+	if (iType!=EInt)
+	    {
+		std::string error = "corrupt SIS file: expression corrupt in condition statement";
+		throw InvalidSis("",error,INVALID_SIS);
+    	}
+
+    return iInt;
+    }
+
+
+bool ExpressionResult::BoolValue() const
+    {
+	return bool(IntegerValue());
+    }
+
+
+const std::wstring& ExpressionResult::StringValue() const
+    {
+	if (iType!=EString)
+	    {
+		std::string error = "corrupt SIS file: expression corrupt in condition statement";
+		throw InvalidSis("",error,INVALID_SIS);
+	    }
+
+    return *iString;
+    }
+
+
+// ExpressionEvaluator
+
+ExpressionEvaluator::ExpressionEvaluator(ExpressionEnvironment& aEnvironment)
+:   iExpEnv(aEnvironment), iTempResult(false), iExpressionDepth(0)
+    {
+    }
+
+
+void ExpressionEvaluator::Require(const void *aPointer) const
+    {
+	if (!aPointer)
+	    {
+		throw std::runtime_error("null pointer");
+    	}
+    }
+
+
+ExpressionResult ExpressionEvaluator::Evaluate(const CSISExpression* aExpression)
+    {
+	Require(aExpression);
+	return Evaluate(*aExpression);
+    }
+
+
+ExpressionResult ExpressionEvaluator::Evaluate(const CSISExpression& aExpression)
+    {
+	if (++iExpressionDepth > KMaxExpressionDepth)
+	    {
+		iExpressionDepth=0;
+		std::string error = "SIS File expression too complex\n";
+		std::string x;
+        //
+		throw InvalidSis(Ucs2ToUtf8(iExpEnv.GetPackageName(),x), error, SIS_NOT_SUPPORTED);
+	    }
+
+	switch (aExpression.Operator())
+	    {
+	case CSISExpression::EBinOpEqual:
+	case CSISExpression::EBinOpNotEqual:
+	case CSISExpression::EBinOpGreaterThan:
+	case CSISExpression::EBinOpLessThan:
+	case CSISExpression::EBinOpGreaterThanOrEqual:
+	case CSISExpression::EBinOpLessThanOrEqual:
+        {
+		const ExpressionResult resultLeft = Evaluate( aExpression.LHS() );
+		const ExpressionResult resultRight = Evaluate( aExpression.RHS() );
+        //
+	    switch (aExpression.Operator())
+	        {
+	    case CSISExpression::EBinOpEqual:
+            iTempResult = ( resultLeft == resultRight );
+            break;
+	    case CSISExpression::EBinOpNotEqual:
+            iTempResult = ( resultLeft != resultRight );
+            break;
+	    case CSISExpression::EBinOpGreaterThan:
+            iTempResult = ( resultLeft > resultRight );
+            break;
+	    case CSISExpression::EBinOpLessThan:
+            iTempResult = ( resultLeft < resultRight );
+            break;
+	    case CSISExpression::EBinOpGreaterThanOrEqual:
+            iTempResult = ( resultLeft >= resultRight );
+            break;
+	    case CSISExpression::EBinOpLessThanOrEqual:
+            iTempResult = ( resultLeft <= resultRight );
+            break;
+            }
+        //
+		break;
+        }
+    
+    case CSISExpression::ELogOpAnd:
+		{
+		ExpressionResult tmp1 = Evaluate(aExpression.LHS());
+		ExpressionResult tmp2 = Evaluate(aExpression.RHS());
+		iTempResult = ExpressionResult(tmp1.BoolValue() && tmp2.BoolValue());
+		break;
+		}
+
+	case CSISExpression::ELogOpOr:
+		{
+		ExpressionResult tmp1 = Evaluate(aExpression.LHS());
+		if (tmp1.BoolValue())
+    		{
+			iTempResult = ExpressionResult(true);
+	    	}
+		else
+		    {
+			iTempResult = ExpressionResult(Evaluate(aExpression.RHS())).BoolValue();
+		    }
+		break;
+		}
+
+	case CSISExpression::EUnaryOpNot:
+		iTempResult=!Evaluate(aExpression.RHS());
+		break;
+
+	case CSISExpression::EFuncAppProperties:
+        {
+        const TUint32 resultLeft = Evaluate( aExpression.LHS() ).IntegerValue();
+        const TUint32 resultRight = Evaluate( aExpression.RHS() ).IntegerValue();
+        //
+		iTempResult = iExpEnv.ApplicationProperty( resultLeft, resultRight );
+		break;
+        }
+
+	case CSISExpression::EFuncDevProperties:
+		iTempResult = ExpressionResult(iExpEnv.Package(Evaluate(aExpression.RHS()).IntegerValue()));
+		break;
+
+	case CSISExpression::EFuncExists:
+		{
+		const CSISString& pS = aExpression.String();
+		if(pS.WasteOfSpace())
+			{
+			throw std::runtime_error("null pointer");
+			}
+
+		/**
+		 * CR1125 - Add Package Versions to SIS File Conditionals
+		 * 
+		 * If the CSISExpression CSISString has been prefixed with the argument string identifier stored within
+		 * KVersionFuncPrefix, the condition is considered to be a VERSION function call. The argument string
+		 * is then passed to PackageVersion() to query the SIS Registry and determine whether the version of
+		 * an installed package satisfies the presented condition. 
+		 */
+		if(pS.GetString().substr(0,KFuncVersionPrefix.length()) == KFuncVersionPrefix)
+			{
+			iTempResult = ExpressionResult(iExpEnv.PackageVersion(pS.GetString().substr(KFuncVersionPrefix.length())));
+			}
+		/**
+		 * Support for exact and equivalent device supported languages
+		 */
+		else if (pS.GetString().substr(0,KFuncSupportedLanguagePrefix.length()) == KFuncSupportedLanguagePrefix)
+			{
+			iTempResult = ExpressionResult(iExpEnv.DeviceLanguage(pS.GetString().substr(KFuncSupportedLanguagePrefix.length())));
+			}
+		else
+			{
+			iTempResult = ExpressionResult(iExpEnv.FindFile(pS.GetString()));
+			}
+		}
+		break;
+
+	case CSISExpression::EPrimTypeString:
+		{
+		const CSISString& pS = aExpression.String();
+		if(pS.WasteOfSpace())
+			{
+			throw std::runtime_error("null pointer");
+			}
+		
+		iTempResult = ExpressionResult(pS.GetString());
+		}
+		break;
+
+	case CSISExpression::EPrimTypeVariable:
+		{
+        const int variableId = aExpression.IntValue();
+        const int variableValue = iExpEnv.Variable( variableId );
+        //
+		iTempResult = ExpressionResult( variableValue );
+		break;
+		}
+
+	case CSISExpression::EPrimTypeOption:
+		{
+		iExpressionDepth=0;
+		std::string error = "SIS File contains user options\n";
+		std::string x;
+        //
+		throw InvalidSis(Ucs2ToUtf8(iExpEnv.GetPackageName(),x), error, SIS_NOT_SUPPORTED);
+		}
+
+	case CSISExpression::EPrimTypeNumber:
+		iTempResult = ExpressionResult(aExpression.IntValue());
+		break;
+
+	default:
+		{
+		iExpressionDepth=0;
+		std::string error = "SIS File contains unknown expression\n";
+		std::string x;
+        //
+		throw InvalidSis(Ucs2ToUtf8(iExpEnv.GetPackageName(),x), error, SIS_NOT_SUPPORTED);
+		}
+    	}
+
+	--iExpressionDepth;
+	return iTempResult;
+    }
+
+
+// ExpressionEnvironment
+
+ExpressionEnvironment::ExpressionEnvironment( const SisFile& aSisFile,
+                                              const SisRegistry& aSisRegistry,
+                                              RomManager& aRomManager,
+                                              ConfigManager& aConfigManager,
+                                              const std::wstring& aCDrive ) 
+:   iSisFile(aSisFile), iSisRegistry(aSisRegistry), 
+    iRomManager( aRomManager ), iConfigManager( aConfigManager ),
+    iCDrive(aCDrive)
+    {
+    }
+
+
+const std::wstring ExpressionEnvironment::GetPackageName()
+    {
+	return iSisFile.GetPackageName();
+    }
+
+
+bool ExpressionEnvironment::FindFile( const std::wstring& aFileName )
+    {
+    bool fileExists = false;
+
+    // Fixed up file name
+    std::wstring fileName( aFileName );
+   
+    // If the file is in ROM then we really need to check with the ROM
+    // manager. If its on C:, then we'll have to resort to using
+    // the specified 'C' drive and hope that it helps.
+    //
+    // Filename length must be at least 3 characters, i.e. drive + semicolon + backslash + filename
+    //
+    if ( fileName.length() >= 1 && fileName[ 0 ] == L'\\' )
+        {
+        // Bad file name?
+  		LWARN(L"\tAssuming file path \'" << aFileName << L"\' refers to Z:" );
+        fileName = L"Z:" + fileName;
+        }
+
+    // Require for invalid file exception (also helps with debugging)
+    std::string narrowFileName;
+    narrowFileName = Ucs2ToUtf8( fileName, narrowFileName );
+
+    // Now continue with file, assuming we've fixed up the path or then
+    // have enough characters to process
+    bool startsWithDrive = StringUtils::StartsWithDrive( fileName );
+    if  ( startsWithDrive )
+        {
+        const wchar_t drive = fileName[ 0 ];
+        //
+        switch( drive )
+            {
+        case L'z':
+        case L'Z':
+            {
+            // File is in 'ROM' so use ROM manager
+            fileExists = iRomManager.RomFileExists( fileName );
+            break;
+            }
+        case L'c':
+        case L'C':
+        case L'!':
+        default:
+            {
+            // File is on 'C:' so merge with C-drive specification and
+            // use native FileExists() check
+            ConvertToLocalPath( fileName, iCDrive );
+
+            // For debugging
+            narrowFileName = Ucs2ToUtf8( fileName, narrowFileName );
+
+            fileExists = FileExists( fileName );
+            break;
+            }
+            }
+        }
+    else
+        {
+		std::string error = "corrupt SIS file: bad \'EXISTS' filename: \'" + narrowFileName + "\'";
+		throw InvalidSis( "", error, INVALID_SIS );
+        }
+    //
+    std::ostringstream stream;
+    stream << "\tIF EXISTS(\'" << narrowFileName << "\') => " << fileExists;
+    std::string msg = stream.str();
+    std::wstring finalMessage = Utf8ToUcs2( msg );
+    LINFO( finalMessage );
+    //
+    return fileExists;
+    }
+
+
+TUint32 ExpressionEnvironment::ApplicationProperty(TUint32 aPackageUid, TUint32 aKey)
+    {
+	// First of all, check in this package
+	if (aPackageUid == iSisFile.GetPackageUid())
+	    {
+		const CSISProperties::SISPropertyArray& props = iSisFile.GetProperties()->Properties(); 
+		for(int i = 0; i < props.size(); ++i)
+			{
+			if (props[i].Key() == aKey)
+				{
+				return props[i].Value();
+				}
+			}
+	    }
+
+	// Then check the registry
+	const SisRegistryObject& aObj = iSisRegistry.GetRegistryObject(aPackageUid);
+	const std::vector<SisRegistryProperty*>& props = aObj.GetProperties();
+	for (std::vector<SisRegistryProperty*>::const_iterator curr1 = props.begin(); curr1 != props.end(); ++curr1)
+		{
+		if ((*curr1)->GetKey() == aKey)
+			{
+			return (*curr1)->GetValue();
+			}
+		}
+
+	// No property
+	return 0;
+    }
+
+
+int ExpressionEnvironment::Variable( int aVariableId )
+    {
+    int result = 0;
+
+    // For debugging
+    std::string attributeName = ConfigManager::AttributeNameById( aVariableId );
+
+    // See if the config manager has an over-ride for this property.
+    // If so, we'll use that value in preference to any other.
+    const bool attributeMappingExists = iConfigManager.ValueExists( (TUint32) aVariableId );
+    if ( attributeMappingExists )
+        {
+        result = iConfigManager.ValueById( (TUint32) aVariableId );
+        
+		// verify whether the language input code is within the supported list in SIS
+		// if not select first langauge in SIS file
+		if (aVariableId == KVariableLanguage)
+			{
+			if (!iSisFile.IsSupportedLanguage((TUint32)result))
+				{
+				int firstLanguage = iSisFile.GetLanguage(); // get the first language
+				std::ostringstream stream;
+				stream << "Input language " << result << " is not supported by SIS file. Using first language " <<firstLanguage;
+				std::string msg = stream.str();
+				std::wstring finalMessage = Utf8ToUcs2( msg );
+				LWARN( finalMessage );	
+				result = firstLanguage;
+				}
+			}
+        std::ostringstream stream;
+        stream << "\tIF " << attributeName << " ... where [" << attributeName << " = " << result << "]";
+        std::string msg = stream.str();
+        std::wstring finalMessage = Utf8ToUcs2( msg );
+        LINFO( finalMessage );
+        }
+	else if ( aVariableId == KVariableLanguage )
+    	{
+		LWARN(L"Disregarding language selection. Using ELangEnglish");
+		result = 1;
+    	}
+    else
+        {
+        std::string packageName;
+        packageName = Ucs2ToUtf8( GetPackageName(), packageName );
+        //
+		std::string error = "SIS File contains HAL attributes\n";
+		throw InvalidSis( packageName, error, SIS_NOT_SUPPORTED );
+        }
+    //
+    return result;
+    }
+
+
+bool ExpressionEnvironment::Package(TUint32 aKey)
+    {
+	return iSisRegistry.IsInstalled(aKey);
+    }
+
+
+bool ExpressionEnvironment::PackageVersion(const std::wstring& aArgsString)
+	{
+	// Create a copy of the argument string to be used when parsing
+	std::wstring parseString(aArgsString);
+
+	// *** Parse 'Package UID' argument ***
+	std::wstring packageUidStr;
+	if(!CSISExpression::ExtractNextToken(parseString,packageUidStr))
+		{
+		return false;
+		}
+	
+	// Package UID format checking
+	packageUidStr[1] = tolower(packageUidStr[1]);
+	if(packageUidStr.find(L"0x") != 0 || packageUidStr.length() != 10)
+		{
+		return false;
+		}
+	
+	// Check and convert the wstring to a TUint32
+	TUint32 packageUid;
+	if(!CSISExpression::IsHexadecimal(packageUidStr.substr(2),packageUid))
+		{
+		return false;
+		}
+
+
+	// *** Parse 'Relational Operator' argument ***
+	std::wstring relationOpStr;
+	if(!CSISExpression::ExtractNextToken(parseString,relationOpStr))
+		{
+		return false;
+		}
+
+
+	// *** Parse 'Major Version Component' argument ***
+	std::wstring vMajorStr;
+	if(!CSISExpression::ExtractNextToken(parseString,vMajorStr))
+		{
+		return false;
+		}
+
+	// Check and convert the wstring to an TInt
+	TInt vMajor;
+	if(!CSISExpression::IsDecimal(vMajorStr, vMajor))
+		{
+		return false;
+		}
+
+
+	// *** Parse 'Minor Version Component' argument ***
+	std::wstring vMinorStr;
+	if(!CSISExpression::ExtractNextToken(parseString,vMinorStr))
+		{
+		return false;
+		}
+
+	// Check and convert the wstring to an TInt
+	TInt vMinor;
+	if(!CSISExpression::IsDecimal(vMinorStr, vMinor))
+		{
+		return false;
+		}
+
+
+	// *** Parse 'Build Version Component' argument ***
+	std::wstring vBuildStr = parseString;
+
+	// Check and convert the wstring to an TInt
+	TInt vBuild;
+	if(!CSISExpression::IsDecimal(vBuildStr, vBuild))
+		{
+		return false;
+		}
+	
+	Version argsVersion(vMajor,vMinor,vBuild);
+
+	// Check that the version component values lie within the valid range
+	if(!argsVersion.IsValid())
+		{
+		return false;
+		}
+
+	// Then check the registry
+	if(iSisRegistry.IsInstalled(packageUid))
+		{
+		const SisRegistryObject& pkgRegEntry = iSisRegistry.GetRegistryObject(packageUid);
+		Version registryVersion = pkgRegEntry.GetVersion();
+
+		// Compare the package version retrieved from the SIS Registry against the version
+		// specified in the PKG condition
+		if(relationOpStr == L"ET") 
+			{// Equal To 
+			return registryVersion == argsVersion;
+			}
+		else if(relationOpStr == L"LT")
+			{// Less Than
+			return registryVersion < argsVersion;
+			}
+		else if(relationOpStr == L"LE") 
+			{// Less Than Or Equal To
+			return registryVersion <= argsVersion;
+			}
+		else if(relationOpStr == L"GT")
+			{// Greater Than
+			return registryVersion > argsVersion;
+			}
+		else if(relationOpStr == L"GE") 
+			{// Greater Than Or Equal To
+			return registryVersion >= argsVersion;
+			}
+		else if(relationOpStr == L"NE")
+			{// Not Equal
+			return registryVersion != argsVersion;
+			}
+		else 
+			{
+			// If the operator is not recognised, return false
+			return false;
+			}
+		}
+	else
+		{
+		// Package UID has not been found within the SIS Registry
+		return false;
+		}
+	}
+
+bool ExpressionEnvironment::DeviceLanguage(const std::wstring& aArgsString)
+	{
+	TInt langID = 0;
+	if(!CSISExpression::IsDecimal(aArgsString, langID))
+		{
+		return false;
+		}
+	std::vector<TInt>  devSuppLang = iConfigManager.GetDeviceSupportedLanguages();		
+ 	std::vector<int>::const_iterator end = devSuppLang.end();
+	for (std::vector<int>::const_iterator curr = devSuppLang.begin(); curr != end; ++curr)
+		{
+			 if ( *curr == langID )
+				 {
+				 iConfigManager.AddMatchingSupportedLanguages(langID);
+				 return true;
+				 }
+			 else
+				 {
+				  TLanguagePath equivalentLang;
+				  Utils::GetEquivalentLanguageList((CSISLanguage::TLanguage)(*curr),equivalentLang);
+				  for ( TInt i=0; i < KMaxDowngradeLanguages; i++)
+					  {
+					  if ( equivalentLang[i] != CSISLanguage::ELangNone )
+						  {
+						  if (equivalentLang[i] == langID )
+							 {
+							 iConfigManager.AddMatchingSupportedLanguages(langID);
+							 return true;
+							 }
+						  }
+					  else
+						  {
+						  break;
+						  }
+					  }
+				 }
+		}
+	return false;
+	}
+