mirror of https://github.com/tongzx/nt5src
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
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;
|
|
}
|