//***************************************************************************

//

//  VPQUALS.CPP

//

//  Module: WBEM VIEW PROVIDER

//

//  Purpose: Contains the implementation of qualifier storage classes

//

// Copyright (c) 1998-2001 Microsoft Corporation, All Rights Reserved
//
//***************************************************************************

#include "precomp.h"
#include <provexpt.h>

#include <malloc.h>
#include <provcoll.h>
#include <provtempl.h>
#include <provmt.h>
#include <typeinfo.h>
#include <process.h>
#include <objbase.h>
#include <wbemidl.h>
#include <stdio.h>
#include <provcont.h>
#include <provevt.h>
#include <provthrd.h>
#include <provlog.h>
#include <cominit.h>

#include <dsgetdc.h>
#include <lmcons.h>

#include <instpath.h>
#include <genlex.h>
#include <sql_1.h>
#include <objpath.h>

#include <vpdefs.h>
#include <vpquals.h>
#include <vpserv.h>
#include <vptasks.h>

CStringW GetStringFromRPNToken(SQL_LEVEL_1_TOKEN* pRPNToken)
{
    CStringW ret;

	if (NULL != pRPNToken->pPropertyName)
	{
		ret = L'('; 
		ret += pRPNToken->pPropertyName;

		switch(pRPNToken->nOperator)
		{
			case SQL_LEVEL_1_TOKEN::OP_EQUAL:
			{
				ret += L'=';
			}
			break;
			case SQL_LEVEL_1_TOKEN::OP_NOT_EQUAL:
			{
				ret += L"<>";
			}
			break;
			case SQL_LEVEL_1_TOKEN::OP_EQUALorGREATERTHAN:
			{
				ret += L">=";
			}
			break;
			case SQL_LEVEL_1_TOKEN::OP_EQUALorLESSTHAN:
			{
				ret += L"<=";
			}
			break;
			case SQL_LEVEL_1_TOKEN::OP_LESSTHAN:
			{
				ret += L'<';
			}
			break;
			case SQL_LEVEL_1_TOKEN::OP_GREATERTHAN:
			{
				ret += L'>';
			}
			break;
			case SQL_LEVEL_1_TOKEN::OP_LIKE:
			{
				ret += L" like ";
			}
			break;
			default:
			{
				ret.Empty();
			}
		}

		if (!ret.IsEmpty())
		{
			switch (pRPNToken->vConstValue.vt)
			{
				case VT_NULL:
				{
					ret += L"null)";
				}
				break;
				case VT_BSTR:
				{
					if (pRPNToken->bConstIsStrNumeric)
					{
						ret += pRPNToken->vConstValue.bstrVal;
						ret += L')';
					}
					else
					{
						ret += L'\"';
						wchar_t* buff = new wchar_t[(wcslen(pRPNToken->vConstValue.bstrVal)*2) + 1];
						wchar_t* tmp = pRPNToken->vConstValue.bstrVal;
						wchar_t* tmpBuff = buff;

						while (*tmp != NULL)
						{
							if ((*tmp == L'\\') || (*tmp == L'"'))
							{
								*tmpBuff = L'\\';
								*tmpBuff++;
							}

							*tmpBuff = *tmp;
							*tmpBuff++;
							*tmp++;
						}

						*tmpBuff = 0;
						ret += buff;
						delete [] buff;
						ret += L"\")";
					}
				}
				break;
				case VT_BOOL:
				{
					if (pRPNToken->vConstValue.boolVal == VARIANT_TRUE)
					{
						ret += L"TRUE)";
					}
					else
					{
						ret += L"FALSE)";
					}
				}
				break ;

				case VT_I4:
				{
					WCHAR tmpBuff[20];
					tmpBuff[0] = L'\0';

					if ( swprintf(tmpBuff, L"%d", pRPNToken->vConstValue.lVal) )
					{
						ret += tmpBuff;
						ret += ')';
					}
					else
					{
						ret.Empty();
					}
				}
				break;
				case VT_I2:
				{
					WCHAR tmpBuff[20];
					tmpBuff[0] = L'\0';

					if ( swprintf(tmpBuff, L"%d", (int)pRPNToken->vConstValue.iVal) )
					{
						ret += tmpBuff;
						ret += ')';
					}
					else
					{
						ret.Empty();
					}
				}
				break;
				case VT_UI1:
				{
					WCHAR tmpBuff[20];
					tmpBuff[0] = L'\0';

					if ( swprintf(tmpBuff, L"%d", (int)pRPNToken->vConstValue.bVal) )
					{
						ret += tmpBuff;
						ret += ')';
					}
					else
					{
						ret.Empty();
					}
				}
				break;
				case VT_R4:
				{
					WCHAR tmpBuff[25];
					tmpBuff[0] = L'\0';

					if ( swprintf(tmpBuff, L"%G", pRPNToken->vConstValue.fltVal) )
					{
						ret += tmpBuff;
						ret += ')';
					}
					else
					{
						ret.Empty();
					}
				}
				break;
				case VT_R8:
				{
					WCHAR tmpBuff[25];
					tmpBuff[0] = L'\0';

					if ( swprintf(tmpBuff, L"%lG", pRPNToken->vConstValue.dblVal) )
					{
						ret += tmpBuff;
						ret += ')';
					}
					else
					{
						ret.Empty();
					}
				}
				break;
				default:
				{
					ret.Empty();
				}
			}
		}
	}
    
	return ret;
}

CStringW GetStringFromRPN(SQL_LEVEL_1_RPN_EXPRESSION* pRPN, DWORD num_extra,
						 SQL_LEVEL_1_TOKEN* pExtraTokens, BOOL bAllprops)
{
	CStringW ret;

	if (NULL == pRPN)
	{
		return ret;
	}

	if (NULL != pRPN->bsClassName)
	{
		CStringW props;

		if ((bAllprops) || (0 == pRPN->nNumberOfProperties))
		{
			props = L'*';
		}
		else
		{
			props = pRPN->pbsRequestedPropertyNames[0];

			for (int x = 1; x < pRPN->nNumberOfProperties; x++)
			{
				props += L", ";
				props += pRPN->pbsRequestedPropertyNames[x];
			}

			props += L", ";
			props += WBEM_PROPERTY_PATH;
			props += L", ";
			props += WBEM_PROPERTY_SERVER;
		}

		ret = L"Select ";
		ret += props;
		ret += L" From ";
		ret += pRPN->bsClassName;

		if ((0 != pRPN->nNumTokens) || (0 != num_extra))
		{
			CStringW whereStr;
			CArray<CStringW, LPCWSTR> exprStack;

			//not likely to get more than five expressions in a row!
			//if we do, we'll grow the array!
			exprStack.SetSize(0, 5);
			DWORD stack_count = 0;

			for (int x = 0; x < (pRPN->nNumTokens + num_extra); x++)
			{
				SQL_LEVEL_1_TOKEN* pToken;

				if (x < pRPN->nNumTokens)
				{
					pToken = &(pRPN->pArrayOfTokens[x]);
				}
				else
				{
					pToken = &(pExtraTokens[x - pRPN->nNumTokens]);
				}

				if (SQL_LEVEL_1_TOKEN::OP_EXPRESSION == pToken->nTokenType)
				{
					if (whereStr.IsEmpty())
					{
						whereStr = GetStringFromRPNToken(pToken);

						if (whereStr.IsEmpty())
						{
							ret.Empty();
							break;
						}
					}
					else
					{
						exprStack.SetAtGrow(stack_count, GetStringFromRPNToken(pToken));

						if (exprStack[stack_count].IsEmpty())
						{
							ret.Empty();
							break;
						}

						stack_count++;
					}
				}
				else if (SQL_LEVEL_1_TOKEN::TOKEN_NOT == pToken->nTokenType)
				{
					CStringW tempStr(L"(Not ");
					
					if (stack_count > 0)
					{
						tempStr += exprStack[stack_count-1];
						tempStr += L')';
						exprStack.SetAt(stack_count-1, tempStr);
					}
					else if (!whereStr.IsEmpty())
					{
						tempStr += whereStr;
						tempStr += L')';
						whereStr = tempStr;
					}
					else
					{
						ret.Empty();
						break;
					}
				}
				else
				{
					CStringW opStr;
					
					if (SQL_LEVEL_1_TOKEN::TOKEN_AND == pToken->nTokenType)
					{
						opStr = L" And ";
					}
					else if (SQL_LEVEL_1_TOKEN::TOKEN_OR == pToken->nTokenType)
					{
						opStr = L" Or ";
					}
					else
					{
						ret.Empty();
						break;
					}

					CStringW tempStr(L'(');

					if (stack_count > 1)
					{
						tempStr += exprStack[stack_count-2];
						tempStr += opStr;
						tempStr += exprStack[stack_count-1];
						tempStr += L')';
						exprStack.SetAt(stack_count-2, tempStr);
						stack_count = stack_count--;
					}
					else if (stack_count == 1)
					{
						tempStr += whereStr;
						tempStr += opStr;
						tempStr += exprStack[0];
						tempStr += L')';
						whereStr = tempStr;
						stack_count = 0;
					}
					else
					{
						ret.Empty();
						whereStr.Empty();
						break;
					}
				}
			}

			exprStack.RemoveAll();

			if (whereStr.IsEmpty() || (stack_count != 0))
			{
				ret.Empty();
			}
			else
			{
				ret += L" Where ";
				ret += whereStr;
			}
		}
	}

	return ret;
}

CSourceQualifierItem::CSourceQualifierItem(wchar_t* qry, IWbemClassObject* obj)
: m_pClassObj(NULL), m_RPNExpr(NULL)
{
	m_isValid = FALSE;

	m_QueryStr = qry;

	if (NULL != qry)
	{
		CTextLexSource querySource(qry);
		SQL1_Parser sqlParser(&querySource);
		m_isValid = SQL1_Parser::SUCCESS == sqlParser.Parse(&m_RPNExpr);
	}

	m_pClassObj = obj;

	if (NULL != m_pClassObj)
	{
		m_pClassObj->AddRef();
	}
}

CSourceQualifierItem::~CSourceQualifierItem()
{
	if (NULL != m_RPNExpr)
	{
		delete m_RPNExpr;
	}

	if (NULL != m_pClassObj)
	{
		m_pClassObj->Release();
	}
}

void CSourceQualifierItem::SetClassObject(IWbemClassObject* pObj)
{
	if (NULL != m_pClassObj)
	{
		m_pClassObj->Release();
	}

	if (NULL != pObj)
	{
		pObj->AddRef();
	}

	m_pClassObj = pObj;
}

IWbemClassObject* CSourceQualifierItem::GetClassObject()
{
	if (NULL != m_pClassObj)
	{
		m_pClassObj->AddRef();
	}

	return m_pClassObj;
}

BSTR CSourceQualifierItem::GetClassName()
{
	if (NULL != m_RPNExpr)
	{
		return m_RPNExpr->bsClassName;
	}

	return NULL;
}

CNSpaceQualifierItem::CNSpaceQualifierItem(const wchar_t* ns_path)
{
	m_Valid = FALSE;
	m_ServObjs = NULL;
	m_NSPaths = NULL;
	m_Count = 0;

	if (NULL != ns_path)
	{
		Parse(ns_path);
	}
}

CNSpaceQualifierItem::~CNSpaceQualifierItem()
{
	if (NULL != m_ServObjs)
	{
		for (UINT x = 0; x < m_Count; x++)
		{
			if (NULL != m_ServObjs[x])
			{
				m_ServObjs[x]->Release();
			}
		}

		delete [] m_ServObjs;
	}

	if (m_NSPaths != NULL)
	{
		delete [] m_NSPaths;
	}
}

void CNSpaceQualifierItem::Parse(const wchar_t* ns_path)
{
	wchar_t* buff = _wcsdup(ns_path);

	if (buff == NULL)
	{
		throw Heap_Exception(Heap_Exception::HEAP_ERROR::E_ALLOCATION_ERROR);
	}

	wchar_t* tmp = wcsstr(buff, NS_DELIMIT);
	CFreeBuff _1(buff);

	if (tmp == NULL)
	{
		m_NSPaths = new CStringW[1];
		m_NSPaths[0] = buff;
		m_NSPaths[0].TrimLeft();

		if (m_NSPaths[0].IsEmpty())
		{
			delete [] m_NSPaths;
			m_NSPaths = NULL;
		}
		else
		{
			m_Count = 1;
			m_Valid = TRUE;
			m_NSPaths[0].TrimRight();
		}
	}
	else
	{
		wchar_t** tmpbuff = (wchar_t**)malloc(MAX_QUERIES*sizeof(wchar_t*));

		if (tmpbuff == NULL)
		{
			throw Heap_Exception(Heap_Exception::HEAP_ERROR::E_ALLOCATION_ERROR);
		}

		CFreeBuff _2(tmpbuff);

		if (tmp != buff)
		{
			tmpbuff[0] = buff;
			m_Count++;
		}

		while (TRUE)
		{
			*tmp = L'\0';
			tmp = tmp + 2;
			
			if (*tmp != L'\0')
			{
				tmpbuff[m_Count] = tmp;
				tmp = wcsstr(tmpbuff[m_Count], NS_DELIMIT);
				m_Count++;

				if (tmp == NULL)
				{
					break;
				}
				
				if ( (m_Count > 0) && (0 == (m_Count%MAX_QUERIES)) )
				{
					UINT x = _msize(tmpbuff);
					tmpbuff = (wchar_t**)realloc(tmpbuff, x+(MAX_QUERIES*sizeof(wchar_t*)));
					_2.SetBuff(tmpbuff);

					if (tmpbuff == NULL)
					{
						throw Heap_Exception(Heap_Exception::HEAP_ERROR::E_ALLOCATION_ERROR);
					}
				}
			}
			else
			{
				break;
			}
		}

		if (m_Count > 0)
		{
			m_NSPaths = new CStringW[m_Count];

			for (UINT x=0; x < m_Count; x++)
			{
				m_NSPaths[x] = tmpbuff[x];
				m_NSPaths[x].TrimLeft();

				if (m_NSPaths[x].IsEmpty())
				{
					break;
				}
				else
				{
					m_NSPaths[x].TrimRight();
				}
			}

			if (!m_NSPaths[m_Count-1].IsEmpty())
			{
				m_Valid = TRUE;
			}
		}
	}
}

CJoinOnQualifierArray::CJoinOnQualifierArray()
{
	m_Count = 0;
	m_AClasses = NULL;
	m_AProps = NULL;
	m_BClasses = NULL;
	m_BProps = NULL;
	m_Ops = NULL;
	m_Buff = NULL;
	m_Valid = FALSE;
	m_bDone = NULL;
}

CJoinOnQualifierArray::~CJoinOnQualifierArray()
{
	if (NULL != m_AClasses)
	{
		free(m_AClasses);
	}

	if (NULL != m_BClasses)
	{
		free(m_BClasses);
	}

	if (NULL != m_AProps)
	{
		free(m_AProps);
	}

	if (NULL != m_BProps)
	{
		free(m_BProps);
	}

	if (NULL != m_Ops)
	{
		free(m_Ops);
	}

	if (NULL != m_Buff)
	{
		free(m_Buff);
	}

	if (NULL != m_bDone)
	{
		delete [] m_bDone;
	}

	m_AllClasses.RemoveAll();
}

BOOL CJoinOnQualifierArray::Set(const wchar_t* jStr)
{
	if (NULL != jStr)
	{
		Parse(jStr);
	}

	return m_Valid;
}

void CJoinOnQualifierArray::Parse(const wchar_t* qualStr)
{
	m_Buff = _wcsdup(qualStr);
	wchar_t* tmp = m_Buff;
	m_Valid = TRUE;
			    
	m_AClasses = (wchar_t**)malloc(MAX_QUERIES*sizeof(wchar_t*));

	if (m_AClasses == NULL)
	{
		throw Heap_Exception(Heap_Exception::HEAP_ERROR::E_ALLOCATION_ERROR);
	}

	m_BClasses = (wchar_t**)malloc(MAX_QUERIES*sizeof(wchar_t*));

	if (m_BClasses == NULL)
	{
		throw Heap_Exception(Heap_Exception::HEAP_ERROR::E_ALLOCATION_ERROR);
	}

	m_AProps = (wchar_t**)malloc(MAX_QUERIES*sizeof(wchar_t*));

	if (m_AProps == NULL)
	{
		throw Heap_Exception(Heap_Exception::HEAP_ERROR::E_ALLOCATION_ERROR);
	}

	m_BProps = (wchar_t**)malloc(MAX_QUERIES*sizeof(wchar_t*));

	if (m_BProps == NULL)
	{
		throw Heap_Exception(Heap_Exception::HEAP_ERROR::E_ALLOCATION_ERROR);
	}

	m_Ops = (UINT*)malloc(MAX_QUERIES*sizeof(UINT));

	if (m_Ops == NULL)
	{
		throw Heap_Exception(Heap_Exception::HEAP_ERROR::E_ALLOCATION_ERROR);
	}

	while ((tmp != NULL) && (L'\0' != *tmp) && (m_Valid))
	{
		m_AClasses[m_Count] = GetClassStr(tmp);

		if ((NULL != m_AClasses[m_Count]) && (L'\0' != *(m_AClasses[m_Count])))
		{
			m_AllClasses.SetAt(m_AClasses[m_Count], 0);
			m_AProps[m_Count] = GetPropertyStrAndOperator(tmp, m_Ops[m_Count]);

			if ((NULL != m_AProps[m_Count]) && (L'\0' != *(m_AProps[m_Count])) && (0 != m_Ops[m_Count]))
			{
				m_BClasses[m_Count] = GetClassStr(tmp);

				if ((NULL != m_BClasses[m_Count]) && (L'\0' != *(m_BClasses[m_Count])))
				{
					m_AllClasses.SetAt(m_BClasses[m_Count], 0);
					m_BProps[m_Count] = GetPropertyStr(tmp);

					if ((NULL != m_BProps[m_Count]) && (L'\0' != *(m_BProps[m_Count])) && StripAnd(tmp))
					{
						m_Count++;

						if ((tmp != NULL) && (L'\0' != *tmp) && (m_Count > 0) && (0 == (m_Count%MAX_QUERIES)) )
						{
							UINT x = _msize(m_AClasses);
							m_AClasses = (wchar_t**)realloc(m_AClasses, x+(MAX_QUERIES*sizeof(wchar_t*)));

							if (m_AClasses == NULL)
							{
								throw Heap_Exception(Heap_Exception::HEAP_ERROR::E_ALLOCATION_ERROR);
							}

							m_BClasses = (wchar_t**)realloc(m_BClasses, x+(MAX_QUERIES*sizeof(wchar_t*)));

							if (m_BClasses == NULL)
							{
								throw Heap_Exception(Heap_Exception::HEAP_ERROR::E_ALLOCATION_ERROR);
							}

							m_AProps = (wchar_t**)realloc(m_AProps, x+(MAX_QUERIES*sizeof(wchar_t*)));

							if (m_AProps == NULL)
							{
								throw Heap_Exception(Heap_Exception::HEAP_ERROR::E_ALLOCATION_ERROR);
							}

							m_BProps = (wchar_t**)realloc(m_BProps, x+(MAX_QUERIES*sizeof(wchar_t*)));

							if (m_BProps == NULL)
							{
								throw Heap_Exception(Heap_Exception::HEAP_ERROR::E_ALLOCATION_ERROR);
							}

							x = _msize(m_Ops);
							m_Ops = (UINT*)realloc(m_Ops, x+(MAX_QUERIES*sizeof(UINT)));

							if (m_Ops == NULL)
							{
								throw Heap_Exception(Heap_Exception::HEAP_ERROR::E_ALLOCATION_ERROR);
							}
						}
					}
					else
					{
						m_Valid = FALSE;
					}
				}
				else
				{
					m_Valid = FALSE;
				}
			}
			else
			{
				m_Valid = FALSE;
			}
		}
		else
		{
			m_Valid = FALSE;
		}
	}

	if (0 == m_Count)
	{
		m_Valid = FALSE;
	}

	if (!m_Valid)
	{
		if (NULL != m_AClasses)
		{
			free(m_AClasses);
			m_AClasses = NULL;
		}

		if (NULL != m_BClasses)
		{
			free(m_BClasses);
			m_BClasses = NULL;
		}

		if (NULL != m_AProps)
		{
			free(m_AProps);
			m_AProps = NULL;
		}

		if (NULL != m_BProps)
		{
			free(m_BProps);
			m_BProps = NULL;
		}

		if (NULL != m_Ops)
		{
			free(m_Ops);
			m_Ops = NULL;
		}

		if (NULL != m_Buff)
		{
			free(m_Buff);
			m_Buff = NULL;
		}
	}
	else
	{
		m_bDone = new BOOL[m_Count];
		memset((void *)m_bDone, 0, sizeof(BOOL)*m_Count);
	}
}

wchar_t* CJoinOnQualifierArray::SkipSpace(wchar_t*& src)
{
	while (iswspace(*src))
	{
		if (*src != L'\0')
		{
			*src = L'\0';
			src++;
		}
	}

	return ((*src == L'\0') ? NULL : src);
}

wchar_t* CJoinOnQualifierArray::SkipToSpecial(wchar_t*& src)
{
	while ((*src != L'.') && (*src != L'=') && (*src != L'!') && (*src != L'<')
		&& !iswspace(*src) && (*src != L'\0'))
	{
		src++;
	}

	return ((*src == L'\0') ? NULL : src);
}

wchar_t* CJoinOnQualifierArray::GetClassStr(wchar_t*& src)
{
	wchar_t* ret = SkipSpace(src);

	if (NULL != ret)
	{
		src = SkipToSpecial(src);

		if ((NULL != src) && (src != ret) && ((*src == L'.')))
		{
			*src = L'\0';
			src++;
		}
		else
		{
			ret = NULL;
		}
	}

	return ret;
}

wchar_t* CJoinOnQualifierArray::GetPropertyStrAndOperator(wchar_t*& src, UINT& op)
{
	wchar_t* ret = src;
	op =  NO_OPERATOR;

	src = SkipToSpecial(src);
	src = SkipSpace(src);

	if ((NULL != src) && (src != ret))
	{
		if (*src == L'=')
		{
			*src = L'\0';
			op = EQUALS_OPERATOR;
			src++;
		}
		else if (*src == L'!')
		{
			wchar_t* prev = src;
			src++;

			if (*src == L'=')
			{
				*prev = L'\0';
				op = NOT_EQUALS_OPERATOR;
				src++;
			}
			else
			{
				ret = NULL;
			}
		}
		else if (*src == L'<')
		{
			wchar_t* prev = src;
			src++;

			if (*src == L'>')
			{
				*prev = L'\0';
				op = NOT_EQUALS_OPERATOR;
				src++;
			}
			else
			{
				ret = NULL;
			}
		}
	}
	else
	{
		ret = NULL;
	}

	return ret;
}

wchar_t* CJoinOnQualifierArray::GetPropertyStr(wchar_t*& src)
{
	wchar_t* ret = src;
	src = SkipToSpecial(src);

	if (NULL != src)
	{
		if ( (src != ret) && iswspace(*src) )
		{
			if (*src != L'\0')
			{
				*src = L'\0';
				src++;
			}
		}
		else
		{
			ret = NULL;
		}
	}

	return ret;
}

BOOL CJoinOnQualifierArray::StripAnd(wchar_t*& src)
{

	if (NULL == src)
	{
		return TRUE;
	}

	src = SkipSpace(src);

	if (NULL == src)
	{
		return TRUE;
	}

	if ((*src == L'a') || (*src == L'A'))
	{
		src++;

		if ((*src == L'n') || (*src == L'N'))
		{
			src++;

			if ((*src == L'd') || (*src == L'D'))
			{
				src++;
				wchar_t* tmp = src;
				src = SkipSpace(src);

				if ((NULL != src) && (tmp != src))
				{
					return TRUE;
				}
			}
		}
	}

	return FALSE;
}

BOOL CJoinOnQualifierArray::ValidateJoin()
{
	if (!m_Valid)
	{
		return m_Valid;
	}

	CMap<CStringW, LPCWSTR, UINT, UINT> validatedClasses;
	CArray<CStringW, LPCWSTR> spareClasses;
	UINT x = 0;

	if (_wcsicmp(m_AClasses[x], m_BClasses[x]) == 0)
	{
		m_Valid = FALSE;
	}
	else
	{
		validatedClasses.SetAt(m_AClasses[x], 0);
		validatedClasses.SetAt(m_BClasses[x], 0);
		x++;
	}

	while ((m_Valid) && (x < m_Count))
	{
		if (_wcsicmp(m_AClasses[x], m_BClasses[x]) == 0)
		{
			m_Valid = FALSE;
		}
		else
		{
			UINT val;

			if (validatedClasses.Lookup(m_AClasses[x], val))
			{
				validatedClasses.SetAt(m_BClasses[x], 0);
			}
			else
			{
				if (validatedClasses.Lookup(m_BClasses[x], val))
				{
					validatedClasses.SetAt(m_AClasses[x], 0);
				}
				else
				{
					spareClasses.Add(m_AClasses[x]);
					spareClasses.Add(m_BClasses[x]);
				}
			}
		}

		x++;
	}

	while ( m_Valid && (0 != spareClasses.GetSize()) )
	{
		m_Valid = FALSE;
		
		for (int i = 0; i < spareClasses.GetSize(); i++)
		{
			UINT val;

			if (validatedClasses.Lookup(spareClasses[i], val))
			{
				if (0 == (i%2))
				{
					validatedClasses.SetAt(spareClasses[i+1], 0);
					spareClasses.RemoveAt(i, 2);
					i -= 1;
				}
				else
				{
					validatedClasses.SetAt(spareClasses[i-1], 0);
					spareClasses.RemoveAt(i-1, 2);
					i -= 2;
				}

				m_Valid = TRUE;
			}
		}
	}

	spareClasses.RemoveAll();
	validatedClasses.RemoveAll();

	return m_Valid;
}


CPropertyQualifierItem::CPropertyQualifierItem(const wchar_t* prop, BOOL bHD, BOOL bKy, CIMTYPE ct, CStringW rfto, BOOL bDt)
{
	if (NULL != prop)
	{
		m_ViewPropertyName = prop;
	}

	m_bDirect = bDt;
	m_HiddenDefault = bHD;
	m_bKey =  bKy;
	m_CimType =  ct;
	m_RefTo = rfto;
}

CPropertyQualifierItem::~CPropertyQualifierItem()
{
	m_SrcPropertyNames.RemoveAll();
}