|
|
/*++
Copyright (C) 1996-1999 Microsoft Corporation
Module Name:
EVALTREE.CPP
Abstract:
WBEM Evaluation Tree
History:
--*/
#include "precomp.h"
#include <stdio.h>
#pragma warning(disable:4786)
#include <wbemcomn.h>
#include <fastall.h>
#include <genutils.h>
#include "evaltree.h"
#include "TreeChecker.h"
#include "evaltree.inl"
#include "TwoPropNode.h"
#include "dumbnode.h"
// #define DUMP_EVAL_TREES 1
HRESULT CoreGetNumParents(_IWmiObject* pClass, ULONG *plNumParents) { /*
*plNumParents = ((CWbemObject*)pClass)->GetNumParents(); */ DWORD dwSize; HRESULT hres = pClass->GetDerivation(0, 0, plNumParents, &dwSize, NULL); if(hres != WBEM_E_BUFFER_TOO_SMALL && hres != S_OK) return WBEM_E_FAILED;
return S_OK; }
RELEASE_ME _IWmiObject* CoreGetEmbeddedObj(_IWmiObject* pObj, long lHandle) { _IWmiObject* pEmbedded = NULL; HRESULT hres = pObj->GetPropAddrByHandle(lHandle, 0, NULL, (void**)&pEmbedded); if(FAILED(hres)) return NULL;
return pEmbedded; }
INTERNAL CCompressedString* CoreGetPropertyString(_IWmiObject* pObj, long lHandle) { CCompressedString* pcs = NULL; HRESULT hres = pObj->GetPropAddrByHandle(lHandle, WMIOBJECT_FLAG_ENCODING_V1, NULL, (void**)&pcs); if(FAILED(hres)) return NULL;
return pcs; }
INTERNAL CCompressedString* CoreGetClassInternal(_IWmiObject* pObj) { CCompressedString* pcs = NULL; HRESULT hres = pObj->GetPropAddrByHandle(FASTOBJ_CLASSNAME_PROP_HANDLE, WMIOBJECT_FLAG_ENCODING_V1, NULL, (void**)&pcs); if(FAILED(hres)) return NULL;
return pcs; }
INTERNAL CCompressedString* CoreGetParentAtIndex(_IWmiObject* pObj, long lIndex) { return ((CWbemObject*)pObj)->GetParentAtIndex(lIndex); }
bool CoreIsDerived(_IWmiObject* pThis, _IWmiObject* pFrom) { CCompressedString* pcs = CoreGetClassInternal(pFrom); if(pcs == NULL) return false;
try { return (pThis->InheritsFrom(pcs->CreateWStringCopy()) == S_OK); } catch (CX_MemoryException) { return false; } }
//******************************************************************************
//******************************************************************************
// TOKEN VALUE
//******************************************************************************
//******************************************************************************
CTokenValue::CTokenValue() { VariantInit(&m_v); } CTokenValue::CTokenValue(CTokenValue& Other) { VariantInit(&m_v); *this = Other; }
CTokenValue::~CTokenValue() { VariantClear(&m_v); }
bool CTokenValue::SetVariant(VARIANT& v) { if(FAILED(VariantCopy(&m_v, &v))) return false;
// Convert to a better type
// ========================
if(V_VT(&v) == VT_I2 || V_VT(&v) == VT_UI1) { if(FAILED(VariantChangeType(&m_v, &m_v, 0, VT_I4))) return false; } else if(V_VT(&v) == VT_R4) { if(FAILED(VariantChangeType(&m_v, &m_v, 0, VT_R8))) return false; }
return true; }
void CTokenValue::operator=(CTokenValue& Other) { if(!SetVariant(Other.m_v)) throw CX_MemoryException(); }
CTokenValue::operator unsigned __int64() const { if(V_VT(&m_v) == VT_I4) { return V_I4(&m_v); } else if(V_VT(&m_v) == VT_BSTR) { unsigned __int64 ui64; if(ReadUI64(V_BSTR(&m_v), ui64)) return ui64; else return 0; // TBD: errors
} else return 0; }
CTokenValue::operator unsigned long() const { if(V_VT(&m_v) == VT_I4) { return V_I4(&m_v); } else if(V_VT(&m_v) == VT_BSTR) { unsigned __int64 ui64; if(ReadUI64(V_BSTR(&m_v), ui64)) return (unsigned long)ui64; else return 0; // TBD: errors
} else return 0; }
CTokenValue::operator __int64() const { if(V_VT(&m_v) == VT_I4) { return V_I4(&m_v); } else if(V_VT(&m_v) == VT_BSTR) { __int64 i64; if(ReadI64(V_BSTR(&m_v), i64)) return i64; else return 0; // TBD: errors
} else return 0; } CTokenValue::operator short() const { if(V_VT(&m_v) == VT_I4) return V_I4(&m_v); else if(V_VT(&m_v) == VT_BOOL) return V_BOOL(&m_v); else return 0; } CTokenValue::operator float() const { if(V_VT(&m_v) == VT_I4) return V_I4(&m_v); else if(V_VT(&m_v) == VT_R8) return V_R8(&m_v); else return 0; }
CTokenValue::operator double() const { if(V_VT(&m_v) == VT_I4) return V_I4(&m_v); else if(V_VT(&m_v) == VT_R8) return V_R8(&m_v); else return 0; }
CTokenValue::operator WString() const { if(V_VT(&m_v) == VT_BSTR) return WString(V_BSTR(&m_v)); else return WString(L""); }
int CTokenValue::Compare(const CTokenValue& Other) const { switch(V_VT(&m_v)) { case VT_I4: return V_I4(&m_v) - V_I4(&Other.m_v); case VT_R8: return (V_R8(&m_v) - V_R8(&Other.m_v)<0 ? -1 : 1); case VT_BSTR: return wbem_wcsicmp(V_BSTR(&m_v), V_BSTR(&Other.m_v)); case VT_BOOL: return V_BOOL(&m_v) - V_BOOL(&Other.m_v); } return 0; } //******************************************************************************
//******************************************************************************
// OBJECT INFO
//******************************************************************************
//******************************************************************************
bool CObjectInfo::SetLength(long lLength) { if(lLength > m_lLength) { delete [] m_apObj; m_apObj = new _IWmiObject*[lLength]; if (m_apObj == NULL) return false;
memset(m_apObj, 0, lLength * sizeof(_IWmiObject*)); } m_lLength = lLength; return true; }
void CObjectInfo::Clear() { for(long i = 1; i < m_lLength; i++) { if(m_apObj[i]) m_apObj[i]->Release(); m_apObj[i] = NULL; } m_apObj[0] = NULL; // do not release
}
void CObjectInfo::SetObjectAt(long lIndex, READ_ONLY _IWmiObject* pObj) { if(m_apObj[lIndex]) m_apObj[lIndex]->Release();
m_apObj[lIndex] = pObj; }
CObjectInfo::~CObjectInfo() { for(long i = 0; i < m_lLength; i++) { if(m_apObj[i]) m_apObj[i]->Release(); } delete [] m_apObj; }
//******************************************************************************
//******************************************************************************
// IMPLICATION LIST
//******************************************************************************
//******************************************************************************
CImplicationList::CRecord::CRecord(const CImplicationList::CRecord& Other) : m_PropName(Other.m_PropName), m_pClass(Other.m_pClass), m_lObjIndex(Other.m_lObjIndex), m_nNull(Other.m_nNull) { if(m_pClass) m_pClass->AddRef();
for(int i = 0; i < Other.m_awsNotClasses.Size(); i++) { if(m_awsNotClasses.Add(Other.m_awsNotClasses[i]) != CWStringArray::no_error) { throw CX_MemoryException(); } } }
CImplicationList::CRecord::~CRecord() { if(m_pClass) m_pClass->Release(); }
HRESULT CImplicationList::CRecord::ImproveKnown(_IWmiObject* pClass) { if ( pClass == NULL ) { //
// not much we can improve on, but NULL is still a valid param.
//
return WBEM_S_NO_ERROR; }
if(m_nNull == EVAL_VALUE_TRUE) { // Contradiction
// =============
return WBEM_E_TYPE_MISMATCH; }
m_nNull = EVAL_VALUE_FALSE;
ULONG lNumParents, lRecordNumParents; HRESULT hres = CoreGetNumParents(pClass, &lNumParents); if(FAILED(hres)) return hres;
if(m_pClass) { hres = CoreGetNumParents(m_pClass, &lRecordNumParents); if(FAILED(hres)) return hres; } if(m_pClass == NULL || lNumParents > lRecordNumParents) { // Better than before. Check for inconsistencies
// =============================================
if(m_pClass) { if(!CoreIsDerived(pClass, m_pClass)) return WBEM_E_TYPE_MISMATCH; }
for(int i = 0; i < m_awsNotClasses.Size(); i++) { if(pClass->InheritsFrom(m_awsNotClasses[i]) == S_OK) { // Contradiction
// =============
return WBEM_E_TYPE_MISMATCH; } }
// Replace
// =======
pClass->AddRef(); if(m_pClass) m_pClass->Release(); m_pClass = pClass; } else { // Verify that we are a parent of the selected and do not replace
// ==============================================================
if(!CoreIsDerived(m_pClass, pClass)) return WBEM_E_TYPE_MISMATCH; }
return WBEM_S_NO_ERROR; } HRESULT CImplicationList::CRecord::ImproveKnownNot(LPCWSTR wszClassName) { if(m_nNull == EVAL_VALUE_TRUE) { // Contradiction
// =============
return WBEM_E_TYPE_MISMATCH; }
// Check for inconsistencies
// =========================
if(m_nNull == EVAL_VALUE_FALSE && m_pClass && m_pClass->InheritsFrom(wszClassName) == S_OK) { // Contradiction
// =============
return WBEM_E_TYPE_MISMATCH; }
try { if(m_awsNotClasses.Add(wszClassName) < 0) return WBEM_E_OUT_OF_MEMORY; } catch (CX_MemoryException) { return WBEM_E_OUT_OF_MEMORY; }
m_nNull = EVAL_VALUE_FALSE; return WBEM_S_NO_ERROR; } HRESULT CImplicationList::CRecord::ImproveKnownNull() { if(m_nNull == EVAL_VALUE_FALSE) { return WBEM_E_TYPE_MISMATCH; } m_nNull = EVAL_VALUE_TRUE;
return WBEM_S_NO_ERROR; }
void CImplicationList::CRecord::Dump(FILE* f, int nOffset) { LPWSTR wszProp = m_PropName.GetText(); CEvalNode::PrintOffset(f, nOffset); fprintf(f, "Learn about %S:\n", wszProp);
if(m_pClass) { VARIANT v; m_pClass->Get(L"__CLASS", 0, &v, NULL, NULL); CEvalNode::PrintOffset(f, nOffset+1); fprintf(f, "Is of class %S\n", V_BSTR(&v)); } for(int i = 0; i < m_awsNotClasses.Size(); i++) { CEvalNode::PrintOffset(f, nOffset+1); fprintf(f, "Not of class %S\n", m_awsNotClasses[i]); } if(m_nNull == EVAL_VALUE_TRUE) { CEvalNode::PrintOffset(f, nOffset+1); fprintf(f, "Is NULL\n"); } }
CImplicationList::CImplicationList(long lFlags) : m_lNextIndex(1), m_lRequiredDepth(1), m_pParent(NULL), m_lFlags(lFlags) { CPropertyName Empty; CRecord* pRecord = new CRecord(Empty, 0); if(pRecord == NULL) throw CX_MemoryException();
if(m_apRecords.Add(pRecord) < 0) throw CX_MemoryException(); }
CImplicationList::CImplicationList(CImplicationList& Other, bool bLink) : m_lNextIndex(Other.m_lNextIndex), m_lRequiredDepth(Other.m_lRequiredDepth), m_pParent(NULL), m_lFlags(Other.m_lFlags) { if(bLink) m_pParent = &Other;
for(int i = 0; i < Other.m_apRecords.GetSize(); i++) { CRecord* pOtherRecord = Other.m_apRecords[i]; CRecord* pNewRecord = new CRecord(*pOtherRecord); if(pNewRecord == NULL) throw CX_MemoryException(); if(m_apRecords.Add(pNewRecord) < 0) throw CX_MemoryException(); } }
CImplicationList::~CImplicationList() { m_lNextIndex = 0; }
void CImplicationList::FindBestComputedContainer(CPropertyName* pPropName, long* plRecord, long* plMatched) { // Look for the largest match
// ==========================
long lMax = -1; long lMaxRecord = -1; for(long lRecord = 0; lRecord < m_apRecords.GetSize(); lRecord++) { CRecord* pRecord = m_apRecords[lRecord]; if ( pRecord->m_lObjIndex == -1 ) { //
// we only consider computed records
//
continue; }
for(int i = 0; i < pPropName->GetNumElements() && i < pRecord->m_PropName.GetNumElements(); i++) { if(wbem_wcsicmp(pPropName->GetStringAt(i), pRecord->m_PropName.GetStringAt(i))) break; }
if(i > lMax) { lMax = i; lMaxRecord = lRecord; } } if(plRecord) *plRecord = lMaxRecord; if(plMatched) *plMatched = lMax; }
HRESULT CImplicationList::FindRecordForProp(CPropertyName* pPropName, long lNumElements, long* plRecord) { if(lNumElements == -1) { if(pPropName) lNumElements = pPropName->GetNumElements(); else lNumElements = 0; }
//
// Look for the exact match
//
for(long lRecord = 0; lRecord < m_apRecords.GetSize(); lRecord++) { CRecord* pRecord = m_apRecords[lRecord]; if(pRecord->m_PropName.GetNumElements() != lNumElements) continue;
for(int i = 0; i < lNumElements; i++) { if(wbem_wcsicmp(pPropName->GetStringAt(i), pRecord->m_PropName.GetStringAt(i))) break; }
if(i == lNumElements) { break; } } if(lRecord < m_apRecords.GetSize()) { // Found it!
*plRecord = lRecord; return S_OK; } else return WBEM_E_NOT_FOUND; }
HRESULT CImplicationList::FindBestComputedContainer(CPropertyName* pPropName, long* plFirstUnknownProp, long* plObjIndex, RELEASE_ME _IWmiObject** ppContainerClass) { if (!pPropName) return WBEM_E_FAILED; long lMax, lMaxRecord; FindBestComputedContainer(pPropName, &lMaxRecord, &lMax); if(lMaxRecord < 0) return WBEM_E_FAILED;
if(plFirstUnknownProp) *plFirstUnknownProp = lMax;
CRecord* pRecord = m_apRecords[lMaxRecord]; if(plObjIndex) *plObjIndex = pRecord->m_lObjIndex;
if(ppContainerClass) { *ppContainerClass = pRecord->m_pClass; if(pRecord->m_pClass) pRecord->m_pClass->AddRef(); }
return WBEM_S_NO_ERROR; }
HRESULT CImplicationList::FindClassForProp(CPropertyName* pPropName, long lNumElements, RELEASE_ME _IWmiObject** ppClass) { // don't have a property name? djinn one up for use...
CPropertyName* pPropNameLocal; CPropertyName blank; if (pPropName) pPropNameLocal = pPropName; else pPropNameLocal = ␣ long lRecord; CRecord* pRecord; if(SUCCEEDED(FindRecordForProp(pPropNameLocal, -1, &lRecord))) { //
// A record is there --- return its class
//
*ppClass = m_apRecords[lRecord]->m_pClass; if(*ppClass) { (*ppClass)->AddRef(); return WBEM_S_NO_ERROR; } else return WBEM_E_NOT_FOUND; } else return WBEM_E_NOT_FOUND; } HRESULT CImplicationList::FindOrCreateRecordForProp(CPropertyName* pPropName, CImplicationList::CRecord** ppRecord) { // don't have a property name? djinn one up for use...
CPropertyName* pPropNameLocal; CPropertyName blank; if (pPropName) pPropNameLocal = pPropName; else pPropNameLocal = ␣ long lRecord; CRecord* pRecord; if(SUCCEEDED(FindRecordForProp(pPropNameLocal, -1, &lRecord))) { //
// A record is there --- improve it
//
pRecord = m_apRecords[lRecord]; } else { try { pRecord = new CRecord(*pPropNameLocal, -1); if(pRecord == NULL) return WBEM_E_OUT_OF_MEMORY; } catch (CX_MemoryException) { return WBEM_E_OUT_OF_MEMORY; } if(m_apRecords.Add(pRecord) < 0) return WBEM_E_OUT_OF_MEMORY; }
*ppRecord = pRecord; return WBEM_S_NO_ERROR; }
HRESULT CImplicationList::ImproveKnown(CPropertyName* pPropName, _IWmiObject* pClass) { CRecord* pRecord; HRESULT hres = FindOrCreateRecordForProp(pPropName, &pRecord); if(FAILED(hres)) return hres;
return pRecord->ImproveKnown(pClass); }
HRESULT CImplicationList::ImproveKnownNot(CPropertyName* pPropName, LPCWSTR wszClassName) { CRecord* pRecord; HRESULT hres = FindOrCreateRecordForProp(pPropName, &pRecord); if(FAILED(hres)) return hres;
return pRecord->ImproveKnownNot(wszClassName); }
HRESULT CImplicationList::ImproveKnownNull(CPropertyName* pPropName) { CRecord* pRecord; HRESULT hres = FindOrCreateRecordForProp(pPropName, &pRecord); if(FAILED(hres)) return hres;
return pRecord->ImproveKnownNull(); } HRESULT CImplicationList::AddComputation(CPropertyName& PropName, _IWmiObject* pClass, long* plObjIndex) { CRecord* pRecord; HRESULT hres = FindOrCreateRecordForProp(&PropName, &pRecord); if(FAILED(hres)) return hres;
if(pClass) { hres = pRecord->ImproveKnown(pClass); if(FAILED(hres)) return hres; }
pRecord->m_lObjIndex = m_lNextIndex; *plObjIndex = m_lNextIndex++;
RequireDepth(m_lNextIndex); return WBEM_S_NO_ERROR; }
long CImplicationList::GetRequiredDepth() { return m_lRequiredDepth; }
void CImplicationList::RequireDepth(long lDepth) { if(lDepth > m_lRequiredDepth) { m_lRequiredDepth = lDepth; if(m_pParent) m_pParent->RequireDepth(lDepth); } }
HRESULT CImplicationList::MergeIn(CImplicationList* pList) { //
// Add everything we learn from the second list into our own
//
HRESULT hres; for(int i = 0; i < pList->m_apRecords.GetSize(); i++) { CRecord* pRecord = pList->m_apRecords[i];
hres = MergeIn(pRecord); if(FAILED(hres)) return hres; }
return S_OK; }
HRESULT CImplicationList::MergeIn(CImplicationList::CRecord* pRecord) { HRESULT hres;
//
// Add everything we learn from the record into our own list
//
if(pRecord->m_pClass) { hres = ImproveKnown(&pRecord->m_PropName, pRecord->m_pClass); if(FAILED(hres)) return hres; }
for(int i = 0; i < pRecord->m_awsNotClasses.Size(); i++) { hres = ImproveKnownNot(&pRecord->m_PropName, pRecord->m_awsNotClasses[i]); if(FAILED(hres)) return hres; }
if(pRecord->m_nNull == EVAL_VALUE_TRUE) { hres = ImproveKnownNull(&pRecord->m_PropName); if(FAILED(hres)) return hres; }
return WBEM_S_NO_ERROR; }
void CImplicationList::Dump(FILE* f, int nOffset) { for(int i = 0; i < m_apRecords.GetSize(); i++) m_apRecords[i]->Dump(f, nOffset); }
//******************************************************************************
//******************************************************************************
// EVAL NODE
//******************************************************************************
//******************************************************************************
CEvalNode::CEvalNode() { #ifdef CHECK_TREES
g_treeChecker.AddNode(this); #endif
}
CEvalNode::CEvalNode(const CEvalNode& other) { #ifdef CHECK_TREES
g_treeChecker.AddNode(this); #endif
}
CEvalNode::~CEvalNode() { #ifdef CHECK_TREES
g_treeChecker.RemoveNode(this); #endif
}
void CEvalNode::PrintOffset(FILE* f, int nOffset) { for(int i = 0; i < nOffset; i++) { fprintf(f, " "); } }
void CEvalNode::DumpNode(FILE* f, int nOffset, CEvalNode* pNode) { if(pNode == NULL) { PrintOffset(f, nOffset); fprintf(f, "FALSE\n"); } else pNode->Dump(f, nOffset); }
CEvalNode* CEvalNode::CloneNode(const CEvalNode* pNode) { if(pNode == NULL) return NULL; else return pNode->Clone(); }
bool CEvalNode::IsNoop(CEvalNode* pNode, int nOp) { if(pNode) return pNode->IsNoop(nOp); else return CValueNode::IsNoop(NULL, nOp); }
#ifdef CHECK_TREES
void CEvalNode::CheckNode(CTreeChecker *pCheck) { pCheck->CheckoffNode(this); } #endif
//******************************************************************************
//******************************************************************************
// SORTED ARRAY
//******************************************************************************
//******************************************************************************
// construct from a 'normal' array
CSortedArray::CSortedArray(unsigned nElements, QueryID* pArray) : CFlexArray(nElements) { memcpy(GetArrayPtr(), pArray, nElements * sizeof(void*)); SetSize(nElements); }
int CSortedArray::CopyDataFrom(const QueryID* pArray, unsigned nElements) { EnsureExtent(nElements); SetSize(nElements);
memcpy(GetArrayPtr(), pArray, nElements * sizeof(void*));
return nElements; }
unsigned CSortedArray::Find(QueryID n) { unsigned ret = InvalidID;
// bailout if empty
if(Size() == 0) return InvalidID;
unsigned lBound = 0; unsigned uBound = Size() -1; // bailout checks - if it's on the boundary, don't search
// if it's outside the boundaries, we ain't got it
if (n == GetAt(uBound)) ret = uBound; else if (n == GetAt(lBound)) ret = lBound; else if ((n > GetAt(lBound)) && (n < GetAt(uBound))) { // binary search
// warning: break in middle of loop
do { unsigned testBound = (lBound + uBound) / 2;
if (n < GetAt(testBound)) uBound = testBound; else if (n > GetAt(testBound)) lBound = testBound; else { ret = testBound; break; } } while (lBound < uBound -1); } return ret; }
// inserts n in proper position
// no dups allowed
void CSortedArray::Insert(QueryID n) { // looks a lot like 'find'
unsigned lBound = 0; unsigned uBound = Size() == 0 ? 0 : Size() -1; unsigned testBound = InvalidID; // check boundaries, empty array, out of bounds conditions...
if ((Size() == 0) || (n < GetAt(lBound))) CFlexArray::InsertAt(0, (void *)n); else if (n > GetAt(uBound)) Add(n); else if ((n != GetAt(uBound)) && (n != GetAt(lBound))) { // binary search
// warning: break in middle of loop
do { testBound = (lBound + uBound) / 2;
if (n < GetAt(testBound)) uBound = testBound; else if (n > GetAt(testBound)) lBound = testBound; else break; } while (lBound < uBound -1);
// at this point, three cases:
// 1) we found the item at testBound
// 2) we didn't find it, uBound = lBound +1
// 3) we didn't find it, uBound == lBound
if (n != GetAt(testBound)) { if (n < GetAt(lBound)) InsertAt(lBound, (void *)n); else InsertAt(uBound, (void *)n); } } }
// removes element with value of n
// NOT the nth element
bool CSortedArray::Remove(QueryID n) { unsigned index; index = Find(n); if (index != InvalidID) { CFlexArray::RemoveAt(index); return true; } else return false; }
//returns zero if arrays are equivalent
// same number of USED elements w/ same values
// LEVN: changed to return < 0 if less, > 0 if more
int CSortedArray::Compare(CSortedArray& otherArray) { int nCompare = Size() - otherArray.Size(); if(nCompare) return nCompare;
nCompare = memcmp(GetArrayPtr(), otherArray.GetArrayPtr(), Size() * sizeof(void*)); return nCompare; }
// changes all QueryID's to begin at newBase
// e.g. if the array is {0,1,5}
// Rebase(6) will change to {6,7,11}
void CSortedArray::Rebase(QueryID newBase) { for (int i = 0; i < Size(); i++) SetAt(i, (void *)(GetAt(i) + newBase)); }
// adds the values from the other array into this one
int CSortedArray::AddDataFrom(const CSortedArray& otherArray) { // Check for emptiness
if(otherArray.Size() == 0) return no_error;
// Ensure there is enough room in our array for the union
// ======================================================
if(EnsureExtent(m_nSize + otherArray.m_nSize)) return out_of_memory; // Start merging from the end
// ==========================
int nThisSourceIndex = m_nSize - 1; int nThisDestIndex = m_nSize + otherArray.m_nSize - 1; int nOtherIndex = otherArray.m_nSize - 1; while(nThisSourceIndex >= 0 && nOtherIndex >= 0) { int nCompare = (QueryID)m_pArray[nThisSourceIndex] - (QueryID)otherArray[nOtherIndex]; if(nCompare < 0) { m_pArray[nThisDestIndex--] = otherArray[nOtherIndex--]; } else if(nCompare > 0) { m_pArray[nThisDestIndex--] = m_pArray[nThisSourceIndex--]; } else { m_pArray[nThisDestIndex--] = otherArray[nOtherIndex--]; nThisSourceIndex--; } }
// Add remainders
// ==============
while(nThisSourceIndex >= 0) m_pArray[nThisDestIndex--] = m_pArray[nThisSourceIndex--];
while(nOtherIndex >= 0) m_pArray[nThisDestIndex--] = otherArray[nOtherIndex--];
// Move the array forward if needed
// ================================
if(nThisDestIndex >= 0) { for(int i = nThisDestIndex+1; i < m_nSize + otherArray.m_nSize; i++) { m_pArray[i-nThisDestIndex-1] = m_pArray[i]; } }
m_nSize = m_nSize + otherArray.m_nSize - (nThisDestIndex+1); return no_error; }
// adds the values from the other array into this one
int CSortedArray::AddDataFrom(const QueryID* pOtherArray, unsigned nValues) { // Check for emptiness
if(nValues == 0) return no_error;
// Ensure there is enough room in our array for the union
// ======================================================
if(EnsureExtent(m_nSize + nValues)) return out_of_memory; // Start merging from the end
// ==========================
int nThisSourceIndex = m_nSize - 1; int nThisDestIndex = m_nSize + nValues - 1; int nOtherIndex = nValues - 1; while(nThisSourceIndex >= 0 && nOtherIndex >= 0) { int nCompare = (QueryID)m_pArray[nThisSourceIndex] - (QueryID)pOtherArray[nOtherIndex]; if(nCompare < 0) { m_pArray[nThisDestIndex--] = (void*)pOtherArray[nOtherIndex--]; } else if(nCompare > 0) { m_pArray[nThisDestIndex--] = m_pArray[nThisSourceIndex--]; } else { m_pArray[nThisDestIndex--] = (void*)pOtherArray[nOtherIndex--]; nThisSourceIndex--; } }
// Add remainders
// ==============
while(nThisSourceIndex >= 0) m_pArray[nThisDestIndex--] = m_pArray[nThisSourceIndex--];
while(nOtherIndex >= 0) m_pArray[nThisDestIndex--] = (void*)pOtherArray[nOtherIndex--];
// Move the array forward if needed
// ================================
if(nThisDestIndex >= 0) { for(int i = nThisDestIndex+1; i < m_nSize + nValues; i++) { m_pArray[i-nThisDestIndex-1] = m_pArray[i]; } }
m_nSize = m_nSize + nValues - (nThisDestIndex+1); return no_error; }
// copies this array to destination
// only copies size number of elements
// returns number of elements copied
unsigned CSortedArray::CopyTo(QueryID* pDest, unsigned size) { unsigned mySize = Size(); unsigned nElementsToCopy = min(size, mySize);
if (nElementsToCopy) memcpy(pDest, GetArrayPtr(), nElementsToCopy * sizeof(void*));
return nElementsToCopy; }
//******************************************************************************
//******************************************************************************
// VALUE NODE
//******************************************************************************
//******************************************************************************
CValueNode::CValueNode(int nNumValues) { }
CValueNode::~CValueNode() { // this page intentionally left blank
}
/* virtual */ int CValueNode::GetType() { return EVAL_NODE_TYPE_VALUE; }
// changes all QueryID's in all arrays to begin at newBase
// e.g. if the array is {0,1,5}
// Rebase(6) will change to {6,7,11}
void CValueNode::Rebase(QueryID newBase) { for (int i = 0; i < m_nValues; i++) m_trueIDs[i] += newBase; }
// returns array index of n
// or InvalidID if not found
unsigned CValueNode::FindQueryID(QueryID n) { unsigned ret = InvalidID;
if ( m_nValues == 0 ) { return ret; }
unsigned lBound = 0; unsigned uBound = m_nValues - 1;
// bailout checks - if it's on the boundary, don't search
// if it's outside the boundaries, we ain't got it
if (n == m_trueIDs[uBound]) ret = uBound; else if (n == m_trueIDs[lBound]) ret = lBound; else if ((n > m_trueIDs[lBound]) && (n < m_trueIDs[uBound])) { // binary search
// warning: break in middle of loop
do { unsigned testBound = (lBound + uBound) / 2;
if (n < m_trueIDs[testBound]) uBound = testBound; else if (n > m_trueIDs[testBound]) lBound = testBound; else { ret = testBound; break; } } while (lBound < uBound -1); }
return ret; }
bool CValueNode::RemoveQueryID(QueryID nQuery) { unsigned n; if ((n = FindQueryID(nQuery)) != InvalidID) { if ((m_nValues > 1) && (n != m_nValues -1)) memcpy(&(m_trueIDs[n]), &(m_trueIDs[n+1]), (m_nValues -n -1) * sizeof(QueryID)); if (m_nValues > 0) m_trueIDs[--m_nValues] = InvalidID; } return (n != InvalidID); }
// combines two arrays, new array has all elements that appear in either
// BUT NOT in the corresponding NOT array
void CValueNode::ORarrays(CSortedArray& array1, CSortedArray& array1Not, CSortedArray& array2, CSortedArray& array2Not, CSortedArray& output) { unsigned array1Index = 0; unsigned array2Index = 0; // walk through both arrays, always adding smallest value to new array
while (array1Index < array1.Size() && array2Index < array2.Size()) { if (array1.GetAt(array1Index) == array2.GetAt(array2Index)) { // found match, add to array & bump up both cursors
output.Add(array1.GetAt(array1Index)); array1Index++; array2Index++; } else if (array2.GetAt(array2Index) < array1.GetAt(array1Index)) { // add it, but only if it's NOT in the NOT array
if (array2Not.Find(array2.GetAt(array2Index)) != InvalidID) output.Add(array2.GetAt(array2Index)); array2Index++; } else { if (array1Not.Find(array1.GetAt(array1Index)) != InvalidID) output.Add(array1.GetAt(array1Index)); array1Index++; } }
// run out whichever array we didn't finish
while (array1Index < array1.Size()) if (array1Not.Find(array1.GetAt(array1Index)) != InvalidID) output.Add(array1.GetAt(array1Index++));
while (array2Index < array2.Size()) if (array2Not.Find(array2.GetAt(array2Index)) != InvalidID) output.Add(array2.GetAt(array2Index++)); }
void CValueNode::ORarrays(CSortedArray& array1, CSortedArray& array2, CSortedArray& output) { unsigned array1Index = 0; unsigned array2Index = 0; // walk through both arrays, always adding smallest value to new array
while (array1Index < array1.Size() && array2Index < array2.Size()) { if (array1.GetAt(array1Index) == array2.GetAt(array2Index)) { // found match, add to array & bump up both cursors
output.Add(array1.GetAt(array1Index)); array1Index++; array2Index++; } else if (array2.GetAt(array2Index) < array1.GetAt(array1Index)) { // add it
output.Add(array2.GetAt(array2Index)); array2Index++; } else { output.Add(array1.GetAt(array1Index)); array1Index++; } }
// run out whichever array we didn't finish
while (array1Index < array1.Size()) output.Add(array1.GetAt(array1Index++));
while (array2Index < array2.Size()) output.Add(array2.GetAt(array2Index++)); }
// pointers point to arrays that are at the corresponding sizes
// caller is responsible for ensuring that the output array is large enough
// return value #elements inserted into new array;
unsigned CValueNode::ORarrays(QueryID* pArray1, unsigned size1, QueryID* pArray2, unsigned size2, QueryID* pOutput) { unsigned nElements = 0;
// if ((pArray1 == NULL) && (pArray2 == NULL))
// really shouldn't happen - one side has should have come from this
// else
if (pArray2 == NULL) { nElements = size1; memcpy(pOutput, pArray1, sizeof(QueryID) * size1); } else if (pArray2 == NULL) { nElements = size1; memcpy(pOutput, pArray1, sizeof(QueryID) * size1); } else { QueryID* pQID1 = pArray1; QueryID* pQID2 = pArray2; QueryID* pOut = pOutput;
// note that the 'ends' are really one past the end, careful now...
QueryID* pEnd1 = pQID1 + size1; QueryID* pEnd2 = pQID2 + size2;
// walk through both arrays, always adding smallest value to new array
while ((pQID1 < pEnd1) && (pQID2 < pEnd2)) { if (*pQID1 == *pQID2) { // found match, add to array & bump up both cursors
*pOut++ = *pQID1++; pQID2++; nElements++; } else if (*pQID2 < *pQID1) { // add it
*pOut++ = *pQID2++; nElements++; } else { // other side must be smaller, add IT.
*pOut++ = *pQID1++; nElements++; } }
// run out whichever array we didn't finish
// only one should ever hit
while (pQID1 < pEnd1) { *pOut++ = *pQID1++; nElements++; } while (pQID2 < pEnd2) { *pOut++ = *pQID2++; nElements++; } }
return nElements; }
void CValueNode::ANDarrays(CSortedArray& array1, CSortedArray& array2, CSortedArray& output) { // going to march down both arrays
// only put value in new array if it appears in both.
unsigned array1Index = 0; unsigned array2Index = 0;
while (array1Index < array1.Size() && array2Index < array2.Size()) { if (array1.GetAt(array1Index) == array2.GetAt(array2Index)) { // found match, add to array & bump up both cursors
output.Add(array1.GetAt(array1Index)); array1Index++; array2Index++; } else if (array1.GetAt(array1Index) > array2.GetAt(array2Index)) array2Index++; else array1Index++; } }
unsigned CValueNode::ANDarrays(QueryID* pArray1, unsigned size1, QueryID* pArray2, unsigned size2, QueryID* pOutput) { unsigned nElements = 0; if ((pArray1 != NULL) && (pArray2 != NULL)) {
QueryID* pQID1 = pArray1; QueryID* pQID2 = pArray2; QueryID* pOut = pOutput;
// note that the 'ends' are really one past the end, careful now...
QueryID* pEnd1 = pQID1 + size1; QueryID* pEnd2 = pQID2 + size2;
// walk through both arrays, adding any values that appear in both
while ((pQID1 < pEnd1) && (pQID2 < pEnd2)) { if (*pQID1 == *pQID2) { // found match, add to array & bump up both cursors
*pOut++ = *pQID1++; pQID2++; nElements++; } else if (*pQID2 < *pQID1) pQID2++; else pQID1++; } }
return nElements; }
void CValueNode::CombineArrays(CSortedArray& array1, CSortedArray& array2, CSortedArray& output) { // march down both arrays
unsigned array1Index = 0; unsigned array2Index = 0;
while (array1Index < array1.Size() && array2Index < array2.Size()) { if (array1.GetAt(array1Index) == array2.GetAt(array2Index)) { // found match, add to array & bump up both cursors
output.Add(array1.GetAt(array1Index)); array1Index++; array2Index++; } else if (array1.GetAt(array1Index) > array2.GetAt(array2Index)) { output.Add(array2.GetAt(array2Index)); array2Index++; } else { output.Add(array1.GetAt(array1Index)); array1Index++; } } // run out whichever array we didn't finish
while (array1Index < array1.Size()) output.Add(array1.GetAt(array1Index++));
while (array2Index < array2.Size()) output.Add(array2.GetAt(array2Index++)); }
unsigned CValueNode::CombineArrays(QueryID* pArray1, unsigned size1, QueryID* pArray2, unsigned size2, QueryID* pOutput) { unsigned nElements = 0; // if ((pArray1 == NULL) && (pArray2 == NULL))
// really shouldn't happen - one side has should have come from this
// else
if (pArray2 == NULL) { nElements = size1; memcpy(pOutput, pArray1, sizeof(QueryID) * size1); } else if (pArray1 == NULL) { nElements = size2; memcpy(pOutput, pArray2, sizeof(QueryID) * size2); } else { QueryID* pQID1 = pArray1; QueryID* pQID2 = pArray2; QueryID* pOut = pOutput;
// note that the 'ends' are really one past the end, careful now...
QueryID* pEnd1 = pQID1 + size1; QueryID* pEnd2 = pQID2 + size2;
while ((pQID1 < pEnd1) && (pQID2 < pEnd2)) { if (*pQID1 == *pQID2) { // found match, add to array & bump up both cursors
*pOut++ = *pQID1++; pQID2++; nElements++; } else if (*pQID2 < *pQID1) { // add it
*pOut++ = *pQID2++; nElements++; } else { // other side must be smaller, add IT.
*pOut++ = *pQID1++; nElements++; } }
// run out whichever array we didn't finish
// only one should ever hit
while (pQID1 < pEnd1) { *pOut++ = *pQID1++; nElements++; } while (pQID2 < pEnd2) { *pOut++ = *pQID2++; nElements++; } }
return nElements; }
// size of new arrays is predicated on the assumption that
// there will usually be more TRUE nodes than INVALID ones
HRESULT CValueNode::CombineWith(CEvalNode* pRawArg2, int nOp, CContextMetaData* pNamespace, CImplicationList& Implications, bool bDeleteThis, bool bDeleteArg2, CEvalNode** ppRes) { HRESULT hRes = WBEM_S_NO_ERROR; CValueNode* pArg2 = (CValueNode*)pRawArg2;
// Check for immediate solutions
// =============================
if(nOp != EVAL_OP_AND) { if(IsAllFalse(pArg2) && bDeleteThis) { // Just return this!
// =================
*ppRes = this; if(bDeleteArg2) delete pArg2; return WBEM_S_NO_ERROR; } else if(IsAllFalse(this) && bDeleteArg2) { // Just return arg2!
// =================
*ppRes = pRawArg2; if(bDeleteThis) delete this; return WBEM_S_NO_ERROR; } }
// if we got enough room in a stack array, we'll use that,
// elsewise we'll allocate one from the heap
const unsigned NewArraySize = 128; QueryID newArray[NewArraySize]; QueryID* pNewArray = newArray; CDeleteMe<QueryID> deleteMe;
CValueNode* pNew; unsigned nElements;
unsigned arg2Values; QueryID* arg2Array; if (pArg2) { arg2Values = pArg2->m_nValues; arg2Array = pArg2->m_trueIDs; } else { arg2Values = 0; arg2Array = NULL; }
if (nOp == EVAL_OP_AND) { if (max(m_nValues, arg2Values) > NewArraySize) { pNewArray = new QueryID[max(m_nValues, arg2Values)]; if(pNewArray == NULL) return WBEM_E_OUT_OF_MEMORY; deleteMe = pNewArray; } nElements = ANDarrays(m_trueIDs, m_nValues, arg2Array, arg2Values, pNewArray); } // HMH: it sure looks to me like OR and COMBINE are the same for this case
// I'm too afraid to risk changing it, tho
else if (nOp == EVAL_OP_OR) { if (max(m_nValues, arg2Values) > NewArraySize) { pNewArray = new QueryID[max(m_nValues, arg2Values)]; if(pNewArray == NULL) return WBEM_E_OUT_OF_MEMORY; deleteMe = pNewArray; }
nElements = ORarrays(m_trueIDs, m_nValues, arg2Array, arg2Values, pNewArray); } else if ((nOp == EVAL_OP_COMBINE) || (nOp == EVAL_OP_INVERSE_COMBINE)) { if ((m_nValues + arg2Values) > NewArraySize) { pNewArray = new QueryID[m_nValues + arg2Values]; if(pNewArray == NULL) return WBEM_E_OUT_OF_MEMORY; deleteMe = pNewArray; }
nElements = CombineArrays(m_trueIDs, m_nValues, arg2Array, arg2Values, pNewArray); }
// check to see if we can reuse a node, note this could result in the array 'shrinking'
if (nElements == 0) *ppRes = NULL; else if (bDeleteThis && (nElements <= m_nValues)) { *ppRes = this; memcpy(m_trueIDs, pNewArray, nElements * sizeof(QueryID)); m_nValues = nElements; bDeleteThis = false; } else if (bDeleteArg2 && pArg2 && (nElements <= pArg2->m_nValues)) { *ppRes = pArg2; memcpy(pArg2->m_trueIDs, pNewArray, nElements * sizeof(QueryID)); pArg2->m_nValues = nElements; bDeleteArg2 = false; } else if (pNew = CreateNode(nElements)) { // can't reuse one, start a new one
*ppRes = pNew; memcpy(pNew->m_trueIDs, pNewArray, nElements * sizeof(QueryID)); } else hRes = WBEM_E_OUT_OF_MEMORY;
// Delete what needed deletion
// ===========================
// deleteMe will take care of the array pointer if allocated
if(bDeleteThis) delete this; if(bDeleteArg2) delete pArg2;
return WBEM_S_NO_ERROR; }
//static
bool CValueNode::IsNoop(CValueNode* pNode, int nOp) { if(nOp == EVAL_OP_OR) return IsAllFalse(pNode); else if(nOp == EVAL_OP_AND) return false; // BUGBUG: would be nice to have IsAllTrue, but can't
else if(nOp == EVAL_OP_COMBINE || nOp == EVAL_OP_INVERSE_COMBINE) return IsAllFalse(pNode); else { //?
return false; } }
HRESULT CValueNode::TryShortCircuit(CEvalNode* pArg2, int nOp, bool bDeleteThis, bool bDeleteArg2, CEvalNode** ppRes) { if(IsAllFalse(this)) { if(nOp == EVAL_OP_AND) { // FALSE & X is FALSE
if(bDeleteThis) *ppRes = this; else { *ppRes = Clone(); if(*ppRes == NULL) return WBEM_E_OUT_OF_MEMORY; } if(bDeleteArg2) delete pArg2; return WBEM_S_NO_ERROR; } else // OR and COMBINE are identical in this case
{ // FALSE | X is X
//
// Well, this is true, but the problem is with optimizations.
// Some branches in X might not be valid under the implications in
// this branch of the tree, and so need to be removed. For now, I
// will simply turn off this short-circuiting path. It may turn out
// that there are some critical performance gains to be had by
// keeping it, in which case we would need to put this back and
// make an efficient pass through it, checking branches.
//
return WBEM_S_FALSE; /*
if(bDeleteArg2) *ppRes = pArg2; else if (pArg2) { *ppRes = pArg2->Clone(); if(*ppRes == NULL) return WBEM_E_OUT_OF_MEMORY; } else *ppRes = NULL;
if(bDeleteThis) delete this; return WBEM_S_NO_ERROR; */ } } return WBEM_S_FALSE; }
HRESULT CValueNode::Project(CContextMetaData* pMeta, CImplicationList& Implications, CProjectionFilter* pFilter, EProjectionType eType, bool bDeleteThis, CEvalNode** ppNewNode) { //
// Projection of a constant is, again, a constant
//
if(bDeleteThis) { *ppNewNode = this; } else { *ppNewNode = Clone(); if(*ppNewNode == NULL) return WBEM_E_OUT_OF_MEMORY; } return S_OK; }
CEvalNode* CValueNode::Clone() const { CValueNode* pNew; if (pNew = CreateNode(m_nValues)) memcpy(pNew->m_trueIDs, m_trueIDs, m_nValues * sizeof(QueryID));
return pNew; }
int CValueNode::Compare(CEvalNode* pRawOther) { if (!pRawOther) return m_nValues; CValueNode* pOther = (CValueNode*)pRawOther; int nCompare = m_nValues - pOther->m_nValues;
if ((nCompare == 0) && (m_nValues != 0)) nCompare = memcmp(m_trueIDs, pOther->m_trueIDs, m_nValues * sizeof(QueryID));
return nCompare; }
CValueNode* CValueNode::GetStandardTrue() { CValueNode* pNew = CreateNode(1); if(pNew) pNew->m_trueIDs[0] = 0;
return pNew; }
CValueNode* CValueNode::GetStandardInvalid() { return new CInvalidNode; }
/*static*/ CValueNode* CValueNode::CreateNode(size_t nNumValues) { return new(nNumValues) CValueNode; }
/*static*/ CValueNode* CValueNode::CreateNode(CSortedArray& values) { CValueNode* pNode; pNode = new(values.Size()) CValueNode; if (pNode) values.CopyTo(pNode->m_trueIDs, values.Size());
return pNode; }
void* CValueNode::operator new( size_t stAllocateBlock, unsigned nEntries) { void *pvTemp; if (pvTemp = ::new byte[ stAllocateBlock + ((nEntries ==0)? 0 : ((nEntries -1)* sizeof(QueryID)))] ) ((CValueNode*)pvTemp)->m_nValues = nEntries;
return pvTemp; }
// VC 5 only allows one delete operator per class
#if _MSC_VER >= 1200
void CValueNode::operator delete( void *p, unsigned nEntries ) { ::delete[] (byte*)p; } #endif
void CValueNode::Dump(FILE* f, int nOffset) { PrintOffset(f, nOffset); fprintf(f, "TRUE: ");
for (int i = 0; i < m_nValues; i++) { fprintf(f, "%u", m_trueIDs[i]); if(i < m_nValues-1) fprintf(f, ", %u", m_trueIDs[i]); }
fprintf(f, "\n"); }
void CInvalidNode::Dump(FILE* f, int nOffset) { PrintOffset(f, nOffset); fprintf(f, "Invalid node (0x%p)\n", this); } //******************************************************************************
//******************************************************************************
// EMBEDDING INFO
//******************************************************************************
//******************************************************************************
CEmbeddingInfo::CEmbeddingInfo() : m_lNumJumps(0), m_aJumps(NULL), m_lStartingObjIndex(0) { }
CEmbeddingInfo::CEmbeddingInfo(const CEmbeddingInfo& Other) : m_lNumJumps(0), m_aJumps(NULL), m_lStartingObjIndex(0) { *this = Other; }
void CEmbeddingInfo::operator=(const CEmbeddingInfo& Other) { m_EmbeddedObjPropName = Other.m_EmbeddedObjPropName; m_lNumJumps = Other.m_lNumJumps; m_lStartingObjIndex = Other.m_lStartingObjIndex;
delete [] m_aJumps;
if(m_lNumJumps > 0) { m_aJumps = new JumpInfo[m_lNumJumps]; if (m_aJumps == NULL) throw CX_MemoryException(); memcpy(m_aJumps, Other.m_aJumps, m_lNumJumps * sizeof(JumpInfo)); } else m_aJumps = NULL; }
CEmbeddingInfo::~CEmbeddingInfo() { delete [] m_aJumps; }
bool CEmbeddingInfo::IsEmpty() const { return (m_EmbeddedObjPropName.GetNumElements() == 0); }
bool CEmbeddingInfo::SetPropertyNameButLast(const CPropertyName& Name) { try { m_EmbeddedObjPropName.Empty(); for(int i = 0; i < Name.GetNumElements() - 1; i++) { m_EmbeddedObjPropName.AddElement(Name.GetStringAt(i)); } return true; } catch (CX_MemoryException) { return false; } }
int CEmbeddingInfo::ComparePrecedence(const CEmbeddingInfo* pOther) { if (pOther) { int nCompare = m_EmbeddedObjPropName.GetNumElements() - pOther->m_EmbeddedObjPropName.GetNumElements(); if(nCompare) return nCompare; for(int i = 0; i < m_EmbeddedObjPropName.GetNumElements(); i++) { nCompare = wbem_wcsicmp(m_EmbeddedObjPropName.GetStringAt(i), pOther->m_EmbeddedObjPropName.GetStringAt(i)); if(nCompare) return nCompare; } }
return 0; }
BOOL CEmbeddingInfo::operator==(const CEmbeddingInfo& Other) { if(m_lStartingObjIndex != Other.m_lStartingObjIndex) return FALSE; if(m_lNumJumps != Other.m_lNumJumps) return FALSE; if(m_aJumps == NULL) { if(Other.m_aJumps == NULL) return TRUE; else return FALSE; } else { if(Other.m_aJumps == NULL) return FALSE; else return (memcmp(m_aJumps, Other.m_aJumps, m_lNumJumps * sizeof(JumpInfo)) == 0); } } HRESULT CEmbeddingInfo::Compile( CContextMetaData* pNamespace, CImplicationList& Implications, _IWmiObject** ppResultClass ) { HRESULT hres;
long lFirstUnknownProp; _IWmiObject* pContainerClass;
hres = Implications.FindBestComputedContainer( &m_EmbeddedObjPropName, &lFirstUnknownProp, &m_lStartingObjIndex, &pContainerClass );
if(FAILED(hres)) return hres;
int nNumEmbeddedJumps = m_EmbeddedObjPropName.GetNumElements();
if(lFirstUnknownProp < nNumEmbeddedJumps) { // Not everything is already loaded
// ================================
delete [] m_aJumps; m_lNumJumps = nNumEmbeddedJumps - lFirstUnknownProp; m_aJumps = new JumpInfo[m_lNumJumps]; if (!m_aJumps) return WBEM_E_OUT_OF_MEMORY;
JumpInfo* pji = NULL;
for(int i = lFirstUnknownProp; i < nNumEmbeddedJumps; i++) { if(pContainerClass == NULL) return WBEMESS_E_REGISTRATION_TOO_BROAD;
// Get the handle of this property
// ===============================
CIMTYPE ct;
pji = m_aJumps + i - lFirstUnknownProp; pji->lTarget = -1;
hres = pContainerClass->GetPropertyHandleEx( (LPWSTR)m_EmbeddedObjPropName.GetStringAt(i), 0L, &ct, &pji->lJump );
if(FAILED(hres) || ct != CIM_OBJECT) { // Invalid. Return
pContainerClass->Release(); return WBEM_E_INVALID_PROPERTY; }
//
// Check if the implications know anything about the class name
// for this property
//
_IWmiObject* pNewContainerClass = NULL; hres = Implications.FindClassForProp(&m_EmbeddedObjPropName, i+1, &pNewContainerClass); if(FAILED(hres)) { //
// Nothing implied --- have to go with the CIMTYPE qualifier
//
//
// Get CIMTYPE qualifier
//
CVar vCimtype; DWORD dwSize; hres = pContainerClass->GetPropQual( (LPWSTR)m_EmbeddedObjPropName.GetStringAt(i), L"CIMTYPE", 0, 0, NULL, NULL, &dwSize, NULL); if(hres != WBEM_E_BUFFER_TOO_SMALL) return WBEM_E_INVALID_PROPERTY; LPWSTR wszCimType = (LPWSTR)new BYTE[dwSize]; if(wszCimType == NULL) return WBEM_E_OUT_OF_MEMORY; CVectorDeleteMe<BYTE> vdm((BYTE*)wszCimType); CIMTYPE ctQualType; hres = pContainerClass->GetPropQual( (LPWSTR)m_EmbeddedObjPropName.GetStringAt(i), L"CIMTYPE", 0, dwSize, &ctQualType, NULL, &dwSize, wszCimType); if(FAILED(hres) || ctQualType != CIM_STRING) return WBEM_E_INVALID_PROPERTY;
//
// Figure out what it references, if available
//
WCHAR* pwc = wcschr(wszCimType, L':'); if(pwc) { // Information about the class is available
// ========================================
hres = pNamespace->GetClass(pwc+1, &pNewContainerClass); if(FAILED(hres)) { return WBEM_E_INVALID_CIM_TYPE; } } }
pContainerClass->Release(); pContainerClass = pNewContainerClass; }
// Get a location for the result and store in the last jump info elem
// ==================================================================
Implications.AddComputation( m_EmbeddedObjPropName, pContainerClass, &pji->lTarget ); } else { // Everything is covered
// =====================
delete [] m_aJumps; m_aJumps = NULL; m_lNumJumps = 0; }
if(ppResultClass) { *ppResultClass = pContainerClass; } else { if(pContainerClass) pContainerClass->Release(); }
return WBEM_S_NO_ERROR; }
HRESULT CEmbeddingInfo::GetContainerObject( CObjectInfo& ObjInfo, INTERNAL _IWmiObject** ppInst) { if( m_lNumJumps == 0 ) { *ppInst = ObjInfo.GetObjectAt(m_lStartingObjIndex); return WBEM_S_NO_ERROR; }
_IWmiObject* pCurrent = ObjInfo.GetObjectAt(m_lStartingObjIndex); pCurrent->AddRef(); for(int i = 0; i < m_lNumJumps; i++) { _IWmiObject* pNew = NULL; HRESULT hres = pCurrent->GetPropAddrByHandle( m_aJumps[i].lJump, 0, NULL, ( void** )&pNew );
if( FAILED( hres ) ) { return hres; } pCurrent->Release(); pCurrent = pNew; if(pNew == NULL) { *ppInst = pCurrent; return WBEM_S_FALSE; }
//
// save the object if required.
//
if ( m_aJumps[i].lTarget != -1 ) { ObjInfo.SetObjectAt( m_aJumps[i].lTarget, pCurrent ); } }
*ppInst = pCurrent; return WBEM_S_NO_ERROR; }
bool CEmbeddingInfo::AreJumpsRelated(const CEmbeddingInfo* pInfo) { if ( !pInfo ) { return false; }
//
// look through the targets of the info and see if we depend on any.
//
for( int i=0; i < pInfo->m_lNumJumps; i++ ) { if ( pInfo->m_aJumps[i].lTarget == m_lStartingObjIndex ) { return true; } }
return false; }
bool CEmbeddingInfo::MixInJumps(const CEmbeddingInfo* pInfo) { //
// Assumes AreJumpsRelated() has been called and returned TRUE.
//
m_lStartingObjIndex = pInfo->m_lStartingObjIndex;
JumpInfo* aNewJumps = new JumpInfo[m_lNumJumps + pInfo->m_lNumJumps]; if(aNewJumps == NULL) return false;
if( pInfo->m_lNumJumps > 0 ) { memcpy( aNewJumps, pInfo->m_aJumps, sizeof(JumpInfo)*(pInfo->m_lNumJumps) ); }
if( m_lNumJumps > 0 ) { memcpy( aNewJumps + pInfo->m_lNumJumps, m_aJumps, sizeof(JumpInfo)*m_lNumJumps ); }
m_lNumJumps += pInfo->m_lNumJumps;
delete [] m_aJumps; m_aJumps = aNewJumps;
return true; }
void CEmbeddingInfo::Dump(FILE* f) { fprintf(f, "Name="); int i; for(i = 0; i < m_EmbeddedObjPropName.GetNumElements(); i++) { if(i != 0) fprintf(f, "."); fprintf(f, "%S", m_EmbeddedObjPropName.GetStringAt(i)); }
fprintf(f, ", Alg=%d -> (", m_lStartingObjIndex); for(i = 0; i < m_lNumJumps; i++) { if(i != 0) fprintf(f, ", "); fprintf(f, "0x%x : %d", m_aJumps[i].lJump, m_aJumps[i].lTarget ); } fprintf(f, ")"); } //******************************************************************************
//******************************************************************************
// BRANCHING NODE
//******************************************************************************
//******************************************************************************
CNodeWithImplications::CNodeWithImplications(const CNodeWithImplications& Other) : CEvalNode(Other), m_pExtraImplications(NULL) { if(Other.m_pExtraImplications) { m_pExtraImplications = new CImplicationList(*Other.m_pExtraImplications, false); // no link
if(m_pExtraImplications == NULL) throw CX_MemoryException(); } }
void CNodeWithImplications::Dump(FILE* f, int nOffset) { if(m_pExtraImplications) m_pExtraImplications->Dump(f, nOffset); }
CBranchingNode::CBranchingNode() : CNodeWithImplications(), m_pNullBranch(NULL), m_pInfo(NULL) { m_pNullBranch = CValueNode::GetStandardFalse(); }
CBranchingNode::CBranchingNode(const CBranchingNode& Other, BOOL bChildren) : CNodeWithImplications(Other), m_pInfo(NULL) { if (Other.m_pInfo) { m_pInfo = new CEmbeddingInfo(*(Other.m_pInfo)); if(m_pInfo == NULL) throw CX_MemoryException(); }
int i; if(bChildren) { m_pNullBranch = (CBranchingNode*)CloneNode(Other.m_pNullBranch); if(m_pNullBranch == NULL && Other.m_pNullBranch != NULL) throw CX_MemoryException();
for(i = 0; i < Other.m_apBranches.GetSize(); i++) { CBranchingNode* pNewBranch = (CBranchingNode*)CloneNode(Other.m_apBranches[i]);
if(pNewBranch == NULL && Other.m_apBranches[i] != NULL) throw CX_MemoryException();
if(m_apBranches.Add(pNewBranch) < 0) throw CX_MemoryException(); } } else { m_pNullBranch = CValueNode::GetStandardFalse(); } }
/* virtual */ int CBranchingNode::GetType() { return EVAL_NODE_TYPE_BRANCH; }
CBranchingNode::~CBranchingNode() { delete m_pNullBranch; delete m_pInfo; }
bool CBranchingNode::MixInJumps( const CEmbeddingInfo* pJump ) { bool bRet;
if ( !pJump ) { return true; }
//
// we want to find the first node in the tree that is related to the
// ancestor embedding info. If this node is related, then we mix in the
// jumps and return. If not, then we propagate the info down the tree.
//
if ( m_pInfo ) { if ( m_pInfo->AreJumpsRelated( pJump ) ) { return m_pInfo->MixInJumps( pJump ); } }
for(int i = 0; i < m_apBranches.GetSize(); i++) { if ( CEvalNode::GetType(m_apBranches[i]) == EVAL_NODE_TYPE_BRANCH ) { if ( !((CBranchingNode*)m_apBranches[i])->MixInJumps( pJump ) ) { return false; } } }
return true; }
bool CBranchingNode::SetEmbeddedObjPropName(CPropertyName& Name) { try { if (!m_pInfo) { m_pInfo = new CEmbeddingInfo; if(m_pInfo == NULL) return false; } m_pInfo->SetEmbeddedObjPropName(Name); return true; } catch (CX_MemoryException) { return false; } }
void CBranchingNode::SetNullBranch(CEvalNode* pBranch) { delete m_pNullBranch; m_pNullBranch = pBranch; }
DELETE_ME CBranchIterator* CBranchingNode::GetBranchIterator() { return new CDefaultBranchIterator(this); }
int CBranchingNode::ComparePrecedence(CBranchingNode* pArg1, CBranchingNode* pArg2) { int nCompare; nCompare = pArg1->GetSubType() - pArg2->GetSubType(); if(nCompare) return nCompare;
// Compare embedding specs
// =======================
if (pArg1->m_pInfo && pArg2->m_pInfo) { nCompare = pArg1->m_pInfo->ComparePrecedence(pArg2->m_pInfo); if(nCompare) return nCompare; } else if (pArg2->m_pInfo) return -1; else if (pArg1->m_pInfo) return 1;
// Embedding are the same --- compare lower levels
// ===============================================
return pArg1->ComparePrecedence(pArg2); } DWORD CBranchingNode::ApplyPredicate(CLeafPredicate* pPred) { DWORD dwRes; for(int i = 0; i < m_apBranches.GetSize(); i++) { if(m_apBranches[i] == NULL) dwRes = (*pPred)(NULL); else dwRes = m_apBranches[i]->ApplyPredicate(pPred);
if(dwRes & WBEM_DISPOSITION_FLAG_DELETE) { m_apBranches.SetAt(i, NULL); dwRes &= ~WBEM_DISPOSITION_FLAG_DELETE; }
if(dwRes & WBEM_DISPOSITION_FLAG_INVALIDATE) { m_apBranches.SetAt(i, CValueNode::GetStandardInvalid()); dwRes &= ~WBEM_DISPOSITION_FLAG_INVALIDATE; }
if(dwRes == WBEM_DISPOSITION_STOPLEVEL) return WBEM_DISPOSITION_NORMAL; if(dwRes == WBEM_DISPOSITION_STOPALL) return dwRes; }
if(m_pNullBranch) dwRes = m_pNullBranch->ApplyPredicate(pPred); else dwRes = (*pPred)(NULL);
if(dwRes & WBEM_DISPOSITION_FLAG_DELETE) { delete m_pNullBranch; m_pNullBranch = NULL; dwRes &= ~WBEM_DISPOSITION_FLAG_DELETE; } if(dwRes & WBEM_DISPOSITION_FLAG_INVALIDATE) { delete m_pNullBranch; m_pNullBranch = CValueNode::GetStandardInvalid(); dwRes &= ~WBEM_DISPOSITION_FLAG_INVALIDATE; }
if(dwRes == WBEM_DISPOSITION_STOPALL) return dwRes; return WBEM_DISPOSITION_NORMAL; } HRESULT CBranchingNode::Project(CContextMetaData* pMeta, CImplicationList& Implications, CProjectionFilter* pFilter, EProjectionType eType, bool bDeleteThis, CEvalNode** ppNewNode) { HRESULT hres;
try { //
// Record what we learn by even getting here
//
CImplicationList TheseImplications(Implications); if(GetExtraImplications()) { hres = TheseImplications.MergeIn(GetExtraImplications()); if(FAILED(hres)) return hres; } // BUGBUG: we could be more efficient and not clone the node when
// bDeleteThis is not specified.
CBranchingNode* pNew; if(bDeleteThis) { pNew = this; } else { pNew = (CBranchingNode*)Clone(); if(pNew == NULL) return WBEM_E_OUT_OF_MEMORY; } // BUGBUG: it is not always necessary to project all children. Could be
// more efficient, but can't find the perfect algorithm...
//
// Project all our children
//
CBranchIterator* pit = pNew->GetBranchIterator(); if(pit == NULL) return WBEM_E_OUT_OF_MEMORY;
CDeleteMe<CBranchIterator> dm(pit); while(pit->IsValid()) { if(CEvalNode::IsInvalid(pit->GetNode())) continue; CImplicationList BranchImplications(TheseImplications); pit->RecordBranch(pMeta, BranchImplications); CEvalNode* pNewBranch; hres = CEvalTree::Project(pMeta, BranchImplications, pit->GetNode(), pFilter, eType, true, &pNewBranch); if(FAILED(hres)) return hres; pit->SetNode(pNewBranch); // old one already deleted
pit->Advance(); } //
// Determine if this is an "in" node for this filter
//
bool bIn = pFilter->IsInSet(this); if(bIn) { //
// For nodes martching the filter that's it --- both necessary and
// sufficient conditions are simply projections of what's below
//
*ppNewNode = pNew; } else { //
// The node does not match the filter. Now is when the difference
// between sufficient and necessary conditions applies
//
int nBranchOp; if(eType == e_Sufficient) { //
// For a condition to be sufficient for the truth of the entire
// node, it should appear in every single branch of the node.
// Therefore, we must AND all the branches together. Except for
// invalid ones --- they can't happen, so we can omit them from
// the analysis
//
nBranchOp = EVAL_OP_AND; } else if(eType == e_Necessary) { //
// For a condition to be necessary for this node, it has to
// appear in at least one branch. Therefore, we must OR all
// the branches together. Except for invalid ones.
//
nBranchOp = EVAL_OP_OR; } else return WBEM_E_INVALID_PARAMETER; //
// Perform the needed operation on them all
//
CBranchIterator* pitInner = pNew->GetBranchIterator(); if(pitInner == NULL) return WBEM_E_OUT_OF_MEMORY;
CDeleteMe<CBranchIterator> dm(pitInner); //
// Merge all of the, in, one at a time, deleting them as we go.
// It is safe to delete them always, since we cloned the entire node
// in the beginning if deletion was not allowed.
//
CEvalNode* pCombination = NULL; bool bInited = false; while(pitInner->IsValid()) { if(CEvalNode::IsInvalid(pitInner->GetNode())) continue; if(bInited) { hres = CEvalTree::Combine(pCombination, pitInner->GetNode(), nBranchOp, pMeta, Implications, true, true, &pCombination); if(FAILED(hres)) return hres; } else { pCombination = pitInner->GetNode(); bInited = true; } pitInner->SetNode(NULL); pitInner->Advance(); } if(!bInited) { //
// No valid nodes??
//
pCombination = CValueNode::GetStandardInvalid(); } //
// The combination is it.
//
*ppNewNode = pCombination; delete pNew; } } catch (CX_MemoryException) { return WBEM_E_OUT_OF_MEMORY; }
return S_OK; } int CBranchingNode::Compare(CEvalNode* pRawOther) { CBranchingNode* pOther = (CBranchingNode*)pRawOther;
int nCompare; nCompare = GetSubType() - pOther->GetSubType(); if(nCompare) return nCompare;
// First, compare embeddings
// =========================
if(m_pInfo == NULL && pOther->m_pInfo != NULL) return -1;
if(m_pInfo != NULL && pOther->m_pInfo == NULL) return 1;
if(m_pInfo != NULL && pOther->m_pInfo != NULL) { nCompare = m_pInfo->ComparePrecedence(pOther->m_pInfo); if(nCompare) return nCompare; }
if(m_apBranches.GetSize() != pOther->m_apBranches.GetSize()) return m_apBranches.GetSize() - pOther->m_apBranches.GetSize();
// Then, compare derived portions
// ==============================
nCompare = SubCompare(pOther); if(nCompare) return nCompare;
// Finally, compare children
// =========================
for(int i = 0; i < m_apBranches.GetSize(); i++) { nCompare = CEvalTree::Compare(m_apBranches[i], pOther->m_apBranches[i]); if(nCompare) return nCompare; }
return 0; }
HRESULT CBranchingNode::CombineWith(CEvalNode* pRawArg2, int nOp, CContextMetaData* pNamespace, CImplicationList& Implications, bool bDeleteThis, bool bDeleteArg2, CEvalNode** ppRes) { CBranchingNode* pArg2 = (CBranchingNode*)pRawArg2; HRESULT hres;
// Compare arguments for precedence
// ================================
int nCompare = ComparePrecedence(this, pArg2); if(nCompare < 0) { // Put pArg1 first and continue
// ============================
hres = CombineInOrderWith(pArg2, nOp, pNamespace, Implications, bDeleteThis, bDeleteArg2, ppRes); } else if(nCompare > 0) { // Put pArg2 first and continue (reverse delete indicators!!)
// ==========================================================
hres = pArg2->CombineInOrderWith(this, FlipEvalOp(nOp), pNamespace, Implications, bDeleteArg2, bDeleteThis, ppRes); } else { // They are about the same property. Combine lookup lists.
// =======================================================
hres = CombineBranchesWith(pArg2, nOp, pNamespace, Implications, bDeleteThis, bDeleteArg2, ppRes); }
return hres; }
HRESULT CBranchingNode::CombineInOrderWith(CEvalNode* pArg2, int nOp, CContextMetaData* pNamespace, CImplicationList& OrigImplications, bool bDeleteThis, bool bDeleteArg2, CEvalNode** ppRes) { HRESULT hres; CBranchingNode* pNew = NULL;
if(bDeleteThis) { pNew = this; } else { //
// I'd like to clone self here, but can't because there is no
// such virtual method. Something to be improved, perhaps
//
pNew = (CBranchingNode*)Clone(); if(pNew == NULL) return WBEM_E_OUT_OF_MEMORY; }
try { CImplicationList Implications(OrigImplications); hres = pNew->AdjustCompile(pNamespace, Implications); if(FAILED(hres)) return hres; //
// Maintain a counter telling us whether any invalid branches (that
// cannot occur under these implications) were detected. If so, we
// need to re-optimize this node
//
bool bInvalidBranchesDetected = false; for(int i = 0; i < m_apBranches.GetSize(); i++) { CEvalNode* pNewBranch = NULL; CImplicationList BranchImplications(Implications); hres = RecordBranch(pNamespace, BranchImplications, i); if(SUCCEEDED(hres)) { // Always delete the branch --- if bDeleteThis, we should, and
// if not, we cloned it!
hres = CEvalTree::Combine(pNew->m_apBranches[i], pArg2, nOp, pNamespace, BranchImplications, true, false, &pNewBranch); if(FAILED(hres)) { delete pNew; return hres; } pNew->m_apBranches.Discard(i); } else { pNewBranch = CValueNode::GetStandardInvalid(); bInvalidBranchesDetected = true; } pNew->m_apBranches.SetAt(i, pNewBranch); } CEvalNode* pNewBranch = NULL; CImplicationList BranchImplications(Implications); hres = RecordBranch(pNamespace, BranchImplications, -1); if(SUCCEEDED(hres)) { //
// Always delete the branch --- if bDeleteThis, we should, and
// if not, we cloned it!
//
hres = CEvalTree::Combine(pNew->GetNullBranch(), pArg2, nOp, pNamespace, BranchImplications, true, false, &pNewBranch); if(FAILED(hres)) { delete pNew; return hres; } pNew->m_pNullBranch = NULL; } else { pNewBranch = CValueNode::GetStandardInvalid(); bInvalidBranchesDetected = true; } pNew->SetNullBranch(pNewBranch); if(bDeleteArg2) delete pArg2; //
// If invalid branches were cut, re-optimize
//
if(bInvalidBranchesDetected) { HRESULT hr = pNew->Optimize(pNamespace, ppRes); if (*ppRes != pNew) delete pNew; return hr; } else { *ppRes = pNew; return WBEM_S_NO_ERROR; } } catch (CX_MemoryException) { return WBEM_E_OUT_OF_MEMORY; } }
BOOL CBranchingNode::AreAllSame(CEvalNode** apNodes, int nSize, int* pnFoundIndex) { BOOL bFoundTwo = FALSE;
*pnFoundIndex = -1; CEvalNode* pFound = NULL;
for(int i = 0; i < nSize; i++) { // ignore invalid nodes --- they don't count
if(CEvalNode::IsInvalid(apNodes[i])) continue;
if(*pnFoundIndex == -1) { //
// This is the first valid chils this node has. Record it --- it
// might be the only one
//
*pnFoundIndex = i; pFound = apNodes[i]; } else if(CEvalTree::Compare(apNodes[i], pFound) != 0) { bFoundTwo = TRUE; break; } }
return !bFoundTwo; }
HRESULT CBranchingNode::StoreBranchImplications(CContextMetaData* pNamespace, int nBranchIndex, CEvalNode* pResult) { if(pResult) { CImplicationList* pBranchImplications = NULL; try { pBranchImplications = new CImplicationList; if(pBranchImplications == NULL) return WBEM_E_OUT_OF_MEMORY; } catch (CX_MemoryException) { return WBEM_E_OUT_OF_MEMORY; }
HRESULT hres = RecordBranch(pNamespace, *pBranchImplications, nBranchIndex); if(FAILED(hres)) { delete pBranchImplications; return hres; }
if(pBranchImplications->IsEmpty()) { // Nothing useful to say!
delete pBranchImplications; pBranchImplications = NULL; }
pResult->SetExtraImplications(pBranchImplications); // acquires
}
return WBEM_S_NO_ERROR; }
HRESULT CBranchingNode::Optimize(CContextMetaData* pNamespace, CEvalNode** ppNew) { int i; HRESULT hres;
// Optimize all branches
// =====================
for(i = 0; i < m_apBranches.GetSize(); i++) { if(m_apBranches[i]) { CEvalNode* pNew = NULL; m_apBranches[i]->Optimize(pNamespace, &pNew); if(pNew != m_apBranches[i]) { m_apBranches.SetAt(i, pNew); } } }
if(CEvalNode::GetType(m_pNullBranch) == EVAL_NODE_TYPE_BRANCH) { CEvalNode* pNew; ((CBranchingNode*)m_pNullBranch)->Optimize(pNamespace, &pNew); if(pNew != m_pNullBranch) { SetNullBranch(pNew); } }
// Self-optimize
// =============
OptimizeSelf();
// Count the number of branches
// ============================
int nFoundIndex = -1; BOOL bFoundTwo = !AreAllSame(m_apBranches.GetArrayPtr(), m_apBranches.GetSize(), &nFoundIndex);
if(bFoundTwo) { *ppNew = this; return WBEM_S_NO_ERROR; }
if(nFoundIndex == -1) {
if(CEvalNode::IsInvalid(m_pNullBranch)) { //
// Totally invalid, the whole lot
//
*ppNew = m_pNullBranch; m_pNullBranch = NULL; } else { //
// There are no valid branches, except for the NullBranch.
// We can replace ourselves with the NullBranch
//
*ppNew = m_pNullBranch; m_pNullBranch = NULL;
//
// Now, we need to copy
// the branch implications into the "extras". This is because
// the information about which branch was taken in this test is
// critical to the compilation of the lower nodes --- it tells them
// about the classes of some of our embedded objects.
//
hres = StoreBranchImplications(pNamespace, -1, *ppNew); if(FAILED(hres)) return hres; //
// since this node is going away, mix in the embedding info it
// has with the child node.
//
if ( CEvalNode::GetType(*ppNew) == EVAL_NODE_TYPE_BRANCH ) { CBranchingNode* pBranchNode = (CBranchingNode*)*ppNew; if(!pBranchNode->MixInJumps( m_pInfo )) return WBEM_E_OUT_OF_MEMORY; } } } else { //
// There is one valid branch in the regular list. Two hopes: that the
// NullBranch is invalid, or that it is the same as the only valid
// branch in the regular list
//
if(CEvalNode::IsInvalid(m_pNullBranch) || CEvalTree::Compare(m_pNullBranch, m_apBranches[nFoundIndex]) == 0) { //
// Hurray. We could replace ourselves with the remaining branch.
//
m_apBranches.SetAt(nFoundIndex, NULL, ppNew);
//
// Now, we need to copy
// the branch implications into the "extras". This is because
// the information about which branch was taken in this test is
// critical to the compilation of the lower nodes --- it tells them
// about the classes of some of our embedded objects.
//
hres = StoreBranchImplications(pNamespace, nFoundIndex, *ppNew); if(FAILED(hres)) return hres;
//
// since this node is going away, mix in the embedding info it
// has with the child node.
//
if ( CEvalNode::GetType(*ppNew) == EVAL_NODE_TYPE_BRANCH ) { CBranchingNode* pBranchNode = (CBranchingNode*)*ppNew; if(!pBranchNode->MixInJumps( m_pInfo )) return WBEM_E_OUT_OF_MEMORY; } } else { *ppNew = this; } return WBEM_S_NO_ERROR; } return WBEM_S_NO_ERROR; }
void CBranchingNode::Dump(FILE* f, int nOffset) { CNodeWithImplications::Dump(f, nOffset); if (m_pInfo) { PrintOffset(f, nOffset); fprintf(f, "Embedding: "); m_pInfo->Dump(f); fprintf(f, "\n"); } }
//******************************************************************************
//******************************************************************************
// PROPERTY NODE
//******************************************************************************
//******************************************************************************
bool CPropertyNode::SetPropertyInfo(LPCWSTR wszPropName, long lPropHandle) { m_lPropHandle = lPropHandle; try { m_wsPropName = wszPropName; } catch (CX_MemoryException) { return false; } return true; }
int CPropertyNode::ComparePrecedence(CBranchingNode* pOther) { CPropertyNode* pOtherNode = (CPropertyNode*)pOther; return m_lPropHandle - pOtherNode->m_lPropHandle; }
bool CPropertyNode::SetEmbeddingInfo(const CEmbeddingInfo* pInfo) { try { if ((pInfo == NULL) || (pInfo->IsEmpty())) { delete m_pInfo; m_pInfo = NULL; } else if (!m_pInfo) { m_pInfo = new CEmbeddingInfo(*pInfo); if(m_pInfo == NULL) return false; } else *m_pInfo = *pInfo; } catch (CX_MemoryException) { return false; }
return true; }
HRESULT CPropertyNode::SetNullTest(int nOperator) { if(nOperator == QL1_OPERATOR_EQUALS) { if(m_apBranches.Add(CValueNode::GetStandardFalse()) < 0) return WBEM_E_OUT_OF_MEMORY;
CEvalNode* pTrue = CValueNode::GetStandardTrue(); if(pTrue == NULL) return WBEM_E_OUT_OF_MEMORY; SetNullBranch(pTrue); } else if(nOperator == QL1_OPERATOR_NOTEQUALS) { CEvalNode* pTrue = CValueNode::GetStandardTrue(); if(pTrue == NULL) return WBEM_E_OUT_OF_MEMORY;
if(m_apBranches.Add(pTrue) < 0) { delete pTrue; return WBEM_E_OUT_OF_MEMORY; }
SetNullBranch(CValueNode::GetStandardFalse()); } else return WBEM_E_INVALID_QUERY;
return WBEM_S_NO_ERROR; }
HRESULT CPropertyNode::SetOperator(int nOperator) { m_apBranches.RemoveAll();
#define GET_STD_TRUE CValueNode::GetStandardTrue()
#define GET_STD_FALSE CValueNode::GetStandardFalse()
#define ADD_STD_TRUE {CEvalNode* p = GET_STD_TRUE; \
if(p == NULL) return WBEM_E_OUT_OF_MEMORY; \ if(m_apBranches.Add(p) < 0) {delete p; return WBEM_E_OUT_OF_MEMORY;}}
#define ADD_STD_FALSE {CEvalNode* p = GET_STD_FALSE; \
if(m_apBranches.Add(p) < 0) {delete p; return WBEM_E_OUT_OF_MEMORY;}} switch(nOperator) { case QL1_OPERATOR_EQUALS: ADD_STD_FALSE; ADD_STD_TRUE; ADD_STD_FALSE; break;
case QL1_OPERATOR_NOTEQUALS: ADD_STD_TRUE; ADD_STD_FALSE; ADD_STD_TRUE; break;
case QL1_OPERATOR_LESS: ADD_STD_TRUE; ADD_STD_FALSE; ADD_STD_FALSE; break; case QL1_OPERATOR_GREATER: ADD_STD_FALSE; ADD_STD_FALSE; ADD_STD_TRUE; break; case QL1_OPERATOR_LESSOREQUALS: ADD_STD_TRUE; ADD_STD_TRUE; ADD_STD_FALSE; break;
case QL1_OPERATOR_GREATEROREQUALS: ADD_STD_FALSE; ADD_STD_TRUE; ADD_STD_TRUE; break;
case QL1_OPERATOR_LIKE: ADD_STD_TRUE; ADD_STD_FALSE; break;
case QL1_OPERATOR_UNLIKE: ADD_STD_FALSE; ADD_STD_TRUE; break;
default: return WBEM_E_CRITICAL_ERROR; }
return WBEM_S_NO_ERROR; }
//******************************************************************************
//******************************************************************************
// STRING PROPERTY NODE
//******************************************************************************
//******************************************************************************
CStringPropNode::CStringPropNode(const CStringPropNode& Other, BOOL bChildren) : CFullCompareNode<CInternalString>(Other, bChildren) { }
CStringPropNode::~CStringPropNode() { }
HRESULT CStringPropNode::Evaluate(CObjectInfo& ObjInfo, INTERNAL CEvalNode** ppNext) { *ppNext = NULL; HRESULT hres; _IWmiObject* pObj; hres = GetContainerObject(ObjInfo, &pObj); if( S_OK != hres ) { return hres; }
// Get the property from the object
// ================================
CCompressedString* pcs = CoreGetPropertyString(pObj, m_lPropHandle); CInternalString is; if(pcs == NULL) { *ppNext = m_pNullBranch; return WBEM_S_NO_ERROR; }
is.AcquireCompressedString(pcs);
// Search for the value
// ====================
TTestPointIterator it; bool bMatch = m_aTestPoints.Find(is, &it); if(bMatch) *ppNext = it->m_pAt; else if(it == m_aTestPoints.End()) *ppNext = m_pRightMost; else *ppNext = it->m_pLeftOf;
is.Unbind();
return WBEM_S_NO_ERROR; }
void CStringPropNode::Dump(FILE* f, int nOffset) { CBranchingNode::Dump(f, nOffset);
PrintOffset(f, nOffset); fprintf(f, "LastPropName = (0x%x)\n", m_lPropHandle);
for(TConstTestPointIterator it = m_aTestPoints.Begin(); it != m_aTestPoints.End(); it++) { PrintOffset(f, nOffset); if (it != m_aTestPoints.Begin()) { TConstTestPointIterator itPrev(it); itPrev--; fprintf(f, "%s < ", itPrev->m_Test.GetText()); } fprintf(f, "X < %s\n", it->m_Test.GetText()); DumpNode(f, nOffset +1, it->m_pLeftOf);
PrintOffset(f, nOffset); fprintf(f, "X = %s\n", it->m_Test.GetText()); DumpNode(f, nOffset +1, it->m_pAt); }
PrintOffset(f, nOffset); if (it != m_aTestPoints.Begin()) { TConstTestPointIterator itPrev(it); itPrev--; fprintf(f, "X > %s\n", itPrev->m_Test.GetText()); } else fprintf(f, "ANY\n"); DumpNode(f, nOffset+1, m_pRightMost);
PrintOffset(f, nOffset); fprintf(f, "NULL->\n"); DumpNode(f, nOffset+1, m_pNullBranch); }
/*****************************************************************************
CLikeStringPropNode ******************************************************************************/
CLikeStringPropNode::CLikeStringPropNode( const CLikeStringPropNode& Other, BOOL bChildren ) : CPropertyNode( Other, bChildren ) { m_Like = Other.m_Like; }
int CLikeStringPropNode::ComparePrecedence( CBranchingNode* pRawOther ) { int nCompare = CPropertyNode::ComparePrecedence( pRawOther ); if( nCompare ) { return nCompare; }
CLikeStringPropNode* pOther = (CLikeStringPropNode*)pRawOther;
return _wcsicmp( m_Like.GetExpression(), pOther->m_Like.GetExpression() ); }
int CLikeStringPropNode::SubCompare( CEvalNode* pRawOther ) { int nCompare;
CLikeStringPropNode* pOther = (CLikeStringPropNode*)pRawOther;
_DBG_ASSERT( m_apBranches.GetSize() == 2 ); _DBG_ASSERT( pOther->m_apBranches.GetSize() == 2 );
nCompare = CEvalTree::Compare( m_apBranches[0], pOther->m_apBranches[0] );
if ( nCompare ) { return nCompare; }
nCompare = CEvalTree::Compare( m_apBranches[1], pOther->m_apBranches[1] ); if ( nCompare ) { return nCompare; }
return CEvalTree::Compare( m_pNullBranch, pOther->m_pNullBranch );
}
HRESULT CLikeStringPropNode::Evaluate( CObjectInfo& ObjInfo, CEvalNode** ppNext ) { *ppNext = NULL;
HRESULT hr;
//
// get the string value.
//
_IWmiObject* pObj; hr = GetContainerObject( ObjInfo, &pObj );
if( S_OK != hr ) { return hr; }
CCompressedString* pcs = CoreGetPropertyString( pObj, m_lPropHandle );
//
// if null, then simply take null branch.
//
if( pcs == NULL ) { *ppNext = m_pNullBranch; return WBEM_S_NO_ERROR; }
CInternalString is; is.AcquireCompressedString(pcs);
WString ws = is;
//
// run through like filter. take branch accordingly.
//
if ( m_Like.Match( ws ) ) { *ppNext = m_apBranches[0]; } else { *ppNext = m_apBranches[1]; }
is.Unbind();
return WBEM_S_NO_ERROR; }
HRESULT CLikeStringPropNode::SetTest( VARIANT& v ) { if ( V_VT(&v) != VT_BSTR ) { return WBEM_E_TYPE_MISMATCH; }
try { m_Like.SetExpression( V_BSTR(&v) ); } catch(CX_MemoryException) { return WBEM_E_OUT_OF_MEMORY; } return WBEM_S_NO_ERROR; }
HRESULT CLikeStringPropNode::CombineBranchesWith( CBranchingNode* pRawArg2, int nOp, CContextMetaData* pNamespace, CImplicationList& Implications, bool bDeleteThis, bool bDeleteArg2, CEvalNode** ppRes ) { HRESULT hres; *ppRes = NULL; CLikeStringPropNode* pArg2 = (CLikeStringPropNode*)pRawArg2; if ( !bDeleteThis ) { return ((CLikeStringPropNode*)Clone())->CombineBranchesWith( pRawArg2, nOp, pNamespace, Implications, true, // reuse clone!
bDeleteArg2, ppRes ); }
CEvalNode* pNew = NULL;
//
// merge the 'match' branches
//
hres = CEvalTree::Combine( m_apBranches[0], pArg2->m_apBranches[0], nOp, pNamespace, Implications, true, bDeleteArg2, &pNew ); if(FAILED(hres)) return hres;
m_apBranches.Discard( 0 ); m_apBranches.SetAt( 0, pNew );
if( bDeleteArg2 ) { pArg2->m_apBranches.Discard( 0 ); }
//
// merge the 'nomatch' branches
//
hres = CEvalTree::Combine( m_apBranches[1], pArg2->m_apBranches[1], nOp, pNamespace, Implications, true, bDeleteArg2, &pNew ); if(FAILED(hres)) return hres;
m_apBranches.Discard( 1 ); m_apBranches.SetAt( 1, pNew );
if( bDeleteArg2 ) { pArg2->m_apBranches.Discard( 1 ); }
//
// merge the 'null' branches
//
hres = CEvalTree::Combine( m_pNullBranch, pArg2->m_pNullBranch, nOp, pNamespace, Implications, true, bDeleteArg2, &pNew ); if(FAILED(hres)) return hres;
m_pNullBranch = pNew;
if( bDeleteArg2 ) pArg2->m_pNullBranch = NULL;
//
// Delete what needs deleting
//
if(bDeleteArg2) delete pArg2; *ppRes = this; return WBEM_S_NO_ERROR; }
HRESULT CLikeStringPropNode::OptimizeSelf() { _DBG_ASSERT( m_apBranches.GetSize() == 2 );
return WBEM_S_NO_ERROR; } void CLikeStringPropNode::Dump(FILE* f, int nOffset) { CBranchingNode::Dump(f, nOffset);
PrintOffset(f, nOffset); fprintf(f, "LastPropName = (0x%x)\n", m_lPropHandle);
PrintOffset( f, nOffset ); fprintf(f, "Like Expression : %S\n", m_Like.GetExpression() );
PrintOffset( f, nOffset ); fprintf(f, "Match : \n" ); DumpNode(f, nOffset+1, m_apBranches[0] );
PrintOffset( f, nOffset ); fprintf(f, "NoMatch : \n" ); DumpNode(f, nOffset+1, m_apBranches[1] );
PrintOffset( f, nOffset ); fprintf(f, "NULL : \n" ); DumpNode(f, nOffset+1, m_pNullBranch ); }
//******************************************************************************
//******************************************************************************
// INHERITANCE NODE
//******************************************************************************
//******************************************************************************
CInheritanceNode::CInheritanceNode() : m_lDerivationIndex(-1), m_lNumPoints(0), m_apcsTestPoints(NULL) { // Add a none-of-the-above node
// ============================
m_apBranches.Add(CValueNode::GetStandardFalse()); }
CInheritanceNode::CInheritanceNode(const CInheritanceNode& Other, BOOL bChildren) : CBranchingNode(Other, bChildren), m_lDerivationIndex(Other.m_lDerivationIndex) { m_lNumPoints = Other.m_lNumPoints; m_apcsTestPoints = new CCompressedString*[m_lNumPoints]; if(m_apcsTestPoints == NULL) throw CX_MemoryException();
for(int i = 0; i < m_lNumPoints; i++) { m_apcsTestPoints[i] = (CCompressedString*) _new BYTE[Other.m_apcsTestPoints[i]->GetLength()];
if(m_apcsTestPoints[i] == NULL) throw CX_MemoryException();
memcpy((void*)m_apcsTestPoints[i], (void*)Other.m_apcsTestPoints[i], Other.m_apcsTestPoints[i]->GetLength()); } }
/* virtual */ long CInheritanceNode::GetSubType() { return EVAL_NODE_TYPE_INHERITANCE; }
CInheritanceNode::~CInheritanceNode() { RemoveAllTestPoints(); }
void CInheritanceNode::RemoveAllTestPoints() { for(int i = 0; i < m_lNumPoints; i++) { delete [] (BYTE*)m_apcsTestPoints[i]; } delete [] m_apcsTestPoints; m_apcsTestPoints = NULL; }
bool CInheritanceNode::SetPropertyInfo(CContextMetaData* pNamespace, CPropertyName& PropName) { return SetEmbeddedObjPropName(PropName); }
HRESULT CInheritanceNode::AddClass(CContextMetaData* pNamespace, LPCWSTR wszClassName, CEvalNode* pDestination) { HRESULT hres;
// Get the class from the namespace
// ================================
_IWmiObject* pObj = NULL; hres = pNamespace->GetClass(wszClassName, &pObj); if(FAILED(hres)) return hres;
hres = AddClass(pNamespace, wszClassName, pObj, pDestination); pObj->Release(); return hres; }
HRESULT CInheritanceNode::AddClass(CContextMetaData* pNamespace, LPCWSTR wszClassName, _IWmiObject* pClass, CEvalNode* pDestination) { // Get the number of items in its derivation --- that's the index where we
// need to look for its name in its children
// =======================================================================
ULONG lDerivationIndex; HRESULT hRes = CoreGetNumParents(pClass, &lDerivationIndex); if (FAILED (hRes)) return hRes;
if(m_lDerivationIndex == -1) { // We don't have a currently set derivation index --- this is the first
// ====================================================================
m_lDerivationIndex = lDerivationIndex; } else if(m_lDerivationIndex != lDerivationIndex) { // Can't add this class --- derivation index mismatch
// ==================================================
return WBEM_E_FAILED; }
// Allocate a compressed string
// ============================
int nLength = CCompressedString::ComputeNecessarySpace(wszClassName); CCompressedString* pcs = (CCompressedString*)new BYTE[nLength]; if (pcs) pcs->SetFromUnicode(wszClassName); else return WBEM_E_OUT_OF_MEMORY;
// Extend the lists by one
// =======================
CCompressedString** apcsNewTestPoints = new CCompressedString*[m_lNumPoints+1]; if (!apcsNewTestPoints) return WBEM_E_OUT_OF_MEMORY;
// Insert it into the list of tests and the list of branches
// =========================================================
int i = 0; while(i < m_lNumPoints && pcs->CheapCompare(*m_apcsTestPoints[i]) > 0) { apcsNewTestPoints[i] = m_apcsTestPoints[i]; i++; }
apcsNewTestPoints[i] = pcs; m_apBranches.InsertAt(i+1, pDestination);
while(i < m_lNumPoints) { apcsNewTestPoints[i+1] = m_apcsTestPoints[i]; } // Set the new list
// ================
delete [] m_apcsTestPoints; m_apcsTestPoints = apcsNewTestPoints; m_lNumPoints++;
return WBEM_S_NO_ERROR; }
HRESULT CInheritanceNode::RecordBranch(CContextMetaData* pNamespace, CImplicationList& Implications, long lBranchIndex) { HRESULT hres = WBEM_S_NO_ERROR; if(lBranchIndex == -1) { // Recording NULL branch
// =====================
hres = Implications.ImproveKnownNull(GetEmbeddedObjPropName()); } else if(lBranchIndex == 0) { // Recording none of the above branch
// ==================================
for(int i = 0; i < m_lNumPoints; i++) { LPWSTR wszClassName = NULL; try { wszClassName = m_apcsTestPoints[i]->CreateWStringCopy().UnbindPtr(); } catch (CX_MemoryException) { return WBEM_E_OUT_OF_MEMORY; } if(wszClassName == NULL) return WBEM_E_OUT_OF_MEMORY; CVectorDeleteMe<WCHAR> vdm(wszClassName);
hres = Implications.ImproveKnownNot(GetEmbeddedObjPropName(), wszClassName); if(FAILED(hres)) { // Contradicts known information --- fail recording
// ================================================
return hres; } } } else { // Normal branch --- record the class
// ==================================
BSTR strClassName = m_apcsTestPoints[lBranchIndex - 1]-> CreateBSTRCopy(); _IWmiObject* pObj = NULL; hres = pNamespace->GetClass(strClassName, &pObj); SysFreeString(strClassName); if(FAILED(hres)) return hres;
hres = Implications.ImproveKnown(GetEmbeddedObjPropName(), pObj); pObj->Release(); } return hres; }
int CInheritanceNode::ComparePrecedence(CBranchingNode* pOther) { CInheritanceNode* pInhOther = (CInheritanceNode*)pOther; return (m_lDerivationIndex - pInhOther->m_lDerivationIndex); }
int CInheritanceNode::SubCompare(CEvalNode* pOther) { CInheritanceNode* pInhOther = (CInheritanceNode*)pOther; int nCompare;
nCompare = m_lDerivationIndex - pInhOther->m_lDerivationIndex; if(nCompare) return nCompare;
nCompare = m_lNumPoints - pInhOther->m_lNumPoints; if(nCompare) return nCompare;
for(int i = 0; i < m_lNumPoints; i++) { nCompare = m_apcsTestPoints[i]->CompareNoCase( *pInhOther->m_apcsTestPoints[i]); if(nCompare) return nCompare; }
return 0; } void CInheritanceNode::RemoveTestPoint(int i) { delete [] m_apcsTestPoints[i]; memcpy((void*)(m_apcsTestPoints + i), (void*)(m_apcsTestPoints + i + 1), sizeof(CCompressedString*) * (m_lNumPoints - i - 1)); m_lNumPoints--; }
HRESULT CInheritanceNode::OptimizeSelf() { for(int i = 0; i < m_lNumPoints; i++) { // Compare this branch to the "nothing" branch
// ===========================================
if(CEvalNode::IsInvalid(m_apBranches[i+1]) || CEvalTree::Compare(m_apBranches[0], m_apBranches[i+1]) == 0) { RemoveTestPoint(i); m_apBranches.RemoveAt(i+1); i--; continue; }
// Check if this node is another class check on the same object
// ============================================================
if(CEvalNode::GetType(m_apBranches[i+1]) != EVAL_NODE_TYPE_BRANCH) continue; CBranchingNode* pBranch = (CBranchingNode*)(m_apBranches[i+1]); if(pBranch->GetSubType() == EVAL_NODE_TYPE_INHERITANCE && pBranch->GetEmbeddedObjPropName() == GetEmbeddedObjPropName()) { // If the "none-of-the-above" branch of this child is the same
// as the "none-of-the-above" branch of ourselves, we can replace
// our "none-of-the-above" branch with this node, since anything
// that is falling under none-of-the-above now will fall under
// none-of-the-above of our child (otherwise there is an
// optimization flaw in the child).
// IMPORTANT: this will no longer be true if we change the
// precedence order of inheritance nodes!!!
if(CEvalTree::Compare(m_apBranches[0], pBranch->GetBranches()[0]) == 0) { m_apBranches.SetAt(0, pBranch); m_apBranches.GetArrayPtr()[i+1] = NULL; m_apBranches.RemoveAt(i+1); RemoveTestPoint(i); i--; } } }
return S_OK; }
HRESULT CInheritanceNode::Optimize(CContextMetaData* pNamespace, CEvalNode** ppNew) { // Delegate to the normal branch optimization process
// ==================================================
*ppNew = NULL; HRESULT hres = CBranchingNode::Optimize(pNamespace, ppNew); if(FAILED(hres) || *ppNew != this) return hres;
// Specific post-processing
// ========================
if(m_apBranches.GetSize() == 1) { // We are reduced to checking for NULL. If our non-NULL branch is
// talking about the same property, push the test there.
// ==============================================================
if (CEvalNode::GetType(m_apBranches[0]) != EVAL_NODE_TYPE_BRANCH) return hres;
CBranchingNode* pBranch = (CBranchingNode*)(m_apBranches[0]); if(pBranch && pBranch->GetSubType() == EVAL_NODE_TYPE_INHERITANCE && pBranch->GetEmbeddedObjPropName() == GetEmbeddedObjPropName()) { pBranch->SetNullBranch(m_pNullBranch); pBranch->Optimize(pNamespace, ppNew); if(*ppNew != pBranch) m_apBranches.RemoveAll(); else m_apBranches.GetArrayPtr()[0] = NULL;
m_pNullBranch = NULL;
return S_OK; } }
return S_OK; }
HRESULT CInheritanceNode::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; }
// Get the parent at the right index
// =================================
CCompressedString* pcs; ULONG lNumParents; HRESULT hRes = CoreGetNumParents(pInst, &lNumParents); if (FAILED(hRes)) return hRes; if(lNumParents < m_lDerivationIndex) { if (m_apBranches.GetSize()) *ppNext = m_apBranches[0]; else *ppNext = NULL; return WBEM_S_NO_ERROR; } else if(lNumParents == m_lDerivationIndex) { pcs = CoreGetClassInternal(pInst); } else { pcs = CoreGetParentAtIndex(pInst, m_lDerivationIndex); }
if(pcs == NULL) { //
// This class does not even have that long an ancestry --- clearly
// not derived from any of those
//
if (m_apBranches.GetSize()) *ppNext = m_apBranches[0]; else *ppNext = NULL;
return WBEM_S_NO_ERROR; }
// Search for the value
// ====================
long lLeft = -1; long lRight = m_lNumPoints; while(lRight > lLeft + 1) { long lMiddle = (lRight + lLeft) >> 1; int nCompare = pcs->CheapCompare(*m_apcsTestPoints[lMiddle]); if(nCompare < 0) { lRight = lMiddle; } else if(nCompare > 0) { lLeft = lMiddle; } else { *ppNext = m_apBranches[lMiddle+1]; return WBEM_S_NO_ERROR; } }
if (m_apBranches.GetSize()) *ppNext = m_apBranches[0]; else *ppNext = NULL;
return WBEM_S_NO_ERROR; }
HRESULT CInheritanceNode::Compile(CContextMetaData* pNamespace, CImplicationList& Implications) { if (!m_pInfo) { m_pInfo = new CEmbeddingInfo; if(m_pInfo == NULL) return WBEM_E_OUT_OF_MEMORY; }
HRESULT hres = CompileEmbeddingPortion(pNamespace, Implications, NULL); return hres; }
// Computes preliminary parameters for merging two inheritance nodes at the
// same level --- which children will be used, and how many times.
HRESULT CInheritanceNode::ComputeUsageForMerge(CInheritanceNode* pArg2, CContextMetaData* pNamespace, CImplicationList& OrigImplications, bool bDeleteThis, bool bDeleteArg2, DWORD* pdwFirstNoneCount, DWORD* pdwSecondNoneCount, bool* pbBothNonePossible) { HRESULT hres;
*pdwFirstNoneCount = 0; *pdwSecondNoneCount = 0; *pbBothNonePossible = false;
try { CImplicationList Implications(OrigImplications); BOOL bFirstNonePossible, bSecondNonePossible; CImplicationList NoneImplications(Implications); hres = RecordBranch(pNamespace, NoneImplications, 0); if(FAILED(hres)) { bFirstNonePossible = FALSE; bSecondNonePossible = SUCCEEDED(pArg2->RecordBranch(pNamespace, NoneImplications, 0)); } else { bFirstNonePossible = TRUE; hres = pArg2->RecordBranch(pNamespace, NoneImplications, 0); if(FAILED(hres)) { // Check if the second one can survive in isolation
// ================================================
CImplicationList NoneImplications1(Implications); bSecondNonePossible = SUCCEEDED(pArg2->RecordBranch(pNamespace, NoneImplications1, 0)); } else { bSecondNonePossible = TRUE; } } if(bFirstNonePossible && bSecondNonePossible) { //
// Both of them will be used at least once: with each other!
//
*pdwFirstNoneCount = *pdwSecondNoneCount = 1; *pbBothNonePossible = true; } //
// If we are not deleting something, the usage count should be infinite!
//
if(!bDeleteThis) *pdwFirstNoneCount = 0xFFFFFFFF; if(!bDeleteArg2) *pdwSecondNoneCount = 0xFFFFFFFF; //
// Merge lookup lists
//
long lFirstIndex = 0; long lSecondIndex = 0; while(lFirstIndex < m_lNumPoints || lSecondIndex < pArg2->m_lNumPoints) { //
// Retrieve the test points from both lists and compare them,
// taking care of boundary conditions
//
int nCompare; CCompressedString* pcsFirstVal = NULL; CCompressedString* pcsSecondVal = NULL; if(lFirstIndex == m_lNumPoints) { nCompare = 1; pcsSecondVal = pArg2->m_apcsTestPoints[lSecondIndex]; } else if(lSecondIndex == pArg2->m_lNumPoints) { pcsFirstVal = m_apcsTestPoints[lFirstIndex]; nCompare = -1; } else { pcsFirstVal = m_apcsTestPoints[lFirstIndex]; pcsSecondVal = pArg2->m_apcsTestPoints[lSecondIndex]; nCompare = pcsFirstVal->CheapCompare(*pcsSecondVal); } if(nCompare < 0) { //
// At this index is the first value combined with second none
//
if(!bDeleteArg2) // not interesting
{ lFirstIndex++; continue; } if(!bSecondNonePossible) { lFirstIndex++; continue; } CImplicationList BranchImplications(Implications); if(FAILED(RecordBranch(pNamespace, BranchImplications, lFirstIndex+1))) { lFirstIndex++; continue; } if(FAILED(pArg2->RecordBranch(pNamespace, BranchImplications, 0))) { lFirstIndex++; continue; } (*pdwSecondNoneCount)++; lFirstIndex++; } else if(nCompare > 0) { // At this index is the second value combined with first none
// ==========================================================
if(!bDeleteThis) // not interesting
{ lSecondIndex++; continue; } if(!bFirstNonePossible) { lSecondIndex++; continue; } CImplicationList BranchImplications(Implications); if(FAILED(pArg2->RecordBranch(pNamespace, BranchImplications, lSecondIndex+1))) { lSecondIndex++; continue; } if(FAILED(RecordBranch(pNamespace, BranchImplications, 0))) { lSecondIndex++; continue; } (*pdwFirstNoneCount)++; lSecondIndex++; } else { // At this index is the combinations of the ats
// ============================================
lFirstIndex++; lSecondIndex++; } } } catch (CX_MemoryException) { return WBEM_E_OUT_OF_MEMORY; }
return S_OK; }
HRESULT CInheritanceNode::CombineBranchesWith(CBranchingNode* pRawArg2, int nOp, CContextMetaData* pNamespace, CImplicationList& OrigImplications, bool bDeleteThis, bool bDeleteArg2, CEvalNode** ppRes) { HRESULT hres;
CInheritanceNode* pArg2 = (CInheritanceNode*)pRawArg2;
if(!bDeleteThis && bDeleteArg2) { // It is easier to combine in the other direction
// ==============================================
return pArg2->CombineBranchesWith(this, FlipEvalOp(nOp), pNamespace, OrigImplications, bDeleteArg2, bDeleteThis, ppRes); }
try { // Either clone or use our node
// ============================
CInheritanceNode* pNew = NULL; if(bDeleteThis) { pNew = this; } else { // Clone this node without cloning the branches.
// =============================================
pNew = (CInheritanceNode*)CloneSelf(); if(pNew == NULL) return WBEM_E_OUT_OF_MEMORY; } CImplicationList Implications(OrigImplications); hres = pNew->AdjustCompile(pNamespace, Implications); if(FAILED(hres)) return hres; //
// Get overall information
//
DWORD dwFirstNoneCount, dwSecondNoneCount; bool bBothNonePossible; hres = ComputeUsageForMerge(pArg2, pNamespace, Implications, bDeleteThis, bDeleteArg2, &dwFirstNoneCount, &dwSecondNoneCount, &bBothNonePossible); if(FAILED(hres)) { if(!bDeleteThis) delete pNew; return hres; } bool bFirstNonePossible = (dwFirstNoneCount > 0); bool bSecondNonePossible = (dwSecondNoneCount > 0); //
// Allocate a new array of test points and a new array of branches. We
// can't use the ones in pNew because we are using some of the
// elements in those arrays in this many times and don't want to trample
// them (since pNew and this might be the same). Therefore, we create
// and fill these arrays outside of the node and then place them into
// pNew when we are done.
//
// As we delete the child nodes in the Branches array, we will set them
// to NULL so that we can clear the branch array in the end
//
CCompressedString** apcsTestPoints = new CCompressedString*[m_lNumPoints + pArg2->m_lNumPoints]; if(apcsTestPoints == NULL) return WBEM_E_OUT_OF_MEMORY; CUniquePointerArray<CEvalNode> apBranches; //
// Merge none-of-the-above branches
//
if(bBothNonePossible) { //
// They have to be merged
//
CImplicationList NoneImplications(Implications); hres = RecordBranch(pNamespace, NoneImplications, 0); if(FAILED(hres)) return hres; hres = pArg2->RecordBranch(pNamespace, NoneImplications, 0); if(FAILED(hres)) return hres; //
// We may delete our None nodes if and only if there predicted usage
// count (adjusted for usage that has already occurred) is dropping
// to 0 --- that is, noone will use these nodes further during this
// merge
//
CEvalNode* pNone = NULL; bool bDeleteFirstBranch = (--dwFirstNoneCount == 0); bool bDeleteSecondBranch = (--dwSecondNoneCount == 0); CEvalTree::Combine(m_apBranches[0], pArg2->m_apBranches[0], nOp, pNamespace, NoneImplications, bDeleteFirstBranch, bDeleteSecondBranch, &pNone); if(bDeleteSecondBranch) pArg2->m_apBranches.Discard(0); if(bDeleteFirstBranch) m_apBranches.Discard(0); if(apBranches.Add(pNone) < 0) return WBEM_E_OUT_OF_MEMORY; } else { //
// Since both none is not possible, we set this branch to FALSE
//
if(apBranches.Add(NULL) < 0) return WBEM_E_OUT_OF_MEMORY; } //
// Merge lookup lists
//
long lFirstIndex = 0; long lSecondIndex = 0; long lNewIndex = 0; while(lFirstIndex < m_lNumPoints || lSecondIndex < pArg2->m_lNumPoints) { //
// Retrieve the test points from both lists and compare them,
// taking care of boundary conditions
//
int nCompare; CCompressedString* pcsFirstVal = NULL; CCompressedString* pcsSecondVal = NULL; if(lFirstIndex == m_lNumPoints) { nCompare = 1; pcsSecondVal = pArg2->m_apcsTestPoints[lSecondIndex]; } else if(lSecondIndex == pArg2->m_lNumPoints) { pcsFirstVal = m_apcsTestPoints[lFirstIndex]; nCompare = -1; } else { pcsFirstVal = m_apcsTestPoints[lFirstIndex]; pcsSecondVal = pArg2->m_apcsTestPoints[lSecondIndex]; nCompare = pcsFirstVal->CheapCompare(*pcsSecondVal); } //
// Compute the branch to be added and its test point
//
CEvalNode* pNewBranch = NULL; CCompressedString* pcsCurrentVal = NULL; if(nCompare < 0) { //
// At this index is the first value combined with second none
//
if(!bSecondNonePossible) { lFirstIndex++; continue; } CImplicationList BranchImplications(Implications); if(FAILED(RecordBranch(pNamespace, BranchImplications, lFirstIndex+1))) { lFirstIndex++; continue; } pArg2->RecordBranch(pNamespace, BranchImplications, 0); //
// We may delete our None nodes if and only if there predicted
// usage count (adjusted for usage that has already occurred) is
// dropping to 0 --- that is, noone will use these nodes further
// during this merge
//
bool bDeleteOtherBranch = (--dwSecondNoneCount == 0); CEvalTree::Combine(m_apBranches[lFirstIndex+1], pArg2->m_apBranches[0], nOp, pNamespace, BranchImplications, bDeleteThis, bDeleteOtherBranch, &pNewBranch); if(bDeleteOtherBranch) pArg2->m_apBranches.Discard(0); if(bDeleteThis) m_apBranches.Discard(lFirstIndex+1); pcsCurrentVal = pcsFirstVal; lFirstIndex++; } else if(nCompare > 0) { // At this index is the second value combined with first none
// ==========================================================
if(!bFirstNonePossible) { lSecondIndex++; continue; } CImplicationList BranchImplications(Implications); if(FAILED(pArg2->RecordBranch(pNamespace, BranchImplications, lSecondIndex+1))) { lSecondIndex++; continue; } if(FAILED(RecordBranch(pNamespace, BranchImplications, 0))) { lSecondIndex++; continue; } //
// We may delete our None nodes if and only if there predicted
// usage count (adjusted for usage that has already occurred) is
// dropping to 0 --- that is, noone will use these nodes further
// during this merge
//
bool bDeleteThisBranch = (--dwFirstNoneCount == 0); CEvalTree::Combine(m_apBranches[0], pArg2->m_apBranches[lSecondIndex+1], nOp, pNamespace, BranchImplications, bDeleteThisBranch, bDeleteArg2, &pNewBranch); if(bDeleteArg2) pArg2->m_apBranches.Discard(lSecondIndex+1); if(bDeleteThisBranch) m_apBranches.Discard(0); pcsCurrentVal = pcsSecondVal; lSecondIndex++; } else { // At this index is the combinations of the ats
// ============================================
CImplicationList BranchImplications(Implications); if(FAILED(RecordBranch(pNamespace, BranchImplications, lFirstIndex+1))) { lSecondIndex++; lFirstIndex++; continue; } CEvalTree::Combine(m_apBranches[lFirstIndex+1], pArg2->m_apBranches[lSecondIndex+1], nOp, pNamespace, BranchImplications, bDeleteThis, bDeleteArg2, &pNewBranch); if(bDeleteArg2) pArg2->m_apBranches.Discard(lSecondIndex+1); if(bDeleteThis) m_apBranches.Discard(lFirstIndex+1); pcsCurrentVal = pcsFirstVal; // doesn't matter --- same
lFirstIndex++; lSecondIndex++; } //
// Add the newely constructed branch
//
if(apBranches.Add(pNewBranch) < 0) return WBEM_E_OUT_OF_MEMORY; //
// Add the newely constructed test point
//
apcsTestPoints[lNewIndex] = (CCompressedString*)_new BYTE[pcsCurrentVal->GetLength()]; if(apcsTestPoints[lNewIndex] == NULL) return WBEM_E_OUT_OF_MEMORY; memcpy((void*)apcsTestPoints[lNewIndex], (void*)pcsCurrentVal, pcsCurrentVal->GetLength()); lNewIndex++; } //
// Now that we are done with testing, place the test-point array into
// pNew
//
pNew->RemoveAllTestPoints(); pNew->m_apcsTestPoints = apcsTestPoints; pNew->m_lNumPoints = lNewIndex; //
// Replace the array of branches that we may have had (guaranteed to
// all be NULL, since we were NULLing them out as we went).
//
pNew->m_apBranches.RemoveAll(); for(int i = 0; i < apBranches.GetSize(); i++) { pNew->m_apBranches.Add(apBranches[i]); apBranches.Discard(i); } //
// Merge the nulls
//
CImplicationList NullImplications(Implications); hres = RecordBranch(pNamespace, Implications, -1); if(SUCCEEDED(hres)) { CEvalNode* pNewBranch = NULL; hres = CEvalTree::Combine(m_pNullBranch, pArg2->m_pNullBranch, nOp, pNamespace, NullImplications, bDeleteThis, bDeleteArg2, &pNewBranch); if(FAILED(hres)) return hres; //
// Clear the old new branch, whatever it was, (it has been deleted,
// if it ever were there at all) 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; } catch (CX_MemoryException) { return WBEM_E_OUT_OF_MEMORY; } }
HRESULT CInheritanceNode::Project(CContextMetaData* pMeta, CImplicationList& Implications, CProjectionFilter* pFilter, EProjectionType eType, bool bDeleteThis, CEvalNode** ppNewNode) { //
// There are two choices here: either it is about us, or we are not
// interested.
//
if(pFilter->IsInSet(this)) { return CBranchingNode::Project(pMeta, Implications, pFilter, eType, bDeleteThis, ppNewNode); } else { if(eType == e_Sufficient) *ppNewNode = CValueNode::GetStandardFalse(); else { *ppNewNode = CValueNode::GetStandardTrue(); if(*ppNewNode == NULL) return WBEM_E_OUT_OF_MEMORY; }
if(bDeleteThis) delete this;
return S_OK; } }
void CInheritanceNode::Dump(FILE* f, int nOffset) { CBranchingNode::Dump(f, nOffset); PrintOffset(f, nOffset); fprintf(f, "inheritance index %d: (0x%p)\n", m_lDerivationIndex, this);
for(int i = 0; i < m_lNumPoints; i++) { WString ws = m_apcsTestPoints[i]->CreateWStringCopy(); PrintOffset(f, nOffset); fprintf(f, "%S->\n", (LPWSTR)ws); DumpNode(f, nOffset+1, m_apBranches[i+1]); }
PrintOffset(f, nOffset); fprintf(f, "none of the above->\n"); DumpNode(f, nOffset+1, m_apBranches[0]);
PrintOffset(f, nOffset); fprintf(f, "NULL->\n"); DumpNode(f, nOffset+1, m_pNullBranch); }
#ifdef CHECK_TREES
void CBranchingNode::CheckNode(CTreeChecker *pCheck) { pCheck->CheckoffNode(this);
int nItems = m_apBranches.GetSize();
for (int i = 0; i < nItems; i++) { CEvalNode *pNode = m_apBranches[i];
if (pNode) m_apBranches[i]->CheckNode(pCheck); }
if (m_pNullBranch) m_pNullBranch->CheckNode(pCheck); } #endif
//******************************************************************************
//******************************************************************************
//
// OR NODE
//
//******************************************************************************
//******************************************************************************
void COrNode::operator=(const COrNode& Other) { // Remove all our children
// =======================
m_apBranches.RemoveAll();
// Clone all the branches from the other
// =====================================
for(int i = 0; i < Other.m_apBranches.GetSize(); i++) { CEvalNode* pNewBranch = CloneNode(Other.m_apBranches[i]);
if(pNewBranch == NULL && Other.m_apBranches[i] != NULL) throw CX_MemoryException();
if(m_apBranches.Add(pNewBranch) < 0) throw CX_MemoryException(); } }
HRESULT COrNode::CombineWith(CEvalNode* pArg2, int nOp, CContextMetaData* pNamespace, CImplicationList& Implications, bool bDeleteThis, bool bDeleteArg2, CEvalNode** ppRes) { HRESULT hres; *ppRes = NULL;
// We don't support AND combines on OR nodes
// =========================================
if(nOp == EVAL_OP_AND) return WBEM_E_CRITICAL_ERROR;
// If the other is another OR node, delegate to the iterator
// =========================================================
if(CEvalNode::GetType(pArg2) == EVAL_NODE_TYPE_OR) { return CombineWithOrNode((COrNode*)pArg2, nOp, pNamespace, Implications, bDeleteThis, bDeleteArg2, ppRes); }
// Make a copy --- the new node will be mostly us
// ==============================================
COrNode* pNew = NULL;
if(!bDeleteThis) { pNew = (COrNode*)Clone(); if(pNew == NULL) return WBEM_E_OUT_OF_MEMORY; } else { pNew = this; }
*ppRes = pNew;
// Combining an OR node with a non-OR --- try all branches
// =======================================================
for(int i = 0; i < m_apBranches.GetSize(); i++) { // Check if this branch is a good fit for the other node
// =====================================================
if(CEvalTree::IsMergeAdvisable(m_apBranches[i], pArg2, Implications) == WBEM_S_NO_ERROR) { // It is --- merge it in
// =====================
CEvalNode* pNewBranch = NULL; hres = CEvalTree::Combine(m_apBranches[i], pArg2, nOp, pNamespace, Implications, bDeleteThis, bDeleteArg2, &pNewBranch); if(FAILED(hres)) return hres;
if(bDeleteThis) m_apBranches.Discard(i);
pNew->m_apBranches.SetAt(i, pNewBranch);
return WBEM_S_NO_ERROR; } }
// No branch was a good fit --- add the node to our list
// =====================================================
if(bDeleteArg2) { hres = pNew->AddBranch(pArg2); } else { CEvalNode* pNode = pArg2->Clone(); if(pNode == NULL) return WBEM_E_OUT_OF_MEMORY; hres = pNew->AddBranch(pNode); }
if(FAILED(hres)) return hres;
return WBEM_S_NO_ERROR; }
HRESULT COrNode::AddBranch(CEvalNode* pNewBranch) { // Search for a place in our array of branches
// ===========================================
for(int i = 0; i < m_apBranches.GetSize(); i++) { int nCompare = CEvalTree::Compare(pNewBranch, m_apBranches[i]); if(nCompare == 0) { // Could happen: sometimes we force an OR-merge
nCompare = -1; }
if(nCompare < 0) { // pNewBranch comes before this branch, so insert it right here
// ============================================================
if(!m_apBranches.InsertAt(i, pNewBranch)) return WBEM_E_OUT_OF_MEMORY;
return WBEM_S_NO_ERROR; } }
// It is after all branches --- append
// ===================================
if(m_apBranches.Add(pNewBranch) < 0) return WBEM_E_OUT_OF_MEMORY;
return WBEM_S_NO_ERROR; } HRESULT COrNode::CombineWithOrNode(COrNode* pArg2, int nOp, CContextMetaData* pNamespace, CImplicationList& Implications, bool bDeleteThis, bool bDeleteArg2, CEvalNode** ppRes) { // NOTE: this function may delete THIS in the middle of execution!!
// ================================================================
// Combine us with every branch of the other
// =========================================
CEvalNode* pCurrent = this; bool bDeleteCurrent = bDeleteThis; for(int i = 0; i < pArg2->m_apBranches.GetSize(); i++) { CEvalNode* pNew = NULL; HRESULT hres = pCurrent->CombineWith(pArg2->m_apBranches[i], nOp, pNamespace, Implications, bDeleteCurrent, bDeleteArg2, &pNew); if(FAILED(hres)) return hres;
pCurrent = pNew;
// At this point, we can safely delete pCurrent if needed --- it's ours
// ====================================================================
bDeleteCurrent = TRUE;
// If pArg2's branch has been deleted, reset it
// ============================================
if(bDeleteArg2) pArg2->m_apBranches.Discard(i); }
*ppRes = pCurrent;
if(bDeleteArg2) delete pArg2; return WBEM_S_NO_ERROR; }
int COrNode::Compare(CEvalNode* pOther) { COrNode* pOtherNode = (COrNode*)pOther;
// Compare array sizes
// ===================
if(m_apBranches.GetSize() != pOtherNode->m_apBranches.GetSize()) return m_apBranches.GetSize() - pOtherNode->m_apBranches.GetSize();
// Compare individual nodes
// ========================
for(int i = 0; i < m_apBranches.GetSize(); i++) { int nCompare = CEvalTree::Compare(m_apBranches[i], pOtherNode->m_apBranches[i]); if(nCompare != 0) return nCompare; }
return 0; }
DWORD COrNode::ApplyPredicate(CLeafPredicate* pPred) { for(int i = 0; i < m_apBranches.GetSize(); i++) { if (m_apBranches[i]) m_apBranches[i]->ApplyPredicate(pPred); } return WBEM_DISPOSITION_NORMAL; }
HRESULT COrNode::Optimize(CContextMetaData* pNamespace, CEvalNode** ppNew) { HRESULT hres = WBEM_S_NO_ERROR;
// First, optimize all its branches
// ================================
for(int i = 0; i < m_apBranches.GetSize(); i++) { CEvalNode* pNew = NULL; if (m_apBranches[i]) { hres = m_apBranches[i]->Optimize(pNamespace, &pNew); if(FAILED(hres)) return hres; }
if(pNew != m_apBranches[i]) { // Replace, but check for emptiness first
// ======================================
if(!CEvalNode::IsAllFalse(pNew)) m_apBranches.SetAt(i, pNew); else { delete pNew; m_apBranches.RemoveAt(i); i--; } } }
if(m_apBranches.GetSize() == 0) { // We have no branches --- equivalent to no successes
// ==================================================
*ppNew = CValueNode::GetStandardFalse(); return WBEM_S_NO_ERROR; } else if(m_apBranches.GetSize() == 1) { // One branch --- equivalent to that branch
// ========================================
m_apBranches.RemoveAt(0, ppNew); } else { *ppNew = this; } return WBEM_S_NO_ERROR; }
void COrNode::Dump(FILE* f, int nOffset) { PrintOffset(f, nOffset); fprintf(f, "FOREST\n");
for(int i = 0; i < m_apBranches.GetSize(); i++) { if (m_apBranches[i]) m_apBranches[i]->Dump(f, nOffset+1); else fprintf(f, "all false ValueNode (or error?)\n"); } }
HRESULT COrNode::Evaluate(CObjectInfo& Info, CSortedArray& trueIDs) { for(int i = 0; i < m_apBranches.GetSize(); i++) { if (m_apBranches[i]) { HRESULT hres = CEvalTree::Evaluate(Info, m_apBranches[i], trueIDs); if(FAILED(hres)) return hres; } }
return WBEM_S_NO_ERROR; } HRESULT COrNode::Project(CContextMetaData* pMeta, CImplicationList& Implications, CProjectionFilter* pFilter, EProjectionType eType, bool bDeleteThis, CEvalNode** ppNewNode) { COrNode* pNew; if(bDeleteThis) pNew = this; else pNew = (COrNode*)Clone();
if(pNew == NULL) return WBEM_E_OUT_OF_MEMORY;
//
// Simply project all the branches
//
for(int i = 0; i < pNew->m_apBranches.GetSize(); i++) { CEvalNode* pProjected = NULL;
HRESULT hres = CEvalTree::Project(pMeta, Implications, pNew->m_apBranches[i], pFilter, eType, true, // always delete --- has been cloned
&pProjected); if(FAILED(hres)) return hres;
pNew->m_apBranches.Discard(i); pNew->m_apBranches.SetAt(i, pProjected); }
*ppNewNode = pNew; return S_OK; }
//******************************************************************************
//******************************************************************************
// PREDICATES
//******************************************************************************
//******************************************************************************
// NOTE: Not checking for NULL leaves, should be checked by caller
DWORD CEvalTree::CRemoveIndexPredicate::operator()(CValueNode* pLeaf) { if(pLeaf) { pLeaf->RemoveQueryID(m_nIndex); if(pLeaf->GetNumTrues() == 0) return WBEM_DISPOSITION_FLAG_DELETE; } return WBEM_DISPOSITION_NORMAL; }
// NOTE: Not checking for NULL leaves, should be checked by caller
DWORD CEvalTree::CRebasePredicate::operator()(CValueNode* pLeaf) { if(pLeaf) pLeaf->Rebase(m_newBase); return WBEM_DISPOSITION_NORMAL; }
// NOTE: Not checking for NULL leaves, should be checked by caller
DWORD CEvalTree::CRemoveFailureAtIndexPredicate::operator()(CValueNode* pLeaf) { if(pLeaf == NULL || pLeaf->GetAt(m_nIndex) != EVAL_VALUE_TRUE) return WBEM_DISPOSITION_FLAG_INVALIDATE; pLeaf->RemoveQueryID(m_nIndex); if(pLeaf->GetNumTrues() == 0) return WBEM_DISPOSITION_FLAG_DELETE;
return WBEM_DISPOSITION_NORMAL; }
//******************************************************************************
//******************************************************************************
// EVALUATION TREE
//******************************************************************************
//******************************************************************************
CEvalTree::CEvalTree() : m_lRef(0), m_pStart(NULL), m_nNumValues(0) { #ifdef CHECK_TREES
g_treeChecker.AddTree(this); #endif
}
CEvalTree::CEvalTree(const CEvalTree& Other) : m_lRef(0), m_pStart(NULL), m_nNumValues(0) { #ifdef CHECK_TREES
g_treeChecker.AddTree(this); #endif
*this = Other; } CEvalTree::~CEvalTree() { #ifdef CHECK_TREES
g_treeChecker.RemoveTree(this); #endif
delete m_pStart; }
bool CEvalTree::SetBool(BOOL bVal) { CInCritSec ics(&m_cs);
delete m_pStart; CValueNode* pNode; if (bVal) { pNode = CValueNode::GetStandardTrue(); if(pNode == NULL) return false; } else pNode = CValueNode::GetStandardFalse(); m_pStart = pNode; m_nNumValues = 1; if(!m_ObjectInfo.SetLength(1)) return false;
return true; }
bool CEvalTree::IsFalse() { return (m_pStart == NULL); }
bool CEvalTree::IsValid() { return !CEvalNode::IsInvalid(m_pStart); }
int CEvalTree::Compare(CEvalNode* pArg1, CEvalNode* pArg2) { if(pArg1 == NULL) { if(pArg2 == NULL) return 0; else return 1; } else if(pArg2 == NULL) return -1; else if(CEvalNode::GetType(pArg1) != CEvalNode::GetType(pArg2)) return CEvalNode::GetType(pArg1) - CEvalNode::GetType(pArg2); else return pArg1->Compare(pArg2); }
HRESULT CEvalTree::CreateFromQuery(CContextMetaData* pNamespace, LPCWSTR wszQuery, long lFlags, long lMaxTokens) { CTextLexSource src((LPWSTR)wszQuery); QL1_Parser parser(&src); QL_LEVEL_1_RPN_EXPRESSION *pExp = 0; int nRes = parser.Parse(&pExp); CDeleteMe<QL_LEVEL_1_RPN_EXPRESSION> deleteMe(pExp);
if (nRes) return WBEM_E_INVALID_QUERY; HRESULT hres = CreateFromQuery(pNamespace, pExp, lFlags, lMaxTokens); return hres; } HRESULT CEvalTree::CreateFromQuery(CContextMetaData* pNamespace, QL_LEVEL_1_RPN_EXPRESSION* pQuery, long lFlags, long lMaxTokens) { return CreateFromQuery(pNamespace, pQuery->bsClassName, pQuery->nNumTokens, pQuery->pArrayOfTokens, lFlags, lMaxTokens); }
HRESULT CEvalTree::CreateFromQuery(CContextMetaData* pNamespace, LPCWSTR wszClassName, int nNumTokens, QL_LEVEL_1_TOKEN* apTokens, long lFlags, long lMaxTokens) { CInCritSec ics(&m_cs);
HRESULT hres;
// Create basic implication list
// =============================
_IWmiObject* pObj = NULL; hres = pNamespace->GetClass(wszClassName, &pObj); if(FAILED(hres)) { return hres; }
CReleaseMe rm1(pObj);
try { CImplicationList Implications(lFlags); CPropertyName EmptyName; Implications.ImproveKnown(&EmptyName, pObj); #ifdef CHECK_TREES
CheckTrees(); #endif
CEvalNode* pWhere = NULL; if(nNumTokens) { // Convert the token list to DNF
// =============================
CDNFExpression DNF; QL_LEVEL_1_TOKEN* pEnd = apTokens + nNumTokens - 1; hres = DNF.CreateFromTokens(pEnd, 0, lMaxTokens); if(FAILED(hres)) return hres;
if(pEnd != apTokens - 1) { return WBEM_E_CRITICAL_ERROR; } DNF.Sort(); // Build a tree for the token list
// ===============================
hres = CreateFromDNF(pNamespace, Implications, &DNF, &pWhere); if(FAILED(hres)) { return hres; } } else { pWhere = CValueNode::GetStandardTrue(); if(pWhere == NULL) return WBEM_E_OUT_OF_MEMORY; } // Add inheritance check
// =====================
CInheritanceNode* pInhNode = new CInheritanceNode; if (!pInhNode) return WBEM_E_OUT_OF_MEMORY; hres = pInhNode->AddClass(pNamespace, wszClassName, (_IWmiObject*)pObj, pWhere); if(FAILED(hres)) { delete pWhere; delete pInhNode; return hres; } if(!m_ObjectInfo.SetLength(Implications.GetRequiredDepth())) { delete pInhNode; return WBEM_E_OUT_OF_MEMORY; } delete m_pStart; m_pStart = pInhNode; m_nNumValues = 1; #ifdef CHECK_TREES
CheckTrees(); #endif
Optimize(pNamespace); #ifdef CHECK_TREES
CheckTrees(); #endif
return WBEM_S_NO_ERROR; } catch (CX_MemoryException) { return WBEM_E_OUT_OF_MEMORY; } }
// extension of BuildFromToken to build nodes that have two properties
// e.g. this would service "select * from class where prop1 < prop2"
HRESULT CEvalTree::BuildTwoPropFromToken(CContextMetaData* pNamespace, CImplicationList& Implications, QL_LEVEL_1_TOKEN& Token, CEvalNode** ppRes) { HRESULT hres; CEmbeddingInfo leftInfo, rightInfo; if(!leftInfo.SetPropertyNameButLast(Token.PropertyName)) return WBEM_E_OUT_OF_MEMORY; if(!rightInfo.SetPropertyNameButLast(Token.PropertyName2)) return WBEM_E_OUT_OF_MEMORY;
_IWmiObject* pLeftClass; hres = leftInfo.Compile(pNamespace, Implications, &pLeftClass); if(FAILED(hres)) return hres; if(pLeftClass == NULL) return WBEMESS_E_REGISTRATION_TOO_BROAD;
_IWmiObject* pRightClass; hres = rightInfo.Compile(pNamespace, Implications, &pRightClass); if(FAILED(hres)) return hres; if(pRightClass == NULL) { pLeftClass->Release(); return WBEMESS_E_REGISTRATION_TOO_BROAD; }
// Get the property types and handles
// ==================================
LPCWSTR wszLeftPropName = Token.PropertyName.GetStringAt( Token.PropertyName.GetNumElements() - 1); LPCWSTR wszRightPropName = Token.PropertyName2.GetStringAt( Token.PropertyName2.GetNumElements() - 1);
CIMTYPE ctLeft, ctRight; long lLeftPropHandle, lRightPropHandle; hres = pLeftClass->GetPropertyHandleEx(wszLeftPropName, 0L, &ctLeft, &lLeftPropHandle); pLeftClass->Release(); if(FAILED(hres)) return hres; hres = pRightClass->GetPropertyHandleEx(wszRightPropName, 0L, &ctRight, &lRightPropHandle); pRightClass->Release(); if(FAILED(hres)) return hres;
if( ((ctLeft & CIM_FLAG_ARRAY) != 0) || (ctLeft == CIM_OBJECT) || ((ctRight & CIM_FLAG_ARRAY) != 0) || (ctRight == CIM_OBJECT) ) return WBEM_E_NOT_SUPPORTED;
// if the type of either node is reference or date, go to dumb
if ( (ctLeft == CIM_DATETIME) || (ctLeft == CIM_REFERENCE) || (ctRight == CIM_DATETIME) || (ctRight == CIM_REFERENCE) ) { if(ctLeft != ctRight) return WBEM_E_TYPE_MISMATCH;
CDumbNode* pDumb = NULL; try { pDumb = new CDumbNode(Token); if(pDumb == NULL) return WBEM_E_OUT_OF_MEMORY; } catch (CX_MemoryException) { return WBEM_E_OUT_OF_MEMORY; }
hres = pDumb->Validate(pLeftClass); if(FAILED(hres)) { delete pDumb; return hres; } *ppRes = pDumb; return WBEM_S_NO_ERROR; } // if the node is mismatched (different types in either node)
// we'll want to create the most flexible node needed to hold both types
CIMTYPE ctNode = ctLeft;
CPropertyNode* pNode = NULL;
try { bool bMismatchedNode = (ctLeft != ctRight); if (bMismatchedNode) { // we'll be real forgiving about strings matching strings
if ( (ctLeft == CIM_STRING) || (ctRight == CIM_STRING) ) pNode = new CTwoMismatchedStringNode; else if ( (ctRight == CIM_REAL32) || (ctRight == CIM_REAL64) || (ctLeft == CIM_REAL32) || (ctLeft == CIM_REAL64) ) pNode = new CTwoMismatchedFloatNode; else if ( (ctLeft == CIM_UINT64) || (ctRight == CIM_UINT64) ) pNode = new CTwoMismatchedUInt64Node; else if ( (ctLeft == CIM_SINT64 ) || (ctRight == CIM_SINT64 ) ) pNode = new CTwoMismatchedInt64Node; else if ( (ctRight == CIM_UINT32) || (ctLeft == CIM_UINT32) ) pNode = new CTwoMismatchedUIntNode; else pNode = new CTwoMismatchedIntNode; } else // not mistmatched - go with the exact type
{ // Create the Proper node
// =====================
switch(ctNode) { case CIM_SINT8: pNode = new TTwoScalarPropNode<signed char>; break; case CIM_UINT8: pNode = new TTwoScalarPropNode<unsigned char>; break; case CIM_SINT16: pNode = new TTwoScalarPropNode<short>; break; case CIM_UINT16: case CIM_CHAR16: pNode = new TTwoScalarPropNode<unsigned short>; break; case CIM_SINT32: pNode = new TTwoScalarPropNode<long>; break; case CIM_UINT32: pNode = new TTwoScalarPropNode<unsigned long>; break; case CIM_SINT64: pNode = new TTwoScalarPropNode<__int64>; break; case CIM_UINT64: pNode = new TTwoScalarPropNode<unsigned __int64>; break; case CIM_REAL32: pNode = new TTwoScalarPropNode<float>; break; case CIM_REAL64: pNode = new TTwoScalarPropNode<double>; break; case CIM_BOOLEAN: pNode = new TTwoScalarPropNode<VARIANT_BOOL>; break; case CIM_STRING: pNode = new CTwoStringPropNode; break; case CIM_DATETIME: case CIM_REFERENCE: { CDumbNode* pDumb = new CDumbNode(Token); hres = pDumb->Validate(pLeftClass); if(FAILED(hres)) { delete pDumb; return hres; } else { *ppRes = pDumb; return WBEM_S_NO_ERROR; } } return WBEM_S_NO_ERROR; default: return WBEM_E_CRITICAL_ERROR; } } } catch (CX_MemoryException) { return WBEM_E_OUT_OF_MEMORY; }
if (!pNode) return WBEM_E_OUT_OF_MEMORY;
if(!pNode->SetEmbeddingInfo(&leftInfo)) return WBEM_E_OUT_OF_MEMORY; if(!pNode->SetPropertyInfo(wszLeftPropName, lLeftPropHandle)) return WBEM_E_OUT_OF_MEMORY;
((CTwoPropNode*)pNode)->SetRightEmbeddingInfo(&rightInfo); ((CTwoPropNode*)pNode)->SetRightPropertyInfo(wszRightPropName, lRightPropHandle);
hres = pNode->SetOperator(Token.nOperator); if(FAILED(hres)) return hres;
*ppRes = pNode; return WBEM_S_NO_ERROR; }
HRESULT CEvalTree::BuildFromToken(CContextMetaData* pNamespace, CImplicationList& Implications, QL_LEVEL_1_TOKEN& Token, CEvalNode** ppRes) { HRESULT hres;
if (Token.m_bPropComp) { hres = BuildTwoPropFromToken(pNamespace, Implications, Token, ppRes); if(hres == WBEMESS_E_REGISTRATION_TOO_BROAD || hres == WBEM_E_INVALID_PROPERTY) { //
// Not enough information to use efficient evaluation
//
CDumbNode* pNode = NULL; try { pNode = new CDumbNode(Token); if(pNode == NULL) return WBEM_E_OUT_OF_MEMORY; } catch (CX_MemoryException) { return WBEM_E_OUT_OF_MEMORY; }
*ppRes = pNode; return WBEM_S_NO_ERROR; } else return hres; }
//
// Retrieve event class definition
//
_IWmiObject* pEventClass; hres = Implications.FindClassForProp(NULL, 0, &pEventClass); if(FAILED(hres)) return hres; if(pEventClass == NULL) return WBEM_E_INVALID_QUERY; CReleaseMe rm1((IWbemClassObject*)pEventClass);
if(Token.nOperator == QL1_OPERATOR_ISA) { //
// Inheritance node are rarely applicable in Nova --- we have no way
// of telling *which definition* of the class is being referenced. Thus,
// we only construct an inheritance node in one case --- where the
// embedded object in question is a property of an instance operation
// event. These we trust.
//
if(pEventClass->InheritsFrom(L"__InstanceOperationEvent") == S_OK) { //
// OK, can use an inheritance node
//
if(V_VT(&Token.vConstValue) != VT_BSTR) return WBEM_E_INVALID_QUERY; BSTR strClassName = V_BSTR(&Token.vConstValue); CInheritanceNode* pNode = NULL; try { pNode = new CInheritanceNode; if (!pNode) return WBEM_E_OUT_OF_MEMORY; } catch (CX_MemoryException) { return WBEM_E_OUT_OF_MEMORY; } CDeleteMe<CInheritanceNode> deleteMe(pNode); CEvalNode* pTrue = CValueNode::GetStandardTrue(); if(pTrue == NULL) return WBEM_E_OUT_OF_MEMORY;
hres = pNode->AddClass(pNamespace, strClassName, pTrue); if(FAILED(hres)) return hres; if(!pNode->SetPropertyInfo(pNamespace, Token.PropertyName)) return WBEM_E_OUT_OF_MEMORY; hres = pNode->Compile(pNamespace, Implications); if(FAILED(hres)) return hres; // Record the fact that TRUE branch is being taken
// ===============================================
pNode->RecordBranch(pNamespace, Implications, 1); // in the event that we made it this far,
// we no longer WANT to delete node
deleteMe = NULL; *ppRes = pNode; return WBEM_S_NO_ERROR; } else { //
// May not use an inheritance node --- use a dumb one instead
//
CDumbNode* pNode = NULL; try { pNode = new CDumbNode(Token); if(pNode == NULL) return WBEM_E_OUT_OF_MEMORY; } catch (CX_MemoryException) { return WBEM_E_OUT_OF_MEMORY; }
hres = pNode->Validate(pEventClass); if(FAILED(hres)) { delete pNode; return hres; } *ppRes = pNode; return WBEM_S_NO_ERROR; } } else { //
// Attempt to compile the embedding portion. This will only succeed if
// the rest of the query implies enough information for us to know
// exactly what class the embedded object is
//
CEmbeddingInfo Info; if(!Info.SetPropertyNameButLast(Token.PropertyName)) return WBEM_E_OUT_OF_MEMORY;
_IWmiObject* pClass; hres = Info.Compile(pNamespace, Implications, &pClass); if(hres == WBEMESS_E_REGISTRATION_TOO_BROAD || hres == WBEM_E_INVALID_PROPERTY || // invalid or not yet known?
pClass == NULL) { //
// Not enough information --- have to use the dumb node
//
CDumbNode* pNode = NULL; try { pNode = new CDumbNode(Token); if(pNode == NULL) return WBEM_E_OUT_OF_MEMORY; } catch (CX_MemoryException) { return WBEM_E_OUT_OF_MEMORY; } hres = pNode->Validate(pEventClass); if(FAILED(hres)) { delete pNode; return hres; } *ppRes = pNode; return WBEM_S_NO_ERROR; } if(FAILED(hres)) return hres;
//
// We do know the class definition. Check if this is a system property,
// though, in which case we still have toi use a dumb node
//
LPCWSTR wszPropName = Token.PropertyName.GetStringAt( Token.PropertyName.GetNumElements() - 1);
if(wszPropName == NULL) return WBEM_E_OUT_OF_MEMORY;
if(wszPropName[0] == '_') { CDumbNode* pNode = NULL; try { pNode = new CDumbNode(Token); if(pNode == NULL) return WBEM_E_OUT_OF_MEMORY; } catch (CX_MemoryException) { return WBEM_E_OUT_OF_MEMORY; }
hres = pNode->Validate(pEventClass); if(FAILED(hres)) { delete pNode; return hres; } *ppRes = pNode; return WBEM_S_NO_ERROR; } // Get the property type and handle
// ================================
CIMTYPE ct; long lPropHandle; hres = pClass->GetPropertyHandleEx(wszPropName, 0L, &ct, &lPropHandle); pClass->Release(); if(FAILED(hres)) return hres; if(((ct & CIM_FLAG_ARRAY) != 0) || (ct == CIM_OBJECT)) return WBEM_E_NOT_SUPPORTED;
// Coerce the constant to the right type
// =====================================
VARIANT v; VariantInit(&v); CClearMe cm(&v); if(V_VT(&Token.vConstValue) != VT_NULL) { hres = ChangeVariantToCIMTYPE(&v, &Token.vConstValue, ct); if(FAILED(hres)) return hres; } else { V_VT(&v) = VT_NULL; }
//
// Create the right node
//
CPropertyNode* pNode = NULL; try { if ( Token.nOperator != QL1_OPERATOR_LIKE && Token.nOperator != QL1_OPERATOR_UNLIKE ) { switch(ct) { case CIM_SINT8: pNode = new CScalarPropNode<signed char>; break; case CIM_UINT8: pNode = new CScalarPropNode<unsigned char>; break; case CIM_SINT16: pNode = new CScalarPropNode<short>; break; case CIM_UINT16: case CIM_CHAR16: pNode = new CScalarPropNode<unsigned short>; break; case CIM_SINT32: pNode = new CScalarPropNode<long>; break; case CIM_UINT32: pNode = new CScalarPropNode<unsigned long>; break; case CIM_SINT64: pNode = new CScalarPropNode<__int64>; break; case CIM_UINT64: pNode = new CScalarPropNode<unsigned __int64>; break; case CIM_REAL32: pNode = new CScalarPropNode<float>; break; case CIM_REAL64: pNode = new CScalarPropNode<double>; break; case CIM_BOOLEAN: pNode = new CScalarPropNode<VARIANT_BOOL>; break; case CIM_STRING: pNode = new CStringPropNode; break; case CIM_DATETIME: case CIM_REFERENCE: { CDumbNode* pDumb = new CDumbNode(Token); if(pDumb == NULL) return WBEM_E_OUT_OF_MEMORY;
hres = pDumb->Validate(pEventClass); if(FAILED(hres)) { delete pDumb; return hres; } else { *ppRes = pDumb; return WBEM_S_NO_ERROR; } } default: return WBEM_E_CRITICAL_ERROR; } } else { if ( V_VT(&v) != VT_BSTR ) return WBEM_E_INVALID_QUERY;
pNode = new CLikeStringPropNode; } } catch (CX_MemoryException) { return WBEM_E_OUT_OF_MEMORY; }
if (!pNode) return WBEM_E_OUT_OF_MEMORY;
if(!pNode->SetEmbeddingInfo(&Info)) { delete pNode; return WBEM_E_OUT_OF_MEMORY; }
if(!pNode->SetPropertyInfo(wszPropName, lPropHandle)) { delete pNode; return WBEM_E_OUT_OF_MEMORY; }
if(V_VT(&v) == VT_NULL) { pNode->SetNullTest(Token.nOperator); } else { //
// Check if the operator makes sense for the type
//
if(ct == CIM_BOOLEAN && (Token.nOperator != QL1_OPERATOR_EQUALS && Token.nOperator != QL1_OPERATOR_NOTEQUALS)) { // No < > for booleans
return WBEM_E_INVALID_QUERY; }
hres = pNode->SetOperator(Token.nOperator); if(FAILED(hres)) return hres; hres = pNode->SetTest(v); if(FAILED(hres)) return hres; }
*ppRes = pNode; return WBEM_S_NO_ERROR; } } HRESULT CEvalTree::Combine(CEvalNode* pArg1, CEvalNode* pArg2, int nOp, CContextMetaData* pNamespace, CImplicationList& Implications, bool bDeleteArg1, bool bDeleteArg2, CEvalNode** ppRes) { HRESULT hres;
try { //
// Apply the extra implications of the nodes being combined
//
CImplicationList* pArg1List = NULL; if(pArg1 && pArg1->GetExtraImplications()) { pArg1List = new CImplicationList(*pArg1->GetExtraImplications(), false); if(pArg1List == NULL) return WBEM_E_OUT_OF_MEMORY; } CDeleteMe<CImplicationList> dm1(pArg1List); CImplicationList* pArg2List = NULL; if(pArg2 && pArg2->GetExtraImplications()) { pArg2List = new CImplicationList(*pArg2->GetExtraImplications(), false); if(pArg2List == NULL) return WBEM_E_OUT_OF_MEMORY; } CDeleteMe<CImplicationList> dm2(pArg2List); if(pArg1List || pArg2List) { CImplicationList TheseImplications(Implications); if(pArg1List) { hres = TheseImplications.MergeIn(pArg1List); if(FAILED(hres)) return hres; } if(pArg2List) { hres = TheseImplications.MergeIn(pArg2List); if(FAILED(hres)) return hres; } //
// Call inner combine to do everything but the implications
//
hres = InnerCombine(pArg1, pArg2, nOp, pNamespace, TheseImplications, bDeleteArg1, bDeleteArg2, ppRes); } else { //
// Call inner combine to do everything but the implications
//
hres = InnerCombine(pArg1, pArg2, nOp, pNamespace, Implications, bDeleteArg1, bDeleteArg2, ppRes); } if(FAILED(hres)) return hres; //
// The implication of the combined node is the combination of the
// individual node implications. It does not matter what the operation
// is: by the time we have arrived here, we have arrived to these
// respective
// points in the individual trees, so the implications have commenced.
// OK, I am convinced :-)
//
if(*ppRes) { CImplicationList* pResultList = NULL; if(pArg1List || pArg2List) { //
// There is actually some implication info in one of them ---
// merge them
//
if(pArg1List == NULL) { pResultList = new CImplicationList(*pArg2List, false); if(pResultList == NULL) return WBEM_E_OUT_OF_MEMORY; } else { pResultList = new CImplicationList(*pArg1List, false); if(pResultList == NULL) return WBEM_E_OUT_OF_MEMORY; if(pArg2List != NULL) { hres = pResultList->MergeIn(pArg2List); if(FAILED(hres)) { delete pResultList; return hres; } } } } return (*ppRes)->SetExtraImplications(pResultList); // acquires
} else return S_OK; } catch (CX_MemoryException) { return WBEM_E_OUT_OF_MEMORY; } }
HRESULT CEvalTree::InnerCombine(CEvalNode* pArg1, CEvalNode* pArg2, int nOp, CContextMetaData* pNamespace, CImplicationList& Implications, bool bDeleteArg1, bool bDeleteArg2, CEvalNode** ppRes) { HRESULT hres; *ppRes = NULL;
if ((pArg1 == NULL) && (pArg2 == NULL)) return WBEM_S_NO_ERROR;
if(CEvalNode::IsInvalid(pArg1) || CEvalNode::IsInvalid(pArg2)) { //
// Invalid branches cannot be taken, so the result is invalid
//
*ppRes = CValueNode::GetStandardInvalid(); if(bDeleteArg1) delete pArg1; if(bDeleteArg2) delete pArg2; return S_OK; }
int arg1Type = CEvalNode::GetType(pArg1); int arg2Type = CEvalNode::GetType(pArg2);
// Check if merging the nodes is called for
// ========================================
if(nOp != EVAL_OP_AND && IsMergeAdvisable(pArg1, pArg2, Implications) != WBEM_S_NO_ERROR) { // Create an OR node instead
// =========================
COrNode* pNew = NULL; try { pNew = new COrNode; if(pNew == NULL) return WBEM_E_OUT_OF_MEMORY; } catch (CX_MemoryException) { return WBEM_E_OUT_OF_MEMORY; }
if(bDeleteArg1) { hres = pNew->AddBranch(pArg1); } else { CEvalNode* pClone = pArg1->Clone(); if(pClone == NULL) return WBEM_E_OUT_OF_MEMORY; hres = pNew->AddBranch(pClone); } if(FAILED(hres)) return hres; if(bDeleteArg2) { hres = pNew->AddBranch(pArg2); } else { CEvalNode* pClone = pArg2->Clone(); if(pClone == NULL) return WBEM_E_OUT_OF_MEMORY; hres = pNew->AddBranch(pClone); } if(FAILED(hres)) { delete pNew; return hres; }
*ppRes = pNew; return WBEM_S_NO_ERROR; } // Delegate same-type operations to the type
// =========================================
if(arg1Type == arg2Type) { if ( ((pArg1 == NULL) || (pArg2 == NULL)) // well, gosh - if we've already decided they're the same type, no reason for redundant checks...
&& (arg1Type == EVAL_NODE_TYPE_VALUE)) { if(nOp == EVAL_OP_AND) { // FALSE AND anything is FALSE
// ===========================
*ppRes = NULL; if(bDeleteArg1) delete pArg1; if(bDeleteArg2) delete pArg2;
return WBEM_S_NO_ERROR; }
// FALSE combined in any other way with anything is that thing
// ===========================================================
if (pArg1) {
if (bDeleteArg1) *ppRes = pArg1; else *ppRes = pArg1->Clone();
if(*ppRes == NULL) return WBEM_E_OUT_OF_MEMORY; } else if (pArg2) { if (bDeleteArg2) *ppRes = pArg2; else *ppRes = pArg2->Clone();
if(*ppRes == NULL) return WBEM_E_OUT_OF_MEMORY; } else // can't touch this
*ppRes = NULL;
return WBEM_S_NO_ERROR; } else // not value nodes
return pArg1->CombineWith(pArg2, nOp, pNamespace, Implications, bDeleteArg1, bDeleteArg2, ppRes); } // Check if one is an OR
// =====================
if(arg1Type == EVAL_NODE_TYPE_OR) return pArg1->CombineWith(pArg2, nOp, pNamespace, Implications, bDeleteArg1, bDeleteArg2, ppRes);
if(arg2Type == EVAL_NODE_TYPE_OR) return pArg2->CombineWith(pArg1, FlipEvalOp(nOp), pNamespace, Implications, bDeleteArg2, bDeleteArg1, ppRes); // One leaf, one branch
// ====================
if(arg1Type == EVAL_NODE_TYPE_VALUE) { return CombineLeafWithBranch((CValueNode*)pArg1, (CBranchingNode*)pArg2, nOp, pNamespace, Implications, bDeleteArg1, bDeleteArg2, ppRes); } else // it's pArg2
{ return CombineLeafWithBranch((CValueNode*)pArg2, (CBranchingNode*)pArg1, FlipEvalOp(nOp), pNamespace, Implications, bDeleteArg2, bDeleteArg1, ppRes); } }
// static
HRESULT CEvalTree::CombineLeafWithBranch(CValueNode* pArg1, CBranchingNode* pArg2, int nOp, CContextMetaData* pNamespace, CImplicationList& Implications, bool bDeleteArg1, bool bDeleteArg2, CEvalNode** ppRes) { HRESULT hres;
if (pArg1 == NULL) { *ppRes = NULL; if(nOp == EVAL_OP_AND) { // Anding a FALSE with something --- getting a FALSE!
// ==================================================
if(bDeleteArg2) delete pArg2;
return WBEM_S_NO_ERROR; } else { // Anything else combined with FALSE gives itself!
// ===============================================
// Well, this is true, but the problem is with optimizations.
// Some branches in X might not be valid under the implications in
// this branch of the tree, and so need to be removed. For now, I
// will simply turn off this short-circuiting path. It may turn out
// that there are some critical performance gains to be had by
// keeping it, in which case we would need to put this back and
// make an efficient pass through it, checking branches.
//
/*
if(bDeleteArg2) *ppRes = pArg2; else *ppRes = pArg2->Clone();
return WBEM_S_NO_ERROR; */ } } else { // Try to short-circuit
// ====================
hres = pArg1->TryShortCircuit(pArg2, nOp, bDeleteArg1, bDeleteArg2, ppRes); if(FAILED(hres)) return hres; // hard-failure
if(hres == WBEM_S_NO_ERROR) return WBEM_S_NO_ERROR; // short-circuit succeeded
}
// Didn't short-circuit
// ====================
return ((CBranchingNode*)pArg2)->CombineInOrderWith(pArg1, FlipEvalOp(nOp), pNamespace, Implications, bDeleteArg2, bDeleteArg1, ppRes); }
HRESULT CEvalTree::Evaluate(CObjectInfo& Info, CEvalNode* pStart, CSortedArray& trueIDs) { HRESULT hres;
// Loop as long as we are still seeing branching nodes
// ===================================================
CEvalNode* pCurrent = pStart; int nType; while((nType = CEvalNode::GetType(pCurrent)) == EVAL_NODE_TYPE_BRANCH) { hres = ((CBranchingNode*)pCurrent)->Evaluate(Info, &pCurrent); if(FAILED(hres)) return hres; }
if(nType == EVAL_NODE_TYPE_OR) { hres = ((COrNode*)pCurrent)->Evaluate(Info, trueIDs); if(FAILED(hres)) return hres; } else // VALUE
{ if (CValueNode::AreAnyTrue((CValueNode*)pCurrent)) ((CValueNode*)pCurrent)->AddTruesTo(trueIDs); }
return WBEM_S_NO_ERROR; }
HRESULT CEvalTree::Evaluate(IWbemObjectAccess* pObj, CSortedArray& trueIDs) { CInCritSec ics(&m_cs);
trueIDs.SetSize(0);
HRESULT hres = WBEM_S_NO_ERROR; if(m_pStart != NULL) { m_ObjectInfo.SetObjectAt(0, (_IWmiObject*)pObj);
hres = Evaluate(m_ObjectInfo, m_pStart, trueIDs);
m_ObjectInfo.Clear(); }
return hres; }
HRESULT CEvalTree::Optimize(CContextMetaData* pNamespace) { CInCritSec ics(&m_cs);
if(m_pStart == NULL) return WBEM_S_NO_ERROR;
CEvalNode* pNew = NULL; HRESULT hres = m_pStart->Optimize(pNamespace, &pNew); if(pNew != m_pStart) { delete m_pStart; m_pStart = pNew; }
if(CEvalNode::GetType(m_pStart) == EVAL_NODE_TYPE_VALUE) { if(!m_ObjectInfo.SetLength(1)) return WBEM_E_OUT_OF_MEMORY; }
return hres; }
HRESULT CEvalTree::CombineWith(CEvalTree& Other, CContextMetaData* pNamespace, int nOp, long lFlags) { CInCritSec ics(&m_cs);
HRESULT hres;
try { CImplicationList Implications(lFlags); //
// Compute required object info depth. We are not set up to configure
// it properly, so we'll estimate the upper bound as the sum of the
// depths of the trees being merged. Except that the first object
// doesn't count --- it's the event itself. Unless one of the objects
// is empty --- in that case it doesn't mention the event itself, and
// so we should not subtract that 1.
//
long lRequiredDepth = m_ObjectInfo.GetLength() + Other.m_ObjectInfo.GetLength(); if(m_ObjectInfo.GetLength() > 0 && Other.m_ObjectInfo.GetLength() > 0) lRequiredDepth--; //
// Combine our Start node with the new tree's. Ours will be deleted in
// the process.
//
CEvalNode* pNew; hres = CEvalTree::Combine(m_pStart, Other.m_pStart, nOp, pNamespace, Implications, true, // delete ours
false, // don't touch theirs
&pNew); if(FAILED(hres)) { m_pStart = NULL; return hres; } m_pStart = pNew; if(!m_ObjectInfo.SetLength(lRequiredDepth)) return WBEM_E_OUT_OF_MEMORY; if(nOp == EVAL_OP_COMBINE || nOp == EVAL_OP_INVERSE_COMBINE) m_nNumValues += Other.m_nNumValues; return WBEM_S_NO_ERROR; } catch (CX_MemoryException) { return WBEM_E_OUT_OF_MEMORY; } }
HRESULT CEvalTree::IsMergeAdvisable(CEvalNode* pArg1, CEvalNode* pArg2, CImplicationList& Implications) { if(Implications.IsMergeMandatory()) return S_OK;
int arg1Type = CEvalNode::GetType(pArg1); int arg2Type = CEvalNode::GetType(pArg2); // if we have ONE non-false ValueNode, and ONE Branch Node, do not merge
if ( ((arg1Type == EVAL_NODE_TYPE_VALUE) && (arg2Type == EVAL_NODE_TYPE_BRANCH) && !CValueNode::IsAllFalse((CValueNode*)pArg1)) || ((arg2Type == EVAL_NODE_TYPE_VALUE) && (arg1Type == EVAL_NODE_TYPE_BRANCH) && !CValueNode::IsAllFalse((CValueNode*)pArg2)) ) return WBEM_S_FALSE; else // otherwise, if one of the nodes is not Branching, certainly yes (how hard can it be?)
if(arg1Type != EVAL_NODE_TYPE_BRANCH || arg2Type != EVAL_NODE_TYPE_BRANCH) { return WBEM_S_NO_ERROR; }
// They are both branching. If not about the same property, then certainly
// inadvisable, since there is very little to be gained
// ========================================================================
CBranchingNode* pBranching1 = (CBranchingNode*)pArg1; CBranchingNode* pBranching2 = (CBranchingNode*)pArg2;
if(CBranchingNode::ComparePrecedence(pBranching1, pBranching2)) return WBEM_S_FALSE; // Check if the nodes are inheritance --- in that case we can only merge if
// they have identical checks
// ========================================================================
if(pBranching1->GetSubType() == EVAL_NODE_TYPE_INHERITANCE) { // So is the other one, given that precedence is identical
// =======================================================
if(((CInheritanceNode*)pBranching1)->SubCompare( (CInheritanceNode*)pBranching2) != 0) { return WBEM_S_FALSE; } else { return WBEM_S_NO_ERROR; } } else if(pBranching1->GetSubType() == EVAL_NODE_TYPE_DUMB) { //
// Only merge if identical
//
if(((CDumbNode*)pBranching1)->SubCompare( (CDumbNode*)pBranching2) != 0) { return WBEM_S_FALSE; } else { return WBEM_S_NO_ERROR; } } // Same property. TBD: better checks
// ==================================
return WBEM_S_NO_ERROR; }
HRESULT CEvalTree::RemoveIndex(int nIndex) { CInCritSec ics(&m_cs);
if(m_pStart != NULL) { CRemoveIndexPredicate P(nIndex); m_pStart->ApplyPredicate(&P);
m_nNumValues--; }
return S_OK; }
HRESULT CEvalTree::UtilizeGuarantee(CEvalTree& Guaranteed, CContextMetaData* pNamespace) { CInCritSec ics(&m_cs); #ifdef DUMP_EVAL_TREES
FILE* f; f = fopen("c:\\log", "a"); fprintf(f, "\n\nORIGINAL:\n"); Dump(f); fprintf(f, "\n\nGUARANTEE:\n"); Guaranteed.Dump(f); fflush(f); #endif
#ifdef CHECK_TREES
CheckTrees(); #endif
//
// Combine them together
//
//
// This is a single-valued tree -- rebase it to 1 to distinguish from
// the guarantee
//
Rebase(1); HRESULT hres = CombineWith(Guaranteed, pNamespace, EVAL_OP_COMBINE, WBEM_FLAG_MANDATORY_MERGE); if(FAILED(hres)) return hres;
#ifdef DUMP_EVAL_TREES
fprintf(f, "AFTER MERGE:\n"); Dump(f); fflush(f); #endif
// Eliminate all nodes where Guaranteed is failing
// ===============================================
if(m_pStart) { CRemoveFailureAtIndexPredicate P(0); hres = m_pStart->ApplyPredicate(&P); if(FAILED(hres)) return hres; } m_nNumValues--;
#ifdef CHECK_TREES
CheckTrees(); #endif
#ifdef DUMP_EVAL_TREES
fprintf(f, "AFTER REMOVE:\n"); Dump(f); fflush(f); #endif
hres = Optimize(pNamespace); if(FAILED(hres)) return hres; Rebase((QueryID)-1);
#ifdef CHECK_TREES
CheckTrees(); #endif
#ifdef DUMP_EVAL_TREES
fprintf(f, "AFTER OPTIMIZE:\n"); Dump(f);
fclose(f); #endif
return S_OK; }
HRESULT CEvalTree::ApplyPredicate(CLeafPredicate* pPred) { CInCritSec ics(&m_cs);
if(m_pStart != NULL) m_pStart->ApplyPredicate(pPred);
return S_OK; }
void CEvalTree::operator=(const CEvalTree& Other) { CInCritSec ics(&m_cs);
delete m_pStart; m_pStart = (Other.m_pStart ? Other.m_pStart->Clone() : NULL);
if(m_pStart == NULL && Other.m_pStart != NULL) throw CX_MemoryException(); m_nNumValues = Other.m_nNumValues; if(!m_ObjectInfo.SetLength(m_nNumValues)) throw CX_MemoryException(); } // renumber the QueryIDs in the leaves of the tree
void CEvalTree::Rebase(QueryID newBase) { CRebasePredicate predRebase(newBase); ApplyPredicate(&predRebase); }
bool CEvalTree::Clear() { CInCritSec ics(&m_cs);
delete m_pStart; m_pStart = CValueNode::GetStandardFalse(); if(!m_ObjectInfo.SetLength(1)) return false;
m_nNumValues = 0; return true; }
void CEvalTree::Dump(FILE* f) { CEvalNode::DumpNode(f, 0, m_pStart); }
#ifdef CHECK_TREES
void CEvalTree::CheckNodes(CTreeChecker *pChecker) { CInCritSec ics2(&m_cs); if (m_pStart) m_pStart->CheckNode(pChecker); } #endif
HRESULT CEvalTree::CreateFromConjunction(CContextMetaData* pNamespace, CImplicationList& Implications, CConjunction* pConj, CEvalNode** ppRes) { HRESULT hres;
*ppRes = NULL;
// Build them for all tokens and AND together
// ==========================================
try { CImplicationList BranchImplications(Implications); for(int i = 0; i < pConj->GetNumTokens(); i++) { CEvalNode* pNew = NULL; hres = CEvalTree::BuildFromToken(pNamespace, BranchImplications, *pConj->GetTokenAt(i), &pNew); if(FAILED(hres)) { delete *ppRes; return hres; } if(i > 0) { CEvalNode* pOld = *ppRes; CEvalTree::Combine(pOld, pNew, EVAL_OP_AND, pNamespace, Implications, true, true, ppRes); // delete both
} else { *ppRes = pNew; } } return WBEM_S_NO_ERROR; } catch (CX_MemoryException) { return WBEM_E_OUT_OF_MEMORY; } }
HRESULT CEvalTree::CreateFromDNF(CContextMetaData* pNamespace, CImplicationList& Implications, CDNFExpression* pDNF, CEvalNode** ppRes) { HRESULT hres;
// Check if there is only one conjunction to talk about
// ====================================================
if(pDNF->GetNumTerms() == 1) { // Just build that one
// ===================
return CreateFromConjunction(pNamespace, Implications, pDNF->GetTermAt(0), ppRes); }
// Build them for all conjunctions and OR together
// ===============================================
CEvalNode* pRes = NULL; for(int i = 0; i < pDNF->GetNumTerms(); i++) { CEvalNode* pNew; hres = CreateFromConjunction(pNamespace, Implications, pDNF->GetTermAt(i), &pNew); if(FAILED(hres)) { delete pRes; return hres; }
if(pRes == NULL) { pRes = pNew; } else { CEvalNode* pNewRes = NULL; hres = CEvalTree::Combine(pRes, pNew, EVAL_OP_COMBINE, pNamespace, Implications, true, true, &pNewRes); if(FAILED(hres)) { delete pRes; delete pNew; return hres; } pRes = pNewRes; } }
*ppRes = pRes; return WBEM_S_NO_ERROR; }
HRESULT CEvalTree::CreateProjection(CEvalTree& Old, CContextMetaData* pMeta, CProjectionFilter* pFilter, EProjectionType eType, bool bDeleteOld) { delete m_pStart; m_pStart = NULL;
try { CImplicationList Implications; return CEvalTree::Project(pMeta, Implications, Old.m_pStart, pFilter, eType, bDeleteOld, &m_pStart); } catch (CX_MemoryException) { return WBEM_E_OUT_OF_MEMORY; } }
HRESULT CEvalTree::Project(CContextMetaData* pMeta, CImplicationList& Implications, CEvalNode* pOldNode, CProjectionFilter* pFilter, EProjectionType eType, bool bDeleteOld, CEvalNode** ppNewNode) { if(pOldNode == NULL) { *ppNewNode = NULL; return WBEM_S_NO_ERROR; }
return pOldNode->Project(pMeta, Implications, pFilter, eType, bDeleteOld, ppNewNode); }
CPropertyProjectionFilter::CPropertyProjectionFilter() { m_papProperties = new CUniquePointerArray<CPropertyName>; if(m_papProperties == NULL) throw CX_MemoryException(); }
CPropertyProjectionFilter::~CPropertyProjectionFilter() { delete m_papProperties; }
bool CPropertyProjectionFilter::IsInSet(CEvalNode* pNode) { if(CEvalNode::GetType(pNode) != EVAL_NODE_TYPE_BRANCH) return false;
CBranchingNode* pBranchingNode = (CBranchingNode*)pNode; CPropertyName* pEmbeddedObjName = pBranchingNode->GetEmbeddedObjPropName(); CPropertyName ThisName; if(pEmbeddedObjName) ThisName = *pEmbeddedObjName;
int nSubType = pBranchingNode->GetSubType(); if(nSubType == EVAL_NODE_TYPE_SCALAR || nSubType == EVAL_NODE_TYPE_STRING) { //
// Derived from CPropertyNode --- get its property name
//
ThisName.AddElement( ((CPropertyNode*)pBranchingNode)->GetPropertyName()); } else if(nSubType == EVAL_NODE_TYPE_INHERITANCE) { // No extra name parts
} else { //
// Two-prop, perhaps. Just say no
//
return false; }
//
// Search for the name in our list
//
for(int i = 0; i < m_papProperties->GetSize(); i++) { if(*(m_papProperties->GetAt(i)) == ThisName) return true; }
return false; }
bool CPropertyProjectionFilter::AddProperty(const CPropertyName& Prop) { CPropertyName* pProp = NULL; try { pProp = new CPropertyName(Prop); if(pProp == NULL) return false; } catch (CX_MemoryException) { return false; }
if(m_papProperties->Add(pProp) < 0) return false;
return true; }
|