Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

2148 lines
57 KiB

//******************************************************************************
//
// ANALYSER.CPP
//
// Copyright (C) 1996-1999 Microsoft Corporation
//
//******************************************************************************
#include "precomp.h"
#include "pragmas.h"
#include "analyser.h"
#include <stack>
#include <strutils.h>
#include <objpath.h>
#include <fastval.h>
#include <genutils.h>
#include <datetimeparser.h>
#include "CWbemTime.h"
#include <wstlallc.h>
CClassInfoArray::CClassInfoArray()
: m_bLimited( FALSE )
{
m_pClasses = new CUniquePointerArray<CClassInformation>;
if ( m_pClasses )
{
m_pClasses->RemoveAll();
}
}
CClassInfoArray::~CClassInfoArray()
{
delete m_pClasses;
}
bool CClassInfoArray::operator=(CClassInfoArray& Other)
{
SetLimited(Other.IsLimited());
m_pClasses->RemoveAll();
for(int i = 0; i < Other.m_pClasses->GetSize(); i++)
{
CClassInformation* pInfo = new CClassInformation(*(*Other.m_pClasses)[i]);
if(pInfo == NULL)
return false;
m_pClasses->Add(pInfo);
}
return true;
}
bool CClassInfoArray::SetOne(LPCWSTR wszClass, BOOL bIncludeChildren)
{
CClassInformation* pNewInfo = _new CClassInformation;
if(pNewInfo == NULL)
return false;
pNewInfo->m_wszClassName = CloneWstr(wszClass);
if(pNewInfo->m_wszClassName == NULL)
{
delete pNewInfo;
return false;
}
pNewInfo->m_bIncludeChildren = bIncludeChildren;
m_pClasses->RemoveAll();
m_pClasses->Add(pNewInfo);
SetLimited(TRUE);
return true;
}
HRESULT CQueryAnalyser::GetPossibleInstanceClasses(
QL_LEVEL_1_RPN_EXPRESSION* pExpr,
CClassInfoArray*& paInfos)
{
// Organize a stack of classinfo arrays
// ====================================
std::stack<CClassInfoArray*,std::deque<CClassInfoArray*,wbem_allocator<CClassInfoArray*> > > InfoStack;
HRESULT hres = WBEM_S_NO_ERROR;
// "Evaluate" the query
// ====================
if(pExpr->nNumTokens == 0)
{
// Empty query --- no information
// ==============================
paInfos = _new CClassInfoArray;
if(paInfos == NULL)
return WBEM_E_OUT_OF_MEMORY;
paInfos->SetLimited(FALSE);
return WBEM_S_NO_ERROR;
}
for(int i = 0; i < pExpr->nNumTokens; i++)
{
QL_LEVEL_1_TOKEN& Token = pExpr->pArrayOfTokens[i];
CClassInfoArray* paNew = _new CClassInfoArray;
if(paNew == NULL)
return WBEM_E_OUT_OF_MEMORY;
CClassInfoArray* paFirst;
CClassInfoArray* paSecond;
switch(Token.nTokenType)
{
case QL1_OP_EXPRESSION:
hres = GetInstanceClasses(Token, *paNew);
InfoStack.push(paNew);
break;
case QL1_AND:
if(InfoStack.size() < 2)
{
hres = WBEM_E_CRITICAL_ERROR;
break;
}
paFirst = InfoStack.top(); InfoStack.pop();
paSecond = InfoStack.top(); InfoStack.pop();
hres = AndPossibleClassArrays(paFirst, paSecond, paNew);
InfoStack.push(paNew);
delete paFirst;
delete paSecond;
break;
case QL1_OR:
if(InfoStack.size() < 2)
{
hres = WBEM_E_CRITICAL_ERROR;
break;
}
paFirst = InfoStack.top(); InfoStack.pop();
paSecond = InfoStack.top(); InfoStack.pop();
hres = OrPossibleClassArrays(paFirst, paSecond, paNew);
InfoStack.push(paNew);
delete paFirst;
delete paSecond;
break;
case QL1_NOT:
if(InfoStack.size() < 1)
{
hres = WBEM_E_CRITICAL_ERROR;
break;
}
paFirst = InfoStack.top(); InfoStack.pop();
hres = NegatePossibleClassArray(paFirst, paNew);
InfoStack.push(paNew);
delete paFirst;
break;
default:
hres = WBEM_E_CRITICAL_ERROR;
delete paNew;
}
if(FAILED(hres))
{
// An error occurred, break out of the loop
// ========================================
break;
}
}
if(SUCCEEDED(hres) && InfoStack.size() != 1)
{
hres = WBEM_E_CRITICAL_ERROR;
}
if(FAILED(hres))
{
// An error occurred. Clear the stack
// ==================================
while(!InfoStack.empty())
{
delete InfoStack.top();
InfoStack.pop();
}
return hres;
}
// All is good
// ===========
paInfos = InfoStack.top();
return S_OK;
}
HRESULT CQueryAnalyser::AndPossibleClassArrays(IN CClassInfoArray* paFirst,
IN CClassInfoArray* paSecond,
OUT CClassInfoArray* paNew)
{
// For now, simply pick one
// ========================
if(paFirst->IsLimited())
*paNew = *paFirst;
else
*paNew = *paSecond;
return WBEM_S_NO_ERROR;
}
HRESULT CQueryAnalyser::OrPossibleClassArrays(IN CClassInfoArray* paFirst,
IN CClassInfoArray* paSecond,
OUT CClassInfoArray* paNew)
{
// Append them together
// ====================
paNew->Clear();
if(paFirst->IsLimited() && paSecond->IsLimited())
{
paNew->SetLimited(TRUE);
for(int i = 0; i < paFirst->GetNumClasses(); i++)
{
CClassInformation* pInfo =
new CClassInformation(*paFirst->GetClass(i));
if(pInfo == NULL)
return WBEM_E_OUT_OF_MEMORY;
if(!paNew->AddClass(pInfo))
{
delete pInfo;
return WBEM_E_OUT_OF_MEMORY;
}
}
for(i = 0; i < paSecond->GetNumClasses(); i++)
{
CClassInformation* pInfo =
new CClassInformation(*paSecond->GetClass(i));
if(pInfo == NULL)
return WBEM_E_OUT_OF_MEMORY;
if(!paNew->AddClass(pInfo))
{
delete pInfo;
return WBEM_E_OUT_OF_MEMORY;
}
}
}
return WBEM_S_NO_ERROR;
}
HRESULT CQueryAnalyser::NegatePossibleClassArray(IN CClassInfoArray* paOrig,
OUT CClassInfoArray* paNew)
{
// No information!
// ===============
paNew->Clear();
return WBEM_S_NO_ERROR;
}
HRESULT CQueryAnalyser::GetDefiniteInstanceClasses(
QL_LEVEL_1_RPN_EXPRESSION* pExpr,
CClassInfoArray*& paInfos)
{
// Organize a stack of classinfo arrays
// ====================================
std::stack<CClassInfoArray*, std::deque<CClassInfoArray*,wbem_allocator<CClassInfoArray*> > > InfoStack;
HRESULT hres = WBEM_S_NO_ERROR;
// "Evaluate" the query
// ====================
if(pExpr->nNumTokens == 0)
{
// Empty query --- no information
// ==============================
paInfos = _new CClassInfoArray;
if(paInfos == NULL)
return WBEM_E_OUT_OF_MEMORY;
paInfos->SetLimited(FALSE);
return WBEM_S_NO_ERROR;
}
for(int i = 0; i < pExpr->nNumTokens; i++)
{
QL_LEVEL_1_TOKEN& Token = pExpr->pArrayOfTokens[i];
CClassInfoArray* paNew = _new CClassInfoArray;
if(paNew == NULL)
return WBEM_E_OUT_OF_MEMORY;
CClassInfoArray* paFirst;
CClassInfoArray* paSecond;
switch(Token.nTokenType)
{
case QL1_OP_EXPRESSION:
hres = GetInstanceClasses(Token, *paNew);
InfoStack.push(paNew);
break;
case QL1_AND:
if(InfoStack.size() < 2)
{
hres = WBEM_E_CRITICAL_ERROR;
break;
}
paFirst = InfoStack.top(); InfoStack.pop();
paSecond = InfoStack.top(); InfoStack.pop();
hres = AndDefiniteClassArrays(paFirst, paSecond, paNew);
InfoStack.push(paNew);
delete paFirst;
delete paSecond;
break;
case QL1_OR:
if(InfoStack.size() < 2)
{
hres = WBEM_E_CRITICAL_ERROR;
break;
}
paFirst = InfoStack.top(); InfoStack.pop();
paSecond = InfoStack.top(); InfoStack.pop();
hres = OrDefiniteClassArrays(paFirst, paSecond, paNew);
InfoStack.push(paNew);
delete paFirst;
delete paSecond;
break;
case QL1_NOT:
if(InfoStack.size() < 1)
{
hres = WBEM_E_CRITICAL_ERROR;
break;
}
paFirst = InfoStack.top(); InfoStack.pop();
hres = NegateDefiniteClassArray(paFirst, paNew);
InfoStack.push(paNew);
delete paFirst;
break;
default:
hres = WBEM_E_CRITICAL_ERROR;
delete paNew;
}
if(FAILED(hres))
{
// An error occurred, break out of the loop
// ========================================
break;
}
}
if(SUCCEEDED(hres) && InfoStack.size() != 1)
{
hres = WBEM_E_CRITICAL_ERROR;
}
if(FAILED(hres))
{
// An error occurred. Clear the stack
// ==================================
while(!InfoStack.empty())
{
delete InfoStack.top();
InfoStack.pop();
}
return hres;
}
// All is good
// ===========
paInfos = InfoStack.top();
return S_OK;
}
HRESULT CQueryAnalyser::AndDefiniteClassArrays(IN CClassInfoArray* paFirst,
IN CClassInfoArray* paSecond,
OUT CClassInfoArray* paNew)
{
// Nothing is definite if both conditions have to hold
// ===================================================
paNew->Clear();
paNew->SetLimited(TRUE);
return WBEM_S_NO_ERROR;
}
HRESULT CQueryAnalyser::OrDefiniteClassArrays(IN CClassInfoArray* paFirst,
IN CClassInfoArray* paSecond,
OUT CClassInfoArray* paNew)
{
// Append them together
// ====================
paNew->Clear();
if(paFirst->IsLimited() && paSecond->IsLimited())
{
paNew->SetLimited(TRUE);
for(int i = 0; i < paFirst->GetNumClasses(); i++)
{
CClassInformation* pInfo =
new CClassInformation(*paFirst->GetClass(i));
if(pInfo == NULL)
return WBEM_E_OUT_OF_MEMORY;
if(!paNew->AddClass(pInfo))
{
delete pInfo;
return WBEM_E_OUT_OF_MEMORY;
}
}
for(i = 0; i < paSecond->GetNumClasses(); i++)
{
CClassInformation* pInfo =
new CClassInformation(*paSecond->GetClass(i));
if(pInfo == NULL)
return WBEM_E_OUT_OF_MEMORY;
if(!paNew->AddClass(pInfo))
{
delete pInfo;
return WBEM_E_OUT_OF_MEMORY;
}
}
}
return WBEM_S_NO_ERROR;
}
HRESULT CQueryAnalyser::NegateDefiniteClassArray(IN CClassInfoArray* paOrig,
OUT CClassInfoArray* paNew)
{
// No information
// ==============
paNew->Clear();
paNew->SetLimited(TRUE);
return WBEM_S_NO_ERROR;
}
HRESULT CQueryAnalyser::GetInstanceClasses(QL_LEVEL_1_TOKEN& Token,
CClassInfoArray& aInfos)
{
// Preset aInfos to the "no information" value
// ===========================================
aInfos.Clear();
// See if this token talks about TargetInstance or PreviousInstance
// ================================================================
if(Token.PropertyName.GetNumElements() < 1)
return WBEM_S_NO_ERROR;
LPCWSTR wszPrimaryName = Token.PropertyName.GetStringAt(0);
if(wszPrimaryName == NULL ||
(_wcsicmp(wszPrimaryName, TARGET_INSTANCE_PROPNAME) &&
_wcsicmp(wszPrimaryName, PREVIOUS_INSTANCE_PROPNAME))
)
{
// This token is irrelevant
// =========================
return WBEM_S_NO_ERROR;
}
// TargetInstance or PreviousInstance is found
// ===========================================
if(Token.PropertyName.GetNumElements() == 1)
{
// It's "TargetInstance <op> <const>" : look for ISA
// =================================================
if(Token.nOperator == QL1_OPERATOR_ISA &&
V_VT(&Token.vConstValue) == VT_BSTR)
{
// Of this class; children included
// ================================
if(!aInfos.SetOne(V_BSTR(&Token.vConstValue), TRUE))
return WBEM_E_OUT_OF_MEMORY;
}
else
{
// No information
// ==============
}
return WBEM_S_NO_ERROR;
}
if(Token.PropertyName.GetNumElements() > 2)
{
// X.Y.Z --- too deep to be useful
// ===============================
return WBEM_S_NO_ERROR;
}
// It's "TargetInstance.X <op> <const>" : look for __CLASS
// =======================================================
LPCWSTR wszSecondaryName = Token.PropertyName.GetStringAt(1);
if(wszSecondaryName == NULL || _wcsicmp(wszSecondaryName, L"__CLASS"))
{
// Not __CLASS --- not useful
// ==========================
return WBEM_S_NO_ERROR;
}
else
{
// __CLASS --- check that the operator is =
// ========================================
if(Token.nOperator == QL1_OPERATOR_EQUALS &&
V_VT(&Token.vConstValue) == VT_BSTR)
{
// Of this class -- children not included
// ======================================
if(!aInfos.SetOne(V_BSTR(&Token.vConstValue), FALSE))
return WBEM_E_OUT_OF_MEMORY;
}
return WBEM_S_NO_ERROR;
}
}
HRESULT CQueryAnalyser::GetNecessaryQueryForProperty(
IN QL_LEVEL_1_RPN_EXPRESSION* pExpr,
IN CPropertyName& PropName,
DELETE_ME QL_LEVEL_1_RPN_EXPRESSION*& pNewExpr)
{
pNewExpr = NULL;
// Class name and selected properties are ignored; we look at tokens only
// ======================================================================
std::stack<QL_LEVEL_1_RPN_EXPRESSION*, std::deque<QL_LEVEL_1_RPN_EXPRESSION*,wbem_allocator<QL_LEVEL_1_RPN_EXPRESSION*> > > ExprStack;
HRESULT hres = WBEM_S_NO_ERROR;
// "Evaluate" the query
// ====================
if(pExpr->nNumTokens == 0)
{
// Empty query --- no information
// ==============================
pNewExpr = _new QL_LEVEL_1_RPN_EXPRESSION;
if(pNewExpr == NULL)
return WBEM_E_OUT_OF_MEMORY;
return WBEM_S_NO_ERROR;
}
for(int i = 0; i < pExpr->nNumTokens; i++)
{
QL_LEVEL_1_TOKEN& Token = pExpr->pArrayOfTokens[i];
QL_LEVEL_1_RPN_EXPRESSION* pNew = _new QL_LEVEL_1_RPN_EXPRESSION;
if(pNew == NULL)
return WBEM_E_OUT_OF_MEMORY;
QL_LEVEL_1_RPN_EXPRESSION* pFirst;
QL_LEVEL_1_RPN_EXPRESSION* pSecond;
switch(Token.nTokenType)
{
case QL1_OP_EXPRESSION:
if(IsTokenAboutProperty(Token, PropName))
{
pNew->AddToken(Token);
}
ExprStack.push(pNew);
break;
case QL1_AND:
if(ExprStack.size() < 2)
{
hres = WBEM_E_CRITICAL_ERROR;
break;
}
pFirst = ExprStack.top(); ExprStack.pop();
pSecond = ExprStack.top(); ExprStack.pop();
hres = AndQueryExpressions(pFirst, pSecond, pNew);
ExprStack.push(pNew);
delete pFirst;
delete pSecond;
break;
case QL1_OR:
if(ExprStack.size() < 2)
{
hres = WBEM_E_CRITICAL_ERROR;
break;
}
pFirst = ExprStack.top(); ExprStack.pop();
pSecond = ExprStack.top(); ExprStack.pop();
hres = OrQueryExpressions(pFirst, pSecond, pNew);
ExprStack.push(pNew);
delete pFirst;
delete pSecond;
break;
case QL1_NOT:
if(ExprStack.size() < 1)
{
hres = WBEM_E_CRITICAL_ERROR;
break;
}
pFirst = ExprStack.top(); ExprStack.pop();
// No information
ExprStack.push(pNew);
delete pFirst;
break;
default:
hres = WBEM_E_CRITICAL_ERROR;
delete pNew;
}
if(FAILED(hres))
{
// An error occurred, break out of the loop
// ========================================
break;
}
}
if(SUCCEEDED(hres) && ExprStack.size() != 1)
{
hres = WBEM_E_CRITICAL_ERROR;
}
if(FAILED(hres))
{
// An error occurred. Clear the stack
// ==================================
while(!ExprStack.empty())
{
delete ExprStack.top();
ExprStack.pop();
}
return hres;
}
// All is good
// ===========
pNewExpr = ExprStack.top();
return S_OK;
}
BOOL CQueryAnalyser::IsTokenAboutProperty(
IN QL_LEVEL_1_TOKEN& Token,
IN CPropertyName& PropName)
{
CPropertyName& TokenPropName = Token.PropertyName;
if(PropName.GetNumElements() != TokenPropName.GetNumElements())
return FALSE;
for(int i = 0; i < PropName.GetNumElements(); i++)
{
LPCWSTR wszPropElement = PropName.GetStringAt(i);
LPCWSTR wszTokenElement = TokenPropName.GetStringAt(i);
if(wszPropElement == NULL || wszTokenElement == NULL)
return FALSE;
if(_wcsicmp(wszPropElement, wszTokenElement))
return FALSE;
}
return TRUE;
}
void CQueryAnalyser::AppendQueryExpression(
IN QL_LEVEL_1_RPN_EXPRESSION* pDest,
IN QL_LEVEL_1_RPN_EXPRESSION* pSource)
{
for(int i = 0; i < pSource->nNumTokens; i++)
{
pDest->AddToken(pSource->pArrayOfTokens[i]);
}
}
HRESULT CQueryAnalyser::AndQueryExpressions(
IN QL_LEVEL_1_RPN_EXPRESSION* pFirst,
IN QL_LEVEL_1_RPN_EXPRESSION* pSecond,
OUT QL_LEVEL_1_RPN_EXPRESSION* pNew)
{
// If either one is NULL (false), the result is NULL
// =================================================
if(pFirst == NULL || pSecond == NULL)
return WBEM_S_FALSE;
// If either one is empty, take the other
// ======================================
if(pFirst->nNumTokens == 0)
{
AppendQueryExpression(pNew, pSecond);
return WBEM_S_NO_ERROR;
}
if(pSecond->nNumTokens == 0)
{
AppendQueryExpression(pNew, pFirst);
return WBEM_S_NO_ERROR;
}
// Both are there --- and together
// ===============================
AppendQueryExpression(pNew, pFirst);
AppendQueryExpression(pNew, pSecond);
QL_LEVEL_1_TOKEN Token;
Token.nTokenType = QL1_AND;
pNew->AddToken(Token);
return WBEM_S_NO_ERROR;
}
HRESULT CQueryAnalyser::OrQueryExpressions(
IN QL_LEVEL_1_RPN_EXPRESSION* pFirst,
IN QL_LEVEL_1_RPN_EXPRESSION* pSecond,
OUT QL_LEVEL_1_RPN_EXPRESSION* pNew)
{
// If both are NULL (false) so is the result
// =========================================
if(pFirst == NULL && pSecond == NULL)
return WBEM_S_FALSE;
// If one is NULL (false) return the other
// =======================================
if(pFirst == NULL)
{
AppendQueryExpression(pNew, pSecond);
return WBEM_S_NO_ERROR;
}
if(pSecond == NULL)
{
AppendQueryExpression(pNew, pFirst);
return WBEM_S_NO_ERROR;
}
// If either one is empty, so is the result
// ========================================
if(pFirst->nNumTokens == 0 || pSecond->nNumTokens == 0)
{
return WBEM_S_NO_ERROR;
}
// Both are there --- or together
// ==============================
AppendQueryExpression(pNew, pFirst);
AppendQueryExpression(pNew, pSecond);
QL_LEVEL_1_TOKEN Token;
Token.nTokenType = QL1_OR;
pNew->AddToken(Token);
return WBEM_S_NO_ERROR;
}
HRESULT CQueryAnalyser::GetPropertiesThatMustDiffer(
IN QL_LEVEL_1_RPN_EXPRESSION* pExpr,
IN CClassInformation& Info,
CWStringArray& awsProperties)
{
HRESULT hres = WBEM_S_NO_ERROR;
//
// "Evaluate" the query, looking for
// PreviousInstance.Prop != TargetInstance.Prop expressions
//
awsProperties.Empty();
std::stack<CWStringArray*, std::deque<CWStringArray*,wbem_allocator<CWStringArray*> > > PropArrayStack;
for(int i = 0; i < pExpr->nNumTokens; i++)
{
QL_LEVEL_1_TOKEN& Token = pExpr->pArrayOfTokens[i];
CWStringArray* pNew = NULL;
CWStringArray* pFirst = NULL;
CWStringArray* pSecond = NULL;
switch(Token.nTokenType)
{
case QL1_OP_EXPRESSION:
//
// Check if this token conforms to the
// PreviousInstance.Prop != TargetInstance.Prop format
//
if(Token.m_bPropComp &&
(Token.nOperator == QL1_OPERATOR_NOTEQUALS ||
Token.nOperator == QL1_OPERATOR_LESS ||
Token.nOperator == QL1_OPERATOR_GREATER) &&
Token.PropertyName.GetNumElements() == 2 &&
Token.PropertyName2.GetNumElements() == 2)
{
//
// Make sure that one of them is talking about TargetInstance,
// and another about PreviousInstance.
//
bool bRightForm = false;
if(!wbem_wcsicmp(Token.PropertyName.GetStringAt(0),
L"TargetInstance") &&
!wbem_wcsicmp(Token.PropertyName2.GetStringAt(0),
L"PreviousInstance"))
{
bRightForm = true;
}
if(!wbem_wcsicmp(Token.PropertyName.GetStringAt(0),
L"PreviousInstance") &&
!wbem_wcsicmp(Token.PropertyName2.GetStringAt(0),
L"TargetInstance"))
{
bRightForm = true;
}
if(bRightForm)
{
pNew = new CWStringArray;
if(pNew == NULL)
return WBEM_E_OUT_OF_MEMORY;
pNew->Add(Token.PropertyName.GetStringAt(1));
}
}
PropArrayStack.push(pNew);
break;
case QL1_AND:
if(PropArrayStack.size() < 2)
{
hres = WBEM_E_CRITICAL_ERROR;
break;
}
pFirst = PropArrayStack.top(); PropArrayStack.pop();
pSecond = PropArrayStack.top(); PropArrayStack.pop();
//
// If either one of them is non-NULL, take either --- since every
// array means "no unless one of these properties is different",
// adding them together is at least as good as having one
//
if(pFirst)
{
pNew = pFirst;
delete pSecond;
}
else
pNew = pSecond;
PropArrayStack.push(pNew);
break;
case QL1_OR:
if(PropArrayStack.size() < 2)
{
hres = WBEM_E_CRITICAL_ERROR;
break;
}
pFirst = PropArrayStack.top(); PropArrayStack.pop();
pSecond = PropArrayStack.top(); PropArrayStack.pop();
//
// Concatenate them --- since every
// array means "no unless one of these properties is different",
// oring them together means "no unless one of the properties in
// either list is different". If one is NULL, though, then we know
// nothing
//
if(pFirst && pSecond)
{
pNew = new CWStringArray;
if(pNew == NULL)
return WBEM_E_OUT_OF_MEMORY;
CWStringArray::Union(*pFirst, *pSecond, *pNew);
}
PropArrayStack.push(pNew);
delete pFirst;
delete pSecond;
break;
case QL1_NOT:
if(PropArrayStack.size() < 1)
{
hres = WBEM_E_CRITICAL_ERROR;
break;
}
pFirst = PropArrayStack.top(); PropArrayStack.pop();
// No information
PropArrayStack.push(pNew);
delete pFirst;
break;
default:
hres = WBEM_E_CRITICAL_ERROR;
delete pNew;
}
if(FAILED(hres))
{
// An error occurred, break out of the loop
// ========================================
break;
}
}
if( SUCCEEDED(hres))
{
if( PropArrayStack.size() > 0 && PropArrayStack.top() )
awsProperties = *PropArrayStack.top();
else
return WBEM_S_FALSE;
}
while(!PropArrayStack.empty())
{
delete PropArrayStack.top();
PropArrayStack.pop();
}
return hres;
}
HRESULT CQueryAnalyser::GetLimitingQueryForInstanceClass(
IN QL_LEVEL_1_RPN_EXPRESSION* pExpr,
IN CClassInformation& Info,
OUT DELETE_ME LPWSTR& wszQuery)
{
HRESULT hres;
//
// "Evaluate" the query, looking for keys and other properties that do not
// change over the life time of an instance (marked as [fixed]). The idea
// here is that if an instance creation/deletion/modification subscription
// is issue and we need to poll, we can only utilize the parts of the WHERE
// clause that talk about the properties that cannot change during the life
// of an instance. Otherwise, we will not be able to tell if an instance
// changed or was created or deleted (when it walks in or out of our polling
// results.
//
// The way we know that a property is such is if it is marked as [key], or
// if it is marked as [fixed] --- the designation by the schema creator that
// the property never changes.
//
//
// Construct an array of all those property names
//
_IWmiObject* pClass = NULL;
hres = Info.m_pClass->QueryInterface(IID__IWmiObject, (void**)&pClass);
if(FAILED(hres))
return WBEM_E_CRITICAL_ERROR;
CReleaseMe rm1(pClass);
CWStringArray awsFixed;
hres = pClass->BeginEnumeration(0);
if(FAILED(hres))
return hres;
BSTR strPropName = NULL;
while((hres = pClass->Next(0, &strPropName, NULL, NULL, NULL)) == S_OK)
{
CSysFreeMe sfm(strPropName);
//
// Check qualifiers
//
DWORD dwSize;
hres = pClass->GetPropQual(strPropName, L"key", 0, 0, NULL,
NULL, &dwSize, NULL);
if(SUCCEEDED(hres) || hres == WBEM_E_BUFFER_TOO_SMALL)
{
awsFixed.Add(strPropName);
}
else if(hres != WBEM_E_NOT_FOUND)
{
return hres;
}
hres = pClass->GetPropQual(strPropName, L"fixed", 0, 0, NULL,
NULL, &dwSize, NULL);
if(SUCCEEDED(hres) || hres == WBEM_E_BUFFER_TOO_SMALL)
{
awsFixed.Add(strPropName);
}
else if(hres != WBEM_E_NOT_FOUND)
{
return hres;
}
}
pClass->EndEnumeration();
if(FAILED(hres))
return hres;
//
// Now "evaluate" the query
//
std::stack<QL_LEVEL_1_RPN_EXPRESSION*, std::deque<QL_LEVEL_1_RPN_EXPRESSION*,wbem_allocator<QL_LEVEL_1_RPN_EXPRESSION*> > > ExprStack;
for(int i = 0; i < pExpr->nNumTokens; i++)
{
QL_LEVEL_1_TOKEN& Token = pExpr->pArrayOfTokens[i];
QL_LEVEL_1_RPN_EXPRESSION* pNew = _new QL_LEVEL_1_RPN_EXPRESSION;
if(pNew == NULL)
return WBEM_E_OUT_OF_MEMORY;
QL_LEVEL_1_RPN_EXPRESSION* pFirst;
QL_LEVEL_1_RPN_EXPRESSION* pSecond;
switch(Token.nTokenType)
{
case QL1_OP_EXPRESSION:
if(Token.PropertyName.GetNumElements() > 1 &&
awsFixed.FindStr(Token.PropertyName.GetStringAt(1),
CWStringArray::no_case) != CWStringArray::not_found)
{
//
// This token is about a fixed property --- we can keep it
//
QL_LEVEL_1_TOKEN NewToken = Token;
NewToken.PropertyName.Empty();
NewToken.PropertyName.AddElement(
Token.PropertyName.GetStringAt(1));
pNew->AddToken(NewToken);
}
ExprStack.push(pNew);
break;
case QL1_AND:
if(ExprStack.size() < 2)
{
hres = WBEM_E_CRITICAL_ERROR;
break;
}
pFirst = ExprStack.top(); ExprStack.pop();
pSecond = ExprStack.top(); ExprStack.pop();
hres = AndQueryExpressions(pFirst, pSecond, pNew);
ExprStack.push(pNew);
delete pFirst;
delete pSecond;
break;
case QL1_OR:
if(ExprStack.size() < 2)
{
hres = WBEM_E_CRITICAL_ERROR;
break;
}
pFirst = ExprStack.top(); ExprStack.pop();
pSecond = ExprStack.top(); ExprStack.pop();
hres = OrQueryExpressions(pFirst, pSecond, pNew);
ExprStack.push(pNew);
delete pFirst;
delete pSecond;
break;
case QL1_NOT:
if(ExprStack.size() < 1)
{
hres = WBEM_E_CRITICAL_ERROR;
break;
}
pFirst = ExprStack.top(); ExprStack.pop();
// No information
ExprStack.push(pNew);
delete pFirst;
break;
default:
hres = WBEM_E_CRITICAL_ERROR;
delete pNew;
}
if(FAILED(hres))
{
// An error occurred, break out of the loop
// ========================================
break;
}
}
if(FAILED(hres))
{
//
// An error occurred. Clear the stack
//
while(!ExprStack.empty())
{
delete ExprStack.top();
ExprStack.pop();
}
return hres;
}
QL_LEVEL_1_RPN_EXPRESSION* pNewExpr = NULL;
if(ExprStack.size() != 0)
{
pNewExpr = ExprStack.top();
}
else
{
pNewExpr = new QL_LEVEL_1_RPN_EXPRESSION;
if(pNewExpr == NULL)
return WBEM_E_OUT_OF_MEMORY;
}
CDeleteMe<QL_LEVEL_1_RPN_EXPRESSION> dm1(pNewExpr);
//
// Figure out the list of property names
//
bool bMayLimit;
if(pExpr->bStar)
{
bMayLimit = false;
}
else if(wbem_wcsicmp(pExpr->bsClassName, L"__InstanceCreationEvent") &&
wbem_wcsicmp(pExpr->bsClassName, L"__InstanceDeletionEvent"))
{
//
// Instance modification events are included. That means we need
// to get enough properties from the provider to be able to compare
// instances for changes. Check if this list is smaller than
// everything
//
CWStringArray awsProperties;
hres = GetPropertiesThatMustDiffer(pExpr, Info, awsProperties);
if(hres == S_OK)
{
//
// Got our list --- add it to the properties to get
//
for(int i = 0; i < awsProperties.Size(); i++)
{
CPropertyName NewProp;
NewProp.AddElement(awsProperties[i]);
pNewExpr->AddProperty(NewProp);
}
bMayLimit = true;
}
else
bMayLimit = false;
}
else
{
//
// No * in select and no modification events asked for --- limit
//
bMayLimit = true;
}
if(bMayLimit)
{
//
// Add RELPATH and DERIVATION, for without them filtering is hard
//
CPropertyName NewProp;
NewProp.AddElement(L"__RELPATH");
pNewExpr->AddProperty(NewProp);
NewProp.Empty();
NewProp.AddElement(L"__DERIVATION");
pNewExpr->AddProperty(NewProp);
//
// Add all the proeperties from the select clause, with
// TargetInstance and PreviousInstance removed
//
for(int i = 0; i < pExpr->nNumberOfProperties; i++)
{
CPropertyName& Prop = pExpr->pRequestedPropertyNames[i];
if(Prop.GetNumElements() > 1)
{
//
// Embedded object property --- add it to the list
//
CPropertyName LocalProp;
LocalProp.AddElement(Prop.GetStringAt(1));
pNewExpr->AddProperty(LocalProp);
}
}
//
// Add all the properties from the where clause, on both sides of
// the comparison
//
for(i = 0; i < pExpr->nNumTokens; i++)
{
QL_LEVEL_1_TOKEN& Token = pExpr->pArrayOfTokens[i];
CPropertyName& Prop = Token.PropertyName;
if(Prop.GetNumElements() > 1)
{
//
// Embedded object property --- add it to the list
//
CPropertyName LocalProp;
LocalProp.AddElement(Prop.GetStringAt(1));
pNewExpr->AddProperty(LocalProp);
}
if(Token.m_bPropComp)
{
CPropertyName& Prop2 = Token.PropertyName2;
if(Prop2.GetNumElements() > 1)
{
//
// Embedded object property --- add it to the list
//
CPropertyName LocalProp;
LocalProp.AddElement(Prop2.GetStringAt(1));
pNewExpr->AddProperty(LocalProp);
}
}
}
}
else
{
//
// May not limit the set of properties to ask for
//
pNewExpr->bStar = TRUE;
}
//
// Set the class name
//
pNewExpr->SetClassName(Info.m_wszClassName);
//
// Produce the text
//
wszQuery = pNewExpr->GetText();
if(wszQuery == NULL)
return WBEM_E_OUT_OF_MEMORY;
return WBEM_S_NO_ERROR;
}
BOOL CQueryAnalyser::CompareRequestedToProvided(
CClassInfoArray& aRequestedInstanceClasses,
CClassInfoArray& aProvidedInstanceClasses)
{
if(!aRequestedInstanceClasses.IsLimited() ||
!aProvidedInstanceClasses.IsLimited())
{
// Provided provides all or client wants all --- they intersect.
// =============================================================
return TRUE;
}
for(int nReqIndex = 0;
nReqIndex < aRequestedInstanceClasses.GetNumClasses();
nReqIndex++)
{
CClassInformation* pRequestedClass =
aRequestedInstanceClasses.GetClass(nReqIndex);
LPWSTR wszRequestedClass = pRequestedClass->m_wszClassName;
for(int nProvIndex = 0;
nProvIndex < aProvidedInstanceClasses.GetNumClasses();
nProvIndex++)
{
// Check if this provided class is derived from the requested one
// ==============================================================
CClassInformation* pProvClass =
aProvidedInstanceClasses.GetClass(nProvIndex);
if(pProvClass->m_pClass != NULL &&
(pProvClass->m_pClass->InheritsFrom(pRequestedClass->m_wszClassName) == S_OK ||
pRequestedClass->m_pClass->InheritsFrom(pProvClass->m_wszClassName) == S_OK)
)
{
return TRUE;
}
}
}
return FALSE;
}
HRESULT CQueryAnalyser::NegateQueryExpression(
IN QL_LEVEL_1_RPN_EXPRESSION* pExpr,
OUT QL_LEVEL_1_RPN_EXPRESSION* pNewExpr)
{
if(pExpr == NULL)
{
// pNewExpr is empty --- true
return WBEM_S_NO_ERROR;
}
if(pExpr->nNumTokens == 0)
{
return WBEM_S_FALSE;
}
AppendQueryExpression(pNewExpr, pExpr);
QL_LEVEL_1_TOKEN Token;
Token.nTokenType = QL1_NOT;
pNewExpr->AddToken(Token);
return WBEM_S_NO_ERROR;
}
HRESULT CQueryAnalyser::SimplifyQueryForChild(
IN QL_LEVEL_1_RPN_EXPRESSION* pExpr,
LPCWSTR wszClassName, IWbemClassObject* pClass,
CContextMetaData* pMeta,
DELETE_ME QL_LEVEL_1_RPN_EXPRESSION*& pNewExpr)
{
pNewExpr = NULL;
std::stack<QL_LEVEL_1_RPN_EXPRESSION*, std::deque<QL_LEVEL_1_RPN_EXPRESSION*,wbem_allocator<QL_LEVEL_1_RPN_EXPRESSION*> > > ExprStack;
HRESULT hres = WBEM_S_NO_ERROR;
// "Evaluate" the query
// ====================
if(pExpr->nNumTokens == 0)
{
// Empty query --- no information
// ==============================
pNewExpr = _new QL_LEVEL_1_RPN_EXPRESSION;
if(pNewExpr == NULL)
return WBEM_E_OUT_OF_MEMORY;
return WBEM_S_NO_ERROR;
}
for(int i = 0; i < pExpr->nNumTokens; i++)
{
QL_LEVEL_1_TOKEN Token = pExpr->pArrayOfTokens[i];
QL_LEVEL_1_RPN_EXPRESSION* pNew = _new QL_LEVEL_1_RPN_EXPRESSION;
if(pNew == NULL)
return WBEM_E_OUT_OF_MEMORY;
QL_LEVEL_1_RPN_EXPRESSION* pFirst;
QL_LEVEL_1_RPN_EXPRESSION* pSecond;
int nDisposition;
switch(Token.nTokenType)
{
case QL1_OP_EXPRESSION:
nDisposition = SimplifyTokenForChild(Token, wszClassName, pClass,
pMeta);
if(nDisposition == e_Keep)
{
pNew->AddToken(Token);
}
else if(nDisposition == e_True)
{
}
else if(nDisposition == e_False)
{
delete pNew;
pNew = NULL;
}
else
{
// the whole thing is invalid
hres = WBEM_E_INVALID_QUERY;
delete pNew;
break;
}
ExprStack.push(pNew);
break;
case QL1_AND:
if(ExprStack.size() < 2)
{
hres = WBEM_E_CRITICAL_ERROR;
break;
}
pFirst = ExprStack.top(); ExprStack.pop();
pSecond = ExprStack.top(); ExprStack.pop();
hres = AndQueryExpressions(pFirst, pSecond, pNew);
if(hres != S_OK)
{
delete pNew;
pNew = NULL;
}
ExprStack.push(pNew);
delete pFirst;
delete pSecond;
break;
case QL1_OR:
if(ExprStack.size() < 2)
{
hres = WBEM_E_CRITICAL_ERROR;
break;
}
pFirst = ExprStack.top(); ExprStack.pop();
pSecond = ExprStack.top(); ExprStack.pop();
hres = OrQueryExpressions(pFirst, pSecond, pNew);
if(hres != S_OK)
{
delete pNew;
pNew = NULL;
}
ExprStack.push(pNew);
delete pFirst;
delete pSecond;
break;
case QL1_NOT:
if(ExprStack.size() < 1)
{
hres = WBEM_E_CRITICAL_ERROR;
break;
}
pFirst = ExprStack.top(); ExprStack.pop();
hres = NegateQueryExpression(pFirst, pNew);
if(hres != S_OK)
{
delete pNew;
pNew = NULL;
}
ExprStack.push(pNew);
delete pFirst;
break;
default:
hres = WBEM_E_CRITICAL_ERROR;
delete pNew;
}
if(FAILED(hres))
{
// An error occurred, break out of the loop
// ========================================
break;
}
}
if(SUCCEEDED(hres) && ExprStack.size() != 1)
{
hres = WBEM_E_CRITICAL_ERROR;
}
if(FAILED(hres))
{
// An error occurred. Clear the stack
// ==================================
while(!ExprStack.empty())
{
delete ExprStack.top();
ExprStack.pop();
}
return hres;
}
// All is good
// ===========
pNewExpr = ExprStack.top();
return S_OK;
}
int CQueryAnalyser::SimplifyTokenForChild(QL_LEVEL_1_TOKEN& Token,
LPCWSTR wszClassName, IWbemClassObject* pClass,
CContextMetaData* pMeta)
{
HRESULT hres;
//
// Check if the main property exists
//
CIMTYPE ct;
hres = pClass->Get((LPWSTR)Token.PropertyName.GetStringAt(0), 0, NULL,
&ct, NULL);
if(FAILED(hres))
{
return e_Invalid;
}
//
// Check if it is complex
//
if(Token.PropertyName.GetNumElements() > 1 && ct != CIM_OBJECT)
return e_Invalid;
//
// Check if it's an array
//
if(ct & CIM_FLAG_ARRAY)
return e_Invalid;
//
// If a CIM DateTime type, normalize it to have a zero UTC offset. Helps
// providers to cope.
//
if (ct == CIM_DATETIME && Token.m_bPropComp == FALSE && V_VT(&Token.vConstValue) == VT_BSTR)
{
BSTR strSource = V_BSTR(&Token.vConstValue);
if (strSource && wcslen(strSource))
{
BSTR strAdjusted = 0;
BOOL bRes = NormalizeCimDateTime(strSource, &strAdjusted);
if (bRes)
{
SysFreeString(strSource);
V_BSTR(&Token.vConstValue) = strAdjusted;
}
}
}
//
// Check operator validity for this type
//
//
// Ensure that only valid operators are applied to boolean props.
//
if(ct == CIM_BOOLEAN && (Token.nOperator != QL_LEVEL_1_TOKEN::OP_EQUAL &&
Token.nOperator != QL_LEVEL_1_TOKEN::OP_NOT_EQUAL))
return e_Invalid;
//
// Ensure that only valid operators are applied to reference props.
//
if(ct == CIM_REFERENCE && (Token.nOperator != QL_LEVEL_1_TOKEN::OP_EQUAL &&
Token.nOperator != QL_LEVEL_1_TOKEN::OP_NOT_EQUAL))
return e_Invalid;
if(Token.m_bPropComp)
{
//
// Check if the other property exists
//
CIMTYPE ct2;
hres = pClass->Get((LPWSTR)Token.PropertyName2.GetStringAt(0), 0, NULL,
&ct2, NULL);
if(FAILED(hres))
{
return e_Invalid;
}
//
// Check if it is complex
//
if(Token.PropertyName2.GetNumElements() > 1 && ct2 != CIM_OBJECT)
return e_Invalid;
//
// Check if it's an array
//
if(ct2 & CIM_FLAG_ARRAY)
return e_Invalid;
//
// Nothing else to say about prop-to-ptop
//
return e_Keep;
}
//
// Check if the value is NULL
//
if(V_VT(&Token.vConstValue) == VT_NULL)
{
if(Token.nOperator != QL1_OPERATOR_EQUALS &&
Token.nOperator != QL1_OPERATOR_NOTEQUALS)
{
return e_Invalid;
}
else
{
return e_Keep;
}
}
if(ct == CIM_OBJECT)
return e_Keep;
// For boolean props ensure that only 1 or 0 or (-1, 0xFFFF [VARIANT_TRUE])
// are used as numeric tests.
// ========================================================================
if (ct == CIM_BOOLEAN && V_VT(&Token.vConstValue) == VT_I4)
{
int n = V_I4(&Token.vConstValue);
if (n != 0 && n != 1 && n != -1 && n != 0xFFFF)
return e_Invalid;
}
//
// If the constant is a real and the target is an integer, then fail the
// query
//
if((V_VT(&Token.vConstValue) == VT_R8 || V_VT(&Token.vConstValue) == VT_R4 ) &&
(ct == CIM_CHAR16 || ct == CIM_UINT8 || ct == CIM_SINT8 ||
ct == CIM_UINT16 || ct == CIM_SINT16 || ct == CIM_UINT32 ||
ct == CIM_SINT32 || ct == CIM_UINT64 || ct == CIM_SINT64))
return e_Invalid;
// Convert the constant to the right type
// ======================================
if(ct == CIM_CHAR16 && V_VT(&Token.vConstValue) == VT_BSTR)
{
BSTR str = V_BSTR(&Token.vConstValue);
if(wcslen(str) != 1)
return e_Invalid;
return e_Keep;
}
VARTYPE vt = CType::GetVARTYPE(ct);
if(ct == CIM_UINT32)
vt = CIM_STRING;
if(FAILED(VariantChangeType(&Token.vConstValue, &Token.vConstValue, 0, vt)))
{
return e_Invalid;
}
// Verify ranges
// =============
__int64 i64;
unsigned __int64 ui64;
switch(ct)
{
case CIM_UINT8:
break;
case CIM_SINT8:
if(V_I2(&Token.vConstValue) < -128 || V_I2(&Token.vConstValue) > 127)
return e_Invalid;
break;
case CIM_UINT16:
if(V_I4(&Token.vConstValue) < 0 || V_I4(&Token.vConstValue) >= 1<<16)
return e_Invalid;
break;
case CIM_SINT16:
break;
case CIM_SINT32:
break;
case CIM_UINT32:
if(!ReadI64(V_BSTR(&Token.vConstValue), i64))
return e_Invalid;
if(i64 < 0 || i64 >= (__int64)1 << 32)
return e_Invalid;
break;
case CIM_UINT64:
if(!ReadUI64(V_BSTR(&Token.vConstValue), ui64))
return e_Invalid;
break;
case CIM_SINT64:
if(!ReadI64(V_BSTR(&Token.vConstValue), i64))
return e_Invalid;
break;
case CIM_REAL32:
case CIM_REAL64:
break;
case CIM_STRING:
break;
case CIM_DATETIME:
if(!ValidateSQLDateTime(V_BSTR(&Token.vConstValue)))
return e_Invalid;
case CIM_REFERENCE:
break;
}
// Check if it is a reference
// ==========================
if(ct != CIM_REFERENCE)
return e_Keep;
// Reference. Parse the path in the value
// ======================================
if(V_VT(&Token.vConstValue) != VT_BSTR)
return e_Keep;
CObjectPathParser Parser;
ParsedObjectPath* pOutput = NULL;
int nRes = Parser.Parse(V_BSTR(&Token.vConstValue), &pOutput);
if(nRes != CObjectPathParser::NoError)
return e_Invalid;
WString wsPathClassName = pOutput->m_pClass;
BOOL bInstance = (pOutput->m_bSingletonObj || pOutput->m_dwNumKeys != 0);
// TBD: analyse the path for validity
delete pOutput;
hres = CanPointToClass(pClass, (LPWSTR)Token.PropertyName.GetStringAt(0),
wsPathClassName, pMeta);
if(FAILED(hres))
return e_Invalid;
else if(hres == WBEM_S_NO_ERROR)
return e_Keep;
else
{
// Equality can never be achieved. The token is either always true,
// or always false, depending on the operator
if(Token.nOperator == QL1_OPERATOR_EQUALS)
return e_False;
else
return e_True;
}
}
BOOL CQueryAnalyser::ValidateSQLDateTime(LPCWSTR wszDateTime)
{
#ifndef UNICODE
char* szBuffer = new char[wcslen(wszDateTime)*4+1];
if(szBuffer == NULL)
return FALSE;
sprintf(szBuffer, "%S", wszDateTime);
CDateTimeParser dtParser(szBuffer);
delete [] szBuffer;
#else
CDateTimeParser dtParser(wszDateTime);
#endif
if(!dtParser.IsValidDateTime())
return FALSE;
WCHAR wszDMTF[26];
dtParser.FillDMTF(wszDMTF);
CWbemTime wt;
if(!wt.SetDMTF(wszDMTF))
return FALSE;
return TRUE;
}
HRESULT CQueryAnalyser::CanPointToClass(IWbemClassObject* pRefClass,
LPCWSTR wszPropName, LPCWSTR wszTargetClassName,
CContextMetaData* pMeta)
{
// Check if the reference is typed
// ===============================
IWbemQualifierSet* pSet;
if(FAILED(pRefClass->GetPropertyQualifierSet((LPWSTR)wszPropName, &pSet)))
{
return WBEM_E_INVALID_PROPERTY;
}
VARIANT v;
HRESULT hres;
hres = pSet->Get(L"cimtype", 0, &v, NULL);
pSet->Release();
if(FAILED(hres) || V_VT(&v) != VT_BSTR)
return WBEM_E_INVALID_PROPERTY;
CClearMe cm(&v);
if(wbem_wcsicmp(V_BSTR(&v), L"ref") == 0)
return WBEM_S_NO_ERROR; // can point to anything
WString wsPropClassName = V_BSTR(&v) + 4;
// Reference is strongly typed.
// ============================
if(!_wcsicmp(wsPropClassName, wszTargetClassName))
return WBEM_S_NO_ERROR;
// Retrieve class def
// ==================
_IWmiObject* pPropClass = NULL;
hres = pMeta->GetClass(wsPropClassName, &pPropClass);
if(FAILED(hres))
return hres;
CReleaseMe rm1((IWbemClassObject*)pPropClass);
// Make sure that the class in the reference is related to our cimtype
// ===================================================================
if(pPropClass->InheritsFrom((LPWSTR)wszTargetClassName) != S_OK)
{
// Get the class in the path to see if it inherits from us
// =======================================================
_IWmiObject* pPathClass = NULL;
hres = pMeta->GetClass(wszTargetClassName, &pPathClass);
if(FAILED(hres))
return hres;
hres = pPathClass->InheritsFrom(wsPropClassName);
pPathClass->Release();
if(hres != S_OK)
{
return WBEM_S_FALSE;
}
}
return WBEM_S_NO_ERROR;
}
HRESULT CQueryAnalyser::GetNecessaryQueryForClass(
IN QL_LEVEL_1_RPN_EXPRESSION* pExpr,
IWbemClassObject* pClass,
CWStringArray& awsOverriden,
DELETE_ME QL_LEVEL_1_RPN_EXPRESSION*& pNewExpr)
{
pNewExpr = NULL;
// Class name and selected properties are ignored; we look at tokens only
// ======================================================================
std::stack<QL_LEVEL_1_RPN_EXPRESSION*, std::deque<QL_LEVEL_1_RPN_EXPRESSION*,wbem_allocator<QL_LEVEL_1_RPN_EXPRESSION*> > > ExprStack;
HRESULT hres = WBEM_S_NO_ERROR;
// "Evaluate" the query
// ====================
for(int i = 0; i < pExpr->nNumTokens; i++)
{
QL_LEVEL_1_TOKEN& Token = pExpr->pArrayOfTokens[i];
QL_LEVEL_1_RPN_EXPRESSION* pNew = _new QL_LEVEL_1_RPN_EXPRESSION;
if(pNew == NULL)
return WBEM_E_OUT_OF_MEMORY;
QL_LEVEL_1_RPN_EXPRESSION* pFirst;
QL_LEVEL_1_RPN_EXPRESSION* pSecond;
switch(Token.nTokenType)
{
case QL1_OP_EXPRESSION:
if(IsTokenAboutClass(Token, pClass, awsOverriden))
{
pNew->AddToken(Token);
}
ExprStack.push(pNew);
break;
case QL1_AND:
if(ExprStack.size() < 2)
{
hres = WBEM_E_CRITICAL_ERROR;
break;
}
pFirst = ExprStack.top(); ExprStack.pop();
pSecond = ExprStack.top(); ExprStack.pop();
hres = AndQueryExpressions(pFirst, pSecond, pNew);
ExprStack.push(pNew);
delete pFirst;
delete pSecond;
break;
case QL1_OR:
if(ExprStack.size() < 2)
{
hres = WBEM_E_CRITICAL_ERROR;
break;
}
pFirst = ExprStack.top(); ExprStack.pop();
pSecond = ExprStack.top(); ExprStack.pop();
hres = OrQueryExpressions(pFirst, pSecond, pNew);
ExprStack.push(pNew);
delete pFirst;
delete pSecond;
break;
case QL1_NOT:
if(ExprStack.size() < 1)
{
hres = WBEM_E_CRITICAL_ERROR;
break;
}
pFirst = ExprStack.top(); ExprStack.pop();
// No information
ExprStack.push(pNew);
delete pFirst;
break;
default:
hres = WBEM_E_CRITICAL_ERROR;
delete pNew;
}
if(FAILED(hres))
{
// An error occurred, break out of the loop
// ========================================
break;
}
}
if(FAILED(hres))
{
// An error occurred. Clear the stack
// ==================================
while(!ExprStack.empty())
{
delete ExprStack.top();
ExprStack.pop();
}
return hres;
}
if(pExpr->nNumTokens == 0)
{
// Empty query --- stays empty
pNewExpr = _new QL_LEVEL_1_RPN_EXPRESSION;
if(pNewExpr == NULL)
return WBEM_E_OUT_OF_MEMORY;
}
else if(ExprStack.size() != 1)
{
// internal error
return WBEM_E_CRITICAL_ERROR;
}
else
{
// All is good
// ===========
pNewExpr = ExprStack.top();
}
//
// Copy the class name
//
VARIANT vName;
hres = pClass->Get(L"__CLASS", 0, &vName, NULL, NULL);
if(FAILED(hres))
return WBEM_E_CRITICAL_ERROR;
pNewExpr->bsClassName = V_BSTR(&vName);
// Variant intentionally not cleared
//
// Copy all the properties in the select clause except for irrelevant ones
//
pNewExpr->bStar = pExpr->bStar;
if(!pNewExpr->bStar)
{
delete [] pNewExpr->pRequestedPropertyNames;
pNewExpr->nCurPropSize = pExpr->nCurPropSize+1;
pNewExpr->pRequestedPropertyNames =
new CPropertyName[pNewExpr->nCurPropSize];
if(pNewExpr->pRequestedPropertyNames == NULL)
{
delete pNewExpr;
return WBEM_E_OUT_OF_MEMORY;
}
//
// Add __RELPATH, as we always need that!
//
pNewExpr->pRequestedPropertyNames[0].AddElement(L"__RELPATH");
pNewExpr->nNumberOfProperties = 1;
for(int i = 0; i < pExpr->nNumberOfProperties; i++)
{
//
// Check if the property exists in the class
//
CIMTYPE ct;
hres = pClass->Get(pExpr->pRequestedPropertyNames[i].GetStringAt(0),
0, NULL, &ct, NULL);
if(SUCCEEDED(hres))
{
//
// Add it to the list
//
pNewExpr->pRequestedPropertyNames[
pNewExpr->nNumberOfProperties++] =
pExpr->pRequestedPropertyNames[i];
}
}
}
return S_OK;
}
BOOL CQueryAnalyser::IsTokenAboutClass(QL_LEVEL_1_TOKEN& Token,
IWbemClassObject* pClass,
CWStringArray& awsOverriden)
{
//
// Check if the property being compared is in our class
// and not overriden
//
if(!IsPropertyInClass(Token.PropertyName, pClass, awsOverriden))
return FALSE;
//
// If comparing to another property, check if that one is
// likewise good
//
if(Token.m_bPropComp &&
!IsPropertyInClass(Token.PropertyName2, pClass, awsOverriden))
return FALSE;
return TRUE;
}
BOOL CQueryAnalyser::IsPropertyInClass(CPropertyName& Prop,
IWbemClassObject* pClass,
CWStringArray& awsOverriden)
{
//
// Check if the property exists in the class
//
CIMTYPE ct;
HRESULT hres = pClass->Get(Prop.GetStringAt(0), 0, NULL, &ct, NULL);
if(FAILED(hres))
return FALSE;
//
// Check if the property is overriden by any of our children
//
if(awsOverriden.FindStr(Prop.GetStringAt(0), CWStringArray::no_case) >= 0)
return FALSE;
return TRUE;
}