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.
1066 lines
32 KiB
1066 lines
32 KiB
/*++
|
|
|
|
Copyright (C) 1996-1999 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
DUMBNODE.CPP
|
|
|
|
Abstract:
|
|
|
|
WBEM Dumb Node
|
|
|
|
History:
|
|
|
|
--*/
|
|
|
|
#include "precomp.h"
|
|
#include <stdio.h>
|
|
#pragma warning(disable:4786)
|
|
#include <wbemcomn.h>
|
|
#include <genutils.h>
|
|
#include "dumbnode.h"
|
|
#include "CWbemTime.h"
|
|
#include "datetimeparser.h"
|
|
|
|
#define DUMBNODE_FALSE_BRANCH_INDEX 0
|
|
#define DUMBNODE_TRUE_BRANCH_INDEX 1
|
|
|
|
|
|
CDumbNode::CDumbNode(QL_LEVEL_1_TOKEN& Token)
|
|
: m_Token(Token)
|
|
{
|
|
//
|
|
// Add the branches for TRUE and FALSE
|
|
//
|
|
|
|
if(m_apBranches.Add(CValueNode::GetStandardFalse()) < 0)
|
|
throw CX_MemoryException();
|
|
|
|
CEvalNode* pNode = CValueNode::GetStandardTrue();
|
|
if(pNode == NULL)
|
|
throw CX_MemoryException();
|
|
|
|
if(m_apBranches.Add( pNode ) < 0)
|
|
{
|
|
delete pNode;
|
|
throw CX_MemoryException();
|
|
}
|
|
}
|
|
|
|
HRESULT CDumbNode::Validate(IWbemClassObject* pClass)
|
|
{
|
|
HRESULT hres;
|
|
|
|
//
|
|
// Check if the property is even in the class
|
|
//
|
|
|
|
CIMTYPE ct;
|
|
hres = pClass->Get(m_Token.PropertyName.GetStringAt(0), 0, NULL, &ct, NULL);
|
|
if(FAILED(hres))
|
|
return WBEM_E_INVALID_PROPERTY;
|
|
|
|
if(m_Token.m_bPropComp)
|
|
{
|
|
hres = pClass->Get(m_Token.PropertyName2.GetStringAt(0), 0, NULL, &ct,
|
|
NULL);
|
|
if(FAILED(hres))
|
|
return WBEM_E_INVALID_PROPERTY;
|
|
}
|
|
|
|
if(ct == CIM_REFERENCE)
|
|
{
|
|
//
|
|
// Make sure that the operator is = or <>
|
|
//
|
|
|
|
if(m_Token.nOperator != QL_LEVEL_1_TOKEN::OP_EQUAL &&
|
|
m_Token.nOperator != QL_LEVEL_1_TOKEN::OP_NOT_EQUAL)
|
|
{
|
|
return WBEM_E_INVALID_OPERATOR;
|
|
}
|
|
|
|
//
|
|
// Make sure the path is parsable
|
|
//
|
|
|
|
if(!m_Token.m_bPropComp)
|
|
{
|
|
if(V_VT(&m_Token.vConstValue) != VT_BSTR)
|
|
{
|
|
if(V_VT(&m_Token.vConstValue) != VT_NULL)
|
|
return WBEM_E_TYPE_MISMATCH;
|
|
}
|
|
else
|
|
{
|
|
LPWSTR wszNormal = NormalizePath(V_BSTR(&m_Token.vConstValue));
|
|
if(wszNormal == NULL)
|
|
return WBEM_E_INVALID_OBJECT_PATH;
|
|
else
|
|
delete [] wszNormal;
|
|
}
|
|
}
|
|
}
|
|
else if(ct == CIM_DATETIME)
|
|
{
|
|
//
|
|
// If comparing to a constant, make sure the constant is a date
|
|
//
|
|
|
|
if(!m_Token.m_bPropComp)
|
|
{
|
|
if(V_VT(&m_Token.vConstValue) != VT_BSTR)
|
|
{
|
|
if(V_VT(&m_Token.vConstValue) != VT_NULL)
|
|
return WBEM_E_TYPE_MISMATCH;
|
|
}
|
|
else
|
|
{
|
|
BSTR strConstVal = V_BSTR(&m_Token.vConstValue);
|
|
#ifdef UNICODE
|
|
CDateTimeParser dtConst(strConstVal);
|
|
#else
|
|
size_t cchBuffer = wcslen(strConstVal) * 4 + 1;
|
|
char* szBuffer = new char[cchBuffer];
|
|
if(szBuffer == NULL)
|
|
return WBEM_E_OUT_OF_MEMORY;
|
|
StringCchPrintf(szBuffer, cchBuffer, "%S", strConstVal);
|
|
|
|
CDateTimeParser dtConst(szBuffer);
|
|
|
|
delete [] szBuffer;
|
|
#endif
|
|
|
|
if(!dtConst.IsValidDateTime())
|
|
return WBEM_E_VALUE_OUT_OF_RANGE;
|
|
}
|
|
}
|
|
}
|
|
|
|
return WBEM_S_NO_ERROR;
|
|
}
|
|
|
|
CDumbNode::CDumbNode(const CDumbNode& Other, BOOL bChildren)
|
|
: CBranchingNode(Other, bChildren), m_Token(Other.m_Token)
|
|
{
|
|
}
|
|
|
|
/* virtual */ long CDumbNode::GetSubType()
|
|
{
|
|
return EVAL_NODE_TYPE_DUMB;
|
|
}
|
|
|
|
CDumbNode::~CDumbNode()
|
|
{
|
|
}
|
|
|
|
int CDumbNode::ComparePrecedence(CBranchingNode* pOther)
|
|
{
|
|
//
|
|
// Dumb nodes can only be merged if they are identical. So, there
|
|
// precedence (level) is the same as theie comparison order
|
|
//
|
|
|
|
return SubCompare(pOther);
|
|
}
|
|
|
|
int CDumbNode::SubCompare(CEvalNode* pOther)
|
|
{
|
|
CDumbNode* pDumbOther = (CDumbNode*)pOther;
|
|
|
|
//
|
|
// The easiest way to compare two tokens is to compare their textual
|
|
// representations. Optimizations paths for the future abound.
|
|
//
|
|
|
|
LPWSTR wszThisText = m_Token.GetText();
|
|
if ( wszThisText == NULL )
|
|
throw CX_MemoryException();
|
|
|
|
CVectorDeleteMe<WCHAR> vdm1(wszThisText);
|
|
|
|
LPWSTR wszOtherText = pDumbOther->m_Token.GetText();
|
|
if ( wszOtherText == NULL )
|
|
throw CX_MemoryException();
|
|
|
|
CVectorDeleteMe<WCHAR> vdm2(wszOtherText);
|
|
|
|
return wbem_wcsicmp(wszThisText, wszOtherText);
|
|
}
|
|
|
|
HRESULT CDumbNode::OptimizeSelf()
|
|
{
|
|
//
|
|
// Nothing to optimize for now. Optimizations abound.
|
|
//
|
|
|
|
return WBEM_S_NO_ERROR;
|
|
}
|
|
|
|
#define INVALID 2
|
|
|
|
int CDumbNode::EvaluateToken(
|
|
IWbemPropertySource *pTestObj,
|
|
QL_LEVEL_1_TOKEN& Tok
|
|
)
|
|
{
|
|
VARIANT PropVal, CompVal;
|
|
VariantInit(&PropVal);
|
|
VariantInit(&CompVal);
|
|
CClearMe clv(&PropVal);
|
|
CClearMe clv2(&CompVal);
|
|
|
|
WBEM_WSTR wszCimType, wszCimType2;
|
|
HRESULT hRes;
|
|
|
|
// Special-case 'this'
|
|
// ===================
|
|
|
|
if(Tok.PropertyName.GetNumElements() == 1 &&
|
|
!wbem_wcsicmp(Tok.PropertyName.GetStringAt(0), L"__THIS"))
|
|
{
|
|
wszCimType = WbemStringCopy(L"object");
|
|
V_VT(&PropVal) = VT_UNKNOWN;
|
|
hRes = pTestObj->QueryInterface(IID_IWbemClassObject,
|
|
(void**)&V_UNKNOWN(&PropVal));
|
|
}
|
|
else
|
|
{
|
|
hRes = pTestObj->GetPropertyValue(&Tok.PropertyName, 0,
|
|
&wszCimType, &PropVal);
|
|
}
|
|
if (FAILED(hRes))
|
|
return FALSE;
|
|
CMemFreeMe wsf(wszCimType);
|
|
|
|
// Handle a property-to-property comparison,
|
|
|
|
if (Tok.m_bPropComp != FALSE)
|
|
{
|
|
hRes = pTestObj->GetPropertyValue(&Tok.PropertyName2, 0,
|
|
&wszCimType2, &CompVal);
|
|
if (FAILED(hRes))
|
|
return FALSE;
|
|
}
|
|
else
|
|
{
|
|
if(FAILED(VariantCopy(&CompVal, &Tok.vConstValue)))
|
|
return INVALID;
|
|
}
|
|
|
|
// Handle NULLs
|
|
// ============
|
|
|
|
if(V_VT(&PropVal) == VT_NULL)
|
|
{
|
|
if(V_VT(&CompVal) == VT_NULL)
|
|
{
|
|
if(Tok.nOperator == QL_LEVEL_1_TOKEN::OP_EQUAL ||
|
|
Tok.nOperator == QL_LEVEL_1_TOKEN::OP_LIKE )
|
|
return TRUE;
|
|
else if(Tok.nOperator == QL_LEVEL_1_TOKEN::OP_NOT_EQUAL ||
|
|
Tok.nOperator == QL_LEVEL_1_TOKEN::OP_UNLIKE )
|
|
return FALSE;
|
|
else
|
|
return INVALID;
|
|
}
|
|
else
|
|
{
|
|
if(Tok.nOperator == QL_LEVEL_1_TOKEN::OP_EQUAL ||
|
|
Tok.nOperator == QL_LEVEL_1_TOKEN::OP_LIKE )
|
|
return FALSE;
|
|
else if(Tok.nOperator == QL_LEVEL_1_TOKEN::OP_NOT_EQUAL ||
|
|
Tok.nOperator == QL_LEVEL_1_TOKEN::OP_UNLIKE )
|
|
return TRUE;
|
|
else
|
|
return INVALID;
|
|
}
|
|
}
|
|
else if(V_VT(&CompVal) == VT_NULL)
|
|
{
|
|
if(Tok.nOperator == QL_LEVEL_1_TOKEN::OP_EQUAL)
|
|
return FALSE;
|
|
else if(Tok.nOperator == QL_LEVEL_1_TOKEN::OP_NOT_EQUAL)
|
|
return TRUE;
|
|
else
|
|
return INVALID;
|
|
}
|
|
|
|
// Handle references
|
|
// =================
|
|
|
|
if(wszCimType &&
|
|
wbem_wcsnicmp(wszCimType, L"ref", 3) == 0 &&
|
|
(wszCimType[3] == 0 || wszCimType[3] == L':'))
|
|
{
|
|
// This is a reference. The only operators allowed are = and !=
|
|
// ============================================================
|
|
|
|
if(V_VT(&PropVal) != VT_BSTR || V_VT(&CompVal) != VT_BSTR)
|
|
return INVALID;
|
|
|
|
LPWSTR va = CDumbNode::NormalizePath(V_BSTR(&PropVal));
|
|
LPWSTR vb = CDumbNode::NormalizePath(V_BSTR(&CompVal));
|
|
if(va == NULL || vb == NULL)
|
|
{
|
|
if(va)
|
|
delete [] va;
|
|
if(vb)
|
|
delete [] vb;
|
|
ERRORTRACE((LOG_ESS, "Invalid path %S or %S specified in an "
|
|
"association\n", V_BSTR(&PropVal), V_BSTR(&CompVal)));
|
|
return INVALID;
|
|
}
|
|
|
|
int nRet;
|
|
switch (Tok.nOperator)
|
|
{
|
|
case QL_LEVEL_1_TOKEN::OP_EQUAL:
|
|
nRet = (wbem_wcsicmp(va,vb) == 0);
|
|
break;
|
|
case QL_LEVEL_1_TOKEN::OP_NOT_EQUAL:
|
|
nRet = (wbem_wcsicmp(va, vb) != 0);
|
|
break;
|
|
default:
|
|
nRet = INVALID;
|
|
break;
|
|
}
|
|
|
|
delete [] va;
|
|
delete [] vb;
|
|
|
|
|
|
return nRet;
|
|
}
|
|
|
|
|
|
// Check if ISA is used
|
|
// ====================
|
|
|
|
if(Tok.nOperator == QL1_OPERATOR_ISA ||
|
|
Tok.nOperator == QL1_OPERATOR_ISNOTA ||
|
|
Tok.nOperator == QL1_OPERATOR_INV_ISA ||
|
|
Tok.nOperator == QL1_OPERATOR_INV_ISNOTA)
|
|
{
|
|
// Account for inversion
|
|
// =====================
|
|
|
|
VARIANT* pv1;
|
|
VARIANT* pv2;
|
|
int bNeedDerived;
|
|
|
|
if(Tok.nOperator == QL1_OPERATOR_ISA ||
|
|
Tok.nOperator == QL1_OPERATOR_ISNOTA)
|
|
{
|
|
pv2 = &CompVal;
|
|
pv1 = &PropVal;
|
|
bNeedDerived = (Tok.nOperator == QL1_OPERATOR_ISA);
|
|
}
|
|
else
|
|
{
|
|
pv1 = &CompVal;
|
|
pv2 = &PropVal;
|
|
bNeedDerived = (Tok.nOperator == QL1_OPERATOR_INV_ISA);
|
|
}
|
|
|
|
// The second argument has to be a string
|
|
// ======================================
|
|
|
|
if(V_VT(pv2) != VT_BSTR)
|
|
{
|
|
return INVALID;
|
|
}
|
|
|
|
BSTR strParentClass = V_BSTR(pv2);
|
|
|
|
// The first argument has to be an object or a string
|
|
// ==================================================
|
|
|
|
BOOL bDerived;
|
|
if(V_VT(pv1) == VT_EMBEDDED_OBJECT)
|
|
{
|
|
IWbemClassObject* pObj = (IWbemClassObject*)V_EMBEDDED_OBJECT(pv1);
|
|
bDerived = (pObj->InheritsFrom(strParentClass) == WBEM_S_NO_ERROR);
|
|
}
|
|
else if(V_VT(pv1) == VT_BSTR)
|
|
{
|
|
// TBD
|
|
// ===
|
|
|
|
return INVALID;
|
|
}
|
|
else
|
|
{
|
|
return INVALID;
|
|
}
|
|
|
|
// Now that we have bDerived, see if it matches the requirement
|
|
// ============================================================
|
|
|
|
if(bDerived == bNeedDerived)
|
|
return TRUE;
|
|
else
|
|
return FALSE;
|
|
|
|
}
|
|
else if ( Tok.nOperator == QL1_OPERATOR_LIKE ||
|
|
Tok.nOperator == QL1_OPERATOR_UNLIKE )
|
|
{
|
|
if ( Tok.m_bPropComp != FALSE )
|
|
{
|
|
return INVALID;
|
|
}
|
|
|
|
if ( FAILED(VariantChangeType( &PropVal, &PropVal, 0, VT_BSTR )) ||
|
|
V_VT(&CompVal) != VT_BSTR )
|
|
{
|
|
return INVALID;
|
|
}
|
|
|
|
try
|
|
{
|
|
CLike Like( V_BSTR(&CompVal) );
|
|
|
|
if ( Like.Match( V_BSTR(&PropVal) ) )
|
|
{
|
|
return Tok.nOperator == QL1_OPERATOR_LIKE ? TRUE : FALSE;
|
|
}
|
|
else
|
|
{
|
|
return Tok.nOperator == QL1_OPERATOR_UNLIKE ? TRUE : FALSE;
|
|
}
|
|
}
|
|
catch( CX_MemoryException )
|
|
{
|
|
return INVALID;
|
|
}
|
|
}
|
|
|
|
// Perform UINT32 workaround
|
|
// =========================
|
|
|
|
if(wszCimType && !wbem_wcsicmp(wszCimType, L"uint32") &&
|
|
V_VT(&PropVal) == VT_I4)
|
|
{
|
|
DWORD dwVal = (DWORD)V_I4(&PropVal);
|
|
WCHAR wszVal[20];
|
|
StringCchPrintfW(wszVal,20,L"%lu", dwVal);
|
|
V_VT(&PropVal) = VT_BSTR;
|
|
V_BSTR(&PropVal) = SysAllocString(wszVal);
|
|
}
|
|
|
|
if(wszCimType &&
|
|
(!wbem_wcsicmp(wszCimType, L"sint64") ||
|
|
!wbem_wcsicmp(wszCimType, L"uint64") ||
|
|
!wbem_wcsicmp(wszCimType, L"uint32")) &&
|
|
V_VT(&CompVal) != VT_NULL && V_VT(&PropVal) != VT_NULL)
|
|
{
|
|
BOOL bUnsigned = (wbem_wcsicmp(wszCimType, L"uint64") == 0);
|
|
|
|
// We have a 64-bit comparison where both sides are present.
|
|
// =========================================================
|
|
|
|
hRes = VariantChangeType(&CompVal, &CompVal, 0,
|
|
VT_BSTR);
|
|
if(FAILED(hRes))
|
|
{
|
|
return INVALID;
|
|
}
|
|
|
|
if(bUnsigned)
|
|
{
|
|
unsigned __int64 ui64Prop, ui64Const;
|
|
|
|
if(!ReadUI64(V_BSTR(&PropVal), ui64Prop))
|
|
return INVALID;
|
|
|
|
if(!ReadUI64(V_BSTR(&CompVal), ui64Const))
|
|
return INVALID;
|
|
|
|
switch (Tok.nOperator)
|
|
{
|
|
case QL_LEVEL_1_TOKEN::OP_EQUAL: return (ui64Prop == ui64Const);
|
|
case QL_LEVEL_1_TOKEN::OP_NOT_EQUAL:
|
|
return (ui64Prop != ui64Const);
|
|
case QL_LEVEL_1_TOKEN::OP_EQUALorGREATERTHAN:
|
|
return (ui64Prop >= ui64Const);
|
|
case QL_LEVEL_1_TOKEN::OP_EQUALorLESSTHAN:
|
|
return (ui64Prop <= ui64Const);
|
|
case QL_LEVEL_1_TOKEN::OP_LESSTHAN:
|
|
return (ui64Prop < ui64Const);
|
|
case QL_LEVEL_1_TOKEN::OP_GREATERTHAN:
|
|
return (ui64Prop > ui64Const);
|
|
case QL_LEVEL_1_TOKEN::OP_LIKE: return (ui64Prop == ui64Const);
|
|
}
|
|
return INVALID;
|
|
}
|
|
else
|
|
{
|
|
__int64 i64Prop, i64Const;
|
|
|
|
if(!ReadI64(V_BSTR(&PropVal), i64Prop))
|
|
return INVALID;
|
|
|
|
if(!ReadI64(V_BSTR(&CompVal), i64Const))
|
|
return INVALID;
|
|
|
|
switch (Tok.nOperator)
|
|
{
|
|
case QL_LEVEL_1_TOKEN::OP_EQUAL: return (i64Prop == i64Const);
|
|
case QL_LEVEL_1_TOKEN::OP_NOT_EQUAL:
|
|
return (i64Prop != i64Const);
|
|
case QL_LEVEL_1_TOKEN::OP_EQUALorGREATERTHAN:
|
|
return (i64Prop >= i64Const);
|
|
case QL_LEVEL_1_TOKEN::OP_EQUALorLESSTHAN:
|
|
return (i64Prop <= i64Const);
|
|
case QL_LEVEL_1_TOKEN::OP_LESSTHAN:
|
|
return (i64Prop < i64Const);
|
|
case QL_LEVEL_1_TOKEN::OP_GREATERTHAN:
|
|
return (i64Prop > i64Const);
|
|
case QL_LEVEL_1_TOKEN::OP_LIKE: return (i64Prop == i64Const);
|
|
}
|
|
return INVALID;
|
|
}
|
|
}
|
|
|
|
if(wszCimType && !wbem_wcsicmp(wszCimType, L"char16") &&
|
|
V_VT(&CompVal) == VT_BSTR && V_VT(&PropVal) != VT_NULL)
|
|
{
|
|
// Coerce strings correctly
|
|
// ========================
|
|
|
|
BSTR str = V_BSTR(&CompVal);
|
|
if(wcslen(str) != 1)
|
|
return INVALID;
|
|
|
|
short va = V_I2(&PropVal);
|
|
short vb = str[0];
|
|
|
|
switch (Tok.nOperator)
|
|
{
|
|
case QL_LEVEL_1_TOKEN::OP_EQUAL: return (va == vb);
|
|
case QL_LEVEL_1_TOKEN::OP_NOT_EQUAL: return (va != vb);
|
|
case QL_LEVEL_1_TOKEN::OP_EQUALorGREATERTHAN: return (va >= vb);
|
|
case QL_LEVEL_1_TOKEN::OP_EQUALorLESSTHAN: return (va <= vb);
|
|
case QL_LEVEL_1_TOKEN::OP_LESSTHAN: return (va < vb);
|
|
case QL_LEVEL_1_TOKEN::OP_GREATERTHAN: return (va > vb);
|
|
case QL_LEVEL_1_TOKEN::OP_LIKE: return (va == vb);
|
|
}
|
|
|
|
return INVALID;
|
|
}
|
|
|
|
if(wszCimType &&
|
|
(!wbem_wcsicmp(wszCimType, L"datetime")) &&
|
|
V_VT(&CompVal) == VT_BSTR && V_VT(&PropVal) == VT_BSTR)
|
|
{
|
|
// Parse the constant specified in the query according to the
|
|
// SQL rules
|
|
// ==========================================================
|
|
|
|
BSTR strConstVal = V_BSTR(&CompVal);
|
|
#ifdef UNICODE
|
|
CDateTimeParser dtConst(strConstVal);
|
|
#else
|
|
size_t cchBuffer = wcslen(strConstVal) * 4 + 1;
|
|
char* szBuffer = new char[cchBuffer];
|
|
if(szBuffer == NULL)
|
|
return WBEM_E_OUT_OF_MEMORY;
|
|
StringCchPrintf(szBuffer, cchBuffer, "%S", strConstVal);
|
|
|
|
CDateTimeParser dtConst(szBuffer);
|
|
delete [] szBuffer;
|
|
#endif
|
|
if(!dtConst.IsValidDateTime())
|
|
return INVALID;
|
|
|
|
WCHAR wszConstValDMTF[26];
|
|
dtConst.FillDMTF(wszConstValDMTF, 26);
|
|
|
|
// Read both DMTF values and parse them
|
|
// ====================================
|
|
|
|
CWbemTime wtConst, wtProp;
|
|
if(!wtConst.SetDMTF(wszConstValDMTF))
|
|
return INVALID;
|
|
if(!wtProp.SetDMTF(V_BSTR(&PropVal)))
|
|
return INVALID;
|
|
|
|
__int64 i64Const = wtConst.Get100nss();
|
|
__int64 i64Prop = wtProp.Get100nss();
|
|
|
|
switch (Tok.nOperator)
|
|
{
|
|
case QL_LEVEL_1_TOKEN::OP_EQUAL: return (i64Prop == i64Const);
|
|
case QL_LEVEL_1_TOKEN::OP_NOT_EQUAL:
|
|
return (i64Prop != i64Const);
|
|
case QL_LEVEL_1_TOKEN::OP_EQUALorGREATERTHAN:
|
|
return (i64Prop >= i64Const);
|
|
case QL_LEVEL_1_TOKEN::OP_EQUALorLESSTHAN:
|
|
return (i64Prop <= i64Const);
|
|
case QL_LEVEL_1_TOKEN::OP_LESSTHAN:
|
|
return (i64Prop < i64Const);
|
|
case QL_LEVEL_1_TOKEN::OP_GREATERTHAN:
|
|
return (i64Prop > i64Const);
|
|
case QL_LEVEL_1_TOKEN::OP_LIKE: return (i64Prop == i64Const);
|
|
}
|
|
}
|
|
|
|
// Coerce types to match.
|
|
// ======================
|
|
|
|
if(V_VT(&CompVal) != VT_NULL && V_VT(&PropVal) != VT_NULL)
|
|
{
|
|
hRes = VariantChangeType(&CompVal, &CompVal, 0, V_VT(&PropVal));
|
|
if(FAILED(hRes))
|
|
{
|
|
return INVALID;
|
|
}
|
|
}
|
|
|
|
|
|
switch (V_VT(&CompVal))
|
|
{
|
|
case VT_NULL:
|
|
return INVALID; // handled above
|
|
|
|
case VT_I4:
|
|
{
|
|
if(V_VT(&PropVal) == VT_NULL)
|
|
return INVALID;
|
|
|
|
LONG va = V_I4(&PropVal);
|
|
LONG vb = V_I4(&CompVal);
|
|
|
|
switch (Tok.nOperator)
|
|
{
|
|
case QL_LEVEL_1_TOKEN::OP_EQUAL: return (va == vb);
|
|
case QL_LEVEL_1_TOKEN::OP_NOT_EQUAL: return (va != vb);
|
|
case QL_LEVEL_1_TOKEN::OP_EQUALorGREATERTHAN: return (va >= vb);
|
|
case QL_LEVEL_1_TOKEN::OP_EQUALorLESSTHAN: return (va <= vb);
|
|
case QL_LEVEL_1_TOKEN::OP_LESSTHAN: return (va < vb);
|
|
case QL_LEVEL_1_TOKEN::OP_GREATERTHAN: return (va > vb);
|
|
case QL_LEVEL_1_TOKEN::OP_LIKE: return (va == vb);
|
|
}
|
|
}
|
|
break;
|
|
|
|
case VT_I2:
|
|
{
|
|
if(V_VT(&PropVal) == VT_NULL)
|
|
return INVALID;
|
|
|
|
short va = V_I2(&PropVal);
|
|
short vb = V_I2(&CompVal);
|
|
|
|
switch (Tok.nOperator)
|
|
{
|
|
case QL_LEVEL_1_TOKEN::OP_EQUAL: return (va == vb);
|
|
case QL_LEVEL_1_TOKEN::OP_NOT_EQUAL: return (va != vb);
|
|
case QL_LEVEL_1_TOKEN::OP_EQUALorGREATERTHAN: return (va >= vb);
|
|
case QL_LEVEL_1_TOKEN::OP_EQUALorLESSTHAN: return (va <= vb);
|
|
case QL_LEVEL_1_TOKEN::OP_LESSTHAN: return (va < vb);
|
|
case QL_LEVEL_1_TOKEN::OP_GREATERTHAN: return (va > vb);
|
|
case QL_LEVEL_1_TOKEN::OP_LIKE: return (va == vb);
|
|
}
|
|
}
|
|
break;
|
|
|
|
case VT_UI1:
|
|
{
|
|
if(V_VT(&PropVal) == VT_NULL)
|
|
return INVALID;
|
|
|
|
BYTE va = V_I1(&PropVal);
|
|
BYTE vb = V_I1(&CompVal);
|
|
|
|
switch (Tok.nOperator)
|
|
{
|
|
case QL_LEVEL_1_TOKEN::OP_EQUAL: return (va == vb);
|
|
case QL_LEVEL_1_TOKEN::OP_NOT_EQUAL: return (va != vb);
|
|
case QL_LEVEL_1_TOKEN::OP_EQUALorGREATERTHAN: return (va >= vb);
|
|
case QL_LEVEL_1_TOKEN::OP_EQUALorLESSTHAN: return (va <= vb);
|
|
case QL_LEVEL_1_TOKEN::OP_LESSTHAN: return (va < vb);
|
|
case QL_LEVEL_1_TOKEN::OP_GREATERTHAN: return (va > vb);
|
|
case QL_LEVEL_1_TOKEN::OP_LIKE: return (va == vb);
|
|
}
|
|
}
|
|
break;
|
|
|
|
case VT_BSTR:
|
|
{
|
|
if(V_VT(&PropVal) == VT_NULL)
|
|
return INVALID;
|
|
|
|
LPWSTR va = (LPWSTR) V_BSTR(&PropVal);
|
|
LPWSTR vb = (LPWSTR) V_BSTR(&CompVal);
|
|
|
|
int retCode = 0;
|
|
BOOL bDidIt = TRUE;
|
|
|
|
switch (Tok.nOperator)
|
|
{
|
|
case QL_LEVEL_1_TOKEN::OP_EQUAL:
|
|
retCode = ( wbem_wcsicmp(va,vb) == 0);
|
|
break;
|
|
case QL_LEVEL_1_TOKEN::OP_NOT_EQUAL:
|
|
retCode = (wbem_wcsicmp(va, vb) != 0);
|
|
break;
|
|
case QL_LEVEL_1_TOKEN::OP_EQUALorGREATERTHAN:
|
|
retCode = (wbem_wcsicmp(va, vb) >= 0);
|
|
break;
|
|
case QL_LEVEL_1_TOKEN::OP_EQUALorLESSTHAN:
|
|
retCode = (wbem_wcsicmp(va, vb) <= 0);
|
|
break;
|
|
case QL_LEVEL_1_TOKEN::OP_LESSTHAN:
|
|
retCode = (wbem_wcsicmp(va, vb) < 0);
|
|
break;
|
|
case QL_LEVEL_1_TOKEN::OP_GREATERTHAN:
|
|
retCode = (wbem_wcsicmp(va, vb) > 0);
|
|
break;
|
|
case QL_LEVEL_1_TOKEN::OP_LIKE:
|
|
retCode = (wbem_wcsicmp(va,vb) == 0);
|
|
break;
|
|
default:
|
|
bDidIt = FALSE;
|
|
break;
|
|
}
|
|
VariantClear(&CompVal);
|
|
if (bDidIt)
|
|
{
|
|
return retCode;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case VT_R8:
|
|
{
|
|
if(V_VT(&PropVal) == VT_NULL)
|
|
return INVALID;
|
|
|
|
double va = V_R8(&PropVal);
|
|
double vb = V_R8(&CompVal);
|
|
|
|
switch (Tok.nOperator)
|
|
{
|
|
case QL_LEVEL_1_TOKEN::OP_EQUAL: return (va == vb);
|
|
case QL_LEVEL_1_TOKEN::OP_NOT_EQUAL: return (va != vb);
|
|
case QL_LEVEL_1_TOKEN::OP_EQUALorGREATERTHAN: return (va >= vb);
|
|
case QL_LEVEL_1_TOKEN::OP_EQUALorLESSTHAN: return (va <= vb);
|
|
case QL_LEVEL_1_TOKEN::OP_LESSTHAN: return (va < vb);
|
|
case QL_LEVEL_1_TOKEN::OP_GREATERTHAN: return (va > vb);
|
|
case QL_LEVEL_1_TOKEN::OP_LIKE: return (va == vb);
|
|
}
|
|
}
|
|
break;
|
|
|
|
case VT_R4:
|
|
{
|
|
if(V_VT(&PropVal) == VT_NULL)
|
|
return INVALID;
|
|
|
|
float va = V_R4(&PropVal);
|
|
float vb = V_R4(&CompVal);
|
|
|
|
switch (Tok.nOperator)
|
|
{
|
|
case QL_LEVEL_1_TOKEN::OP_EQUAL: return (va == vb);
|
|
case QL_LEVEL_1_TOKEN::OP_NOT_EQUAL: return (va != vb);
|
|
case QL_LEVEL_1_TOKEN::OP_EQUALorGREATERTHAN: return (va >= vb);
|
|
case QL_LEVEL_1_TOKEN::OP_EQUALorLESSTHAN: return (va <= vb);
|
|
case QL_LEVEL_1_TOKEN::OP_LESSTHAN: return (va < vb);
|
|
case QL_LEVEL_1_TOKEN::OP_GREATERTHAN: return (va > vb);
|
|
case QL_LEVEL_1_TOKEN::OP_LIKE: return (va == vb);
|
|
}
|
|
}
|
|
break;
|
|
|
|
case VT_BOOL:
|
|
{
|
|
if(V_VT(&PropVal) == VT_NULL)
|
|
return INVALID;
|
|
|
|
VARIANT_BOOL va = V_BOOL(&PropVal);
|
|
if(va != VARIANT_FALSE) va = VARIANT_TRUE;
|
|
VARIANT_BOOL vb = V_BOOL(&CompVal);
|
|
if(vb != VARIANT_FALSE) vb = VARIANT_TRUE;
|
|
|
|
switch (Tok.nOperator)
|
|
{
|
|
case QL_LEVEL_1_TOKEN::OP_EQUAL: return (va == vb);
|
|
case QL_LEVEL_1_TOKEN::OP_NOT_EQUAL: return (va != vb);
|
|
case QL_LEVEL_1_TOKEN::OP_EQUALorGREATERTHAN: return INVALID;
|
|
case QL_LEVEL_1_TOKEN::OP_EQUALorLESSTHAN: return INVALID;
|
|
case QL_LEVEL_1_TOKEN::OP_LESSTHAN: return INVALID;
|
|
case QL_LEVEL_1_TOKEN::OP_GREATERTHAN: return INVALID;
|
|
case QL_LEVEL_1_TOKEN::OP_LIKE: return (va == vb);
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
LPWSTR CDumbNode::NormalizePath(LPCWSTR wszObjectPath)
|
|
{
|
|
CObjectPathParser Parser;
|
|
ParsedObjectPath* pParsedPath;
|
|
|
|
if(Parser.Parse((LPWSTR)wszObjectPath, &pParsedPath) !=
|
|
CObjectPathParser::NoError ||
|
|
!pParsedPath->IsObject())
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
if(pParsedPath->m_pClass == NULL)
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
//
|
|
// Ignore the server and the namespaze
|
|
//
|
|
|
|
//
|
|
// Check for it being a class
|
|
//
|
|
|
|
LPWSTR wszKey = NULL;
|
|
if(!pParsedPath->IsInstance())
|
|
{
|
|
//
|
|
// It's a class
|
|
//
|
|
|
|
DWORD cLen = wcslen(pParsedPath->m_pClass) +1;
|
|
WCHAR* wszBuffer = new WCHAR[cLen];
|
|
if(wszBuffer == NULL)
|
|
return NULL;
|
|
StringCchCopyW(wszBuffer, cLen, pParsedPath->m_pClass);
|
|
return wszBuffer;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// It's an instance
|
|
//
|
|
|
|
wszKey = pParsedPath->GetKeyString();
|
|
if(wszKey == NULL)
|
|
return NULL;
|
|
|
|
CVectorDeleteMe<WCHAR> vdm(wszKey);
|
|
DWORD cLen = wcslen(pParsedPath->m_pClass) + wcslen(wszKey) + 2;
|
|
WCHAR* wszBuffer = new WCHAR[cLen];
|
|
if(wszBuffer == NULL)
|
|
return NULL;
|
|
|
|
StringCchPrintfW(wszBuffer,cLen,L"%s.%s",pParsedPath->m_pClass,wszKey);
|
|
return wszBuffer;
|
|
}
|
|
}
|
|
|
|
HRESULT CDumbNode::Evaluate(CObjectInfo& ObjInfo,
|
|
INTERNAL CEvalNode** ppNext)
|
|
{
|
|
_IWmiObject* pInst;
|
|
HRESULT hres = GetContainerObject(ObjInfo, &pInst);
|
|
if(FAILED(hres)) return hres;
|
|
if(pInst == NULL)
|
|
{
|
|
*ppNext = m_pNullBranch;
|
|
return WBEM_S_NO_ERROR;
|
|
}
|
|
|
|
//
|
|
// Just evaluate the token, ala core.
|
|
//
|
|
|
|
IWbemPropertySource* pPropSource = NULL;
|
|
hres = pInst->QueryInterface(IID_IWbemPropertySource, (void**)&pPropSource);
|
|
if(FAILED(hres))
|
|
return WBEM_E_CRITICAL_ERROR;
|
|
CReleaseMe rm1(pPropSource);
|
|
|
|
int nRes = EvaluateToken(pPropSource, m_Token);
|
|
if(nRes == INVALID)
|
|
*ppNext = m_pNullBranch;
|
|
else if(nRes == FALSE)
|
|
*ppNext = m_apBranches[DUMBNODE_FALSE_BRANCH_INDEX];
|
|
else
|
|
*ppNext = m_apBranches[DUMBNODE_TRUE_BRANCH_INDEX];
|
|
|
|
return WBEM_S_NO_ERROR;
|
|
}
|
|
|
|
HRESULT CDumbNode::Compile(CContextMetaData* pNamespace,
|
|
CImplicationList& Implications)
|
|
{
|
|
if (!m_pInfo)
|
|
{
|
|
try
|
|
{
|
|
m_pInfo = new CEmbeddingInfo;
|
|
}
|
|
catch(CX_MemoryException)
|
|
{
|
|
return WBEM_E_OUT_OF_MEMORY;
|
|
}
|
|
|
|
if(m_pInfo == NULL)
|
|
return WBEM_E_OUT_OF_MEMORY;
|
|
}
|
|
|
|
|
|
HRESULT hres = CompileEmbeddingPortion(pNamespace, Implications, NULL);
|
|
return hres;
|
|
}
|
|
|
|
HRESULT CDumbNode::CombineBranchesWith(CBranchingNode* pRawArg2, int nOp,
|
|
CContextMetaData* pNamespace,
|
|
CImplicationList& OrigImplications,
|
|
bool bDeleteThis, bool bDeleteArg2,
|
|
CEvalNode** ppRes)
|
|
{
|
|
HRESULT hres;
|
|
|
|
//
|
|
// There is only one case in which combining dumb nodes is allowed ---
|
|
// when both of them are exactly the same
|
|
//
|
|
|
|
CDumbNode* pArg2 = (CDumbNode*)pRawArg2;
|
|
if(SubCompare(pArg2) != 0)
|
|
return WBEM_E_CRITICAL_ERROR;
|
|
|
|
if(!bDeleteThis && bDeleteArg2)
|
|
{
|
|
// It is easier to combine in the other direction
|
|
// ==============================================
|
|
|
|
return pArg2->CombineBranchesWith(this, FlipEvalOp(nOp), pNamespace,
|
|
OrigImplications, bDeleteArg2, bDeleteThis, ppRes);
|
|
}
|
|
|
|
// Either clone or use our node
|
|
// ============================
|
|
|
|
CDumbNode* pNew = NULL;
|
|
if(bDeleteThis)
|
|
{
|
|
pNew = this;
|
|
}
|
|
else
|
|
{
|
|
// Clone this node without cloning the branches.
|
|
// =============================================
|
|
|
|
pNew = (CDumbNode*)CloneSelf();
|
|
if(pNew == NULL)
|
|
return WBEM_E_OUT_OF_MEMORY;
|
|
}
|
|
|
|
CImplicationList Implications(OrigImplications);
|
|
pNew->AdjustCompile(pNamespace, Implications);
|
|
|
|
// Merge all branches
|
|
// ==================
|
|
|
|
for(int i = 0; i < m_apBranches.GetSize(); i++)
|
|
{
|
|
// Prepare implications for taking this branch
|
|
// ===========================================
|
|
|
|
CImplicationList BranchImplications(Implications);
|
|
|
|
CEvalNode* pNewBranch = NULL;
|
|
hres = CEvalTree::Combine(m_apBranches[i],
|
|
pArg2->m_apBranches[i],
|
|
nOp, pNamespace, BranchImplications,
|
|
bDeleteThis, bDeleteArg2,
|
|
&pNewBranch);
|
|
if(FAILED(hres))
|
|
{
|
|
if ( !bDeleteThis )
|
|
delete pNew;
|
|
return hres;
|
|
}
|
|
|
|
if(bDeleteThis)
|
|
{
|
|
m_apBranches.Discard(i);
|
|
pNew->m_apBranches.SetAt(i, pNewBranch);
|
|
}
|
|
else
|
|
{
|
|
if(pNew->m_apBranches.Add(pNewBranch) < 0)
|
|
return WBEM_E_OUT_OF_MEMORY;
|
|
}
|
|
|
|
if(bDeleteArg2)
|
|
pArg2->m_apBranches.Discard(i);
|
|
}
|
|
|
|
// Merge the nulls
|
|
// ===============
|
|
|
|
CImplicationList NullImplications(Implications);
|
|
CEvalNode* pNewBranch = NULL;
|
|
hres = CEvalTree::Combine(m_pNullBranch, pArg2->m_pNullBranch, nOp,
|
|
pNamespace, NullImplications, bDeleteThis, bDeleteArg2,
|
|
&pNewBranch);
|
|
|
|
if(FAILED(hres))
|
|
{
|
|
if ( !bDeleteThis )
|
|
delete pNew;
|
|
return hres;
|
|
}
|
|
|
|
// Clear the old new branch, whatever it was, and replace it with the
|
|
// new one.
|
|
// ==================================================================
|
|
|
|
pNew->m_pNullBranch = pNewBranch;
|
|
|
|
// Clear deleted branches
|
|
// ======================
|
|
|
|
if(bDeleteArg2)
|
|
pArg2->m_pNullBranch = NULL;
|
|
|
|
// Delete Arg2, if needed (reused portions have been nulled out)
|
|
// =============================================================
|
|
|
|
if(bDeleteArg2)
|
|
delete pArg2;
|
|
|
|
*ppRes = pNew;
|
|
return WBEM_S_NO_ERROR;
|
|
}
|
|
|
|
void CDumbNode::Dump(FILE* f, int nOffset)
|
|
{
|
|
CBranchingNode::Dump(f, nOffset);
|
|
LPWSTR wszText = m_Token.GetText();
|
|
CVectorDeleteMe<WCHAR> vdm1(wszText);
|
|
|
|
PrintOffset(f, nOffset);
|
|
fprintf(f, "token %S:\n", wszText);
|
|
|
|
PrintOffset(f, nOffset);
|
|
fprintf(f, "FALSE->\n");
|
|
DumpNode(f, nOffset+1, m_apBranches[DUMBNODE_FALSE_BRANCH_INDEX]);
|
|
|
|
PrintOffset(f, nOffset);
|
|
fprintf(f, "TRUE->\n");
|
|
DumpNode(f, nOffset+1, m_apBranches[DUMBNODE_TRUE_BRANCH_INDEX]);
|
|
|
|
PrintOffset(f, nOffset);
|
|
fprintf(f, "NULL->\n");
|
|
DumpNode(f, nOffset+1, m_pNullBranch);
|
|
}
|
|
|