//***************************************************************************
//
//  (c) 1999 by Microsoft Corporation
//
//  XML2WMI.CPP
//
//  alanbos  09-Jul-99   Created.
//
//  The XML -> WMI translator
//
//***************************************************************************
#include <windows.h>
#include <stdio.h>
#include <objbase.h>
#include <wbemidl.h>

#include <genlex.h>
#include <opathlex.h>
#include <objpath.h>
#include <cominit.h>

#include <httpext.h>
#include <msxml.h>

#include "provtempl.h"
#include "common.h"
#include "wmixmlop.h"
#include "concache.h"
#include "wmiconv.h"
#include "xml2wmi.h"
#include "wmixmlt.h"
#include "request.h"
#include "strings.h"
#include "xmlhelp.h"
#include "parse.h"
//***************************************************************************
//
//  CXmlToWmi::CXmlToWmi
//
//  DESCRIPTION:
//
//  Constructor
//
//***************************************************************************

CXmlToWmi::CXmlToWmi ()
{
	m_pXml = NULL;
	m_pWmiObject = NULL;
	m_pServices = NULL;
}

HRESULT CXmlToWmi::Initialize (IXMLDOMNode *pXml, IWbemServices *pServices, IWbemClassObject *pWmiObject)
{
	if (m_pXml = pXml)
		m_pXml->AddRef ();
	if (m_pWmiObject = pWmiObject)
		m_pWmiObject->AddRef ();
	if (m_pServices = pServices)
		m_pServices->AddRef ();
	return S_OK;
}

//***************************************************************************
//
//  CXmlToWmi::~CXmlToWmi
//
//  DESCRIPTION:
//
//  Destructor.
//
//***************************************************************************

CXmlToWmi::~CXmlToWmi(void)
{
    if (m_pXml)
		m_pXml->Release ();
	if (m_pWmiObject)
		m_pWmiObject->Release ();
	if(m_pServices)
		m_pServices->Release();
}

HRESULT CXmlToWmi::MapClassName (BSTR *pstrClassName)
{
	HRESULT hr = WBEM_E_FAILED;
	*pstrClassName = NULL;

	if(SUCCEEDED(hr = GetBstrAttribute(m_pXml, NAME_ATTRIBUTE, pstrClassName)))
	{
		VARIANT value;
		VariantInit (&value);
		value.vt = VT_BSTR;
		value.bstrVal = *pstrClassName;
		hr = m_pWmiObject->Put (L"__CLASS", 0, &value, VT_BSTR);
		value.bstrVal = NULL;
		VariantClear (&value);
	}

	return hr;
}


//***************************************************************************
//
//  HRESULT CXmlToWmi::MapClass
//
//  DESCRIPTION:
//
//  Maps an XML <CLASS> into its WMI IWbemClassObject equivalent form
//
//  PARAMETERS:
//
//
//  RETURN VALUES:
//
//
//***************************************************************************

HRESULT CXmlToWmi::MapClass (
	bool bIsModify
)
{
	HRESULT hr = S_OK;

	if(m_pXml && m_pWmiObject)
	{
		IWbemQualifierSet *pQualSet = NULL;

		if (SUCCEEDED(m_pWmiObject->GetQualifierSet (&pQualSet)))
		{
			BSTR strClassName = NULL;
			if (SUCCEEDED(hr = MapClassName (&strClassName)))
			{
				VARIANT_BOOL bHasChildNodes;

				if (SUCCEEDED(m_pXml->hasChildNodes (&bHasChildNodes)) &&
					(VARIANT_TRUE == bHasChildNodes))
				{
					IXMLDOMNodeList *pNodeList = NULL;
					if (SUCCEEDED(m_pXml->get_childNodes (&pNodeList)))
					{
						IXMLDOMNode *pNode = NULL;
						while (SUCCEEDED(hr) && SUCCEEDED(pNodeList->nextNode (&pNode)) &&pNode)
						{
							// Get the Name of the property/method/qualifier
							// We dont need to map system properties that begin with "__"
							bool bMapElement = false;
							BSTR strName = NULL;
							if(SUCCEEDED(hr = GetBstrAttribute(pNode, NAME_ATTRIBUTE, &strName)))
							{
								// See if it is one of the System Properties
								if(_wcsnicmp(strName, L"__", 2) != 0)
									bMapElement = true;
								SysFreeString(strName);
							}

							// This element should be mapped only if it was defined/modified
							// in the current class. Hence get its class origin information
							// If there's no class origin information, assume that it is defined in
							// the current class
							BSTR strClassOrigin = NULL;
							if(bMapElement && SUCCEEDED(hr = GetBstrAttribute(pNode, CLASS_ORIGIN_ATTRIBUTE, &strClassOrigin)) && strClassOrigin)
							{
								if(_wcsicmp(strClassOrigin, strClassName) != 0)
									bMapElement = false;
								SysFreeString(strClassOrigin);
							}

							if(bMapElement)
							{
								BSTR strNodeName = NULL;
								if (SUCCEEDED(pNode->get_nodeName (&strNodeName)))
								{
									if (0 == _wcsicmp(strNodeName, QUALIFIER_TAG))
										hr = MapQualifier (pNode, pQualSet);
									else if (0 == _wcsicmp(strNodeName, PROPERTY_TAG))
										hr = MapProperty (pNode, false, bIsModify);
									else if (0 == _wcsicmp(strNodeName, PROPERTYARRAY_TAG))
										hr = MapProperty (pNode, true, bIsModify);
									else if (0 == _wcsicmp(strNodeName, PROPERTYREFERENCE_TAG))
										hr = MapPropertyReference (pNode, false, bIsModify);
									else if (0 == _wcsicmp(strNodeName, PROPERTYREFARRAY_TAG))
										hr = MapPropertyReference (pNode, true, bIsModify);
									else if (0 == _wcsicmp(strNodeName, PROPERTYOBJECT_TAG))
										hr = MapPropertyObject (pNode, false, bIsModify);
									else if (0 == _wcsicmp(strNodeName, PROPERTYOBJECTARRAY_TAG))
										hr = MapPropertyObject (pNode, true, bIsModify);
									else if (0 == _wcsicmp(strNodeName, METHOD_TAG))
										hr = MapMethod (pNode, bIsModify);
									else
										hr = WBEM_E_FAILED;	// Parse error
									SysFreeString (strNodeName);
								}
							}

							pNode->Release ();
						}

						pNodeList->Release ();
					}
				}
			}
			SysFreeString(strClassName);

			pQualSet->Release ();
		}
	}

	return hr;
}

//***************************************************************************
//
//  HRESULT CXmlToWmi::MapInstance
//
//  DESCRIPTION:
//
//  Maps an XML <CLASS> into its WMI IWbemClassObject equivalent form
//
//  PARAMETERS:
//
//
//  RETURN VALUES:
//
//
//***************************************************************************

HRESULT CXmlToWmi::MapInstance (
	bool bIsModify
)
{
	HRESULT hr = WBEM_E_FAILED;

	if(m_pXml && m_pWmiObject)
	{
		IWbemQualifierSet *pQualSet = NULL;

		if (SUCCEEDED(m_pWmiObject->GetQualifierSet (&pQualSet)))
		{
			VARIANT_BOOL bHasChildNodes;

			if (SUCCEEDED(m_pXml->hasChildNodes (&bHasChildNodes)) &&
				(VARIANT_TRUE == bHasChildNodes))
			{
				IXMLDOMNodeList *pNodeList = NULL;

				if (SUCCEEDED(m_pXml->get_childNodes (&pNodeList)))
				{
					IXMLDOMNode *pNode = NULL;
					hr = WBEM_S_NO_ERROR;

					while (SUCCEEDED(hr) && SUCCEEDED(pNodeList->nextNode (&pNode)) &&pNode)
					{
						// Get the name of the element (QUALIFIER, PROPERTY, METHOD)
						BSTR strNodeName = NULL;
						if (SUCCEEDED(pNode->get_nodeName (&strNodeName)))
						{
							// Get the Name of the property/method/qualifier
							// We dont need to map system properties that begin with "__"
							bool bMap = false;
							BSTR strName = NULL;
							if(SUCCEEDED(hr = GetBstrAttribute(pNode, NAME_ATTRIBUTE, &strName)))
							{
								// See if it is one of the System Properties
								if(_wcsnicmp(strName, L"__", 2) != 0)
									bMap = true;
								SysFreeString(strName);
							}

							if(bMap)
							{
								if (0 == _wcsicmp(strNodeName, QUALIFIER_TAG))
									hr = MapQualifier (pNode, pQualSet, true);
								if (0 == _wcsicmp(strNodeName, PROPERTY_TAG))
									hr = MapProperty (pNode, false, bIsModify, true);
								else if (0 == _wcsicmp(strNodeName, PROPERTYARRAY_TAG))
									hr = MapProperty (pNode, true, bIsModify, true);
								else if (0 == _wcsicmp(strNodeName, PROPERTYREFERENCE_TAG))
									hr = MapPropertyReference (pNode, false, bIsModify, true);
								else if (0 == _wcsicmp(strNodeName, PROPERTYREFARRAY_TAG))
									hr = MapPropertyReference (pNode, true, bIsModify, true);
								else if (0 == _wcsicmp(strNodeName, PROPERTYOBJECT_TAG))
									hr = MapPropertyObject (pNode, false, bIsModify, true);
								else if (0 == _wcsicmp(strNodeName, PROPERTYOBJECTARRAY_TAG))
									hr = MapPropertyObject (pNode, true, bIsModify, true);
								else
									hr = WBEM_E_FAILED;	// Parse error
							}

							SysFreeString (strNodeName);
						}

						pNode->Release ();
					}

					pNodeList->Release ();
				}
			}

			pQualSet->Release ();
		}
	}

	return hr;
}

//***************************************************************************
//
//  HRESULT CXmlToWmi::MapContextObject
//
//  DESCRIPTION:
//
//  Maps an XML <INSTANCE> into a IWbemContext object
//
//  PARAMETERS:
//
//
//  RETURN VALUES:
//
//
//***************************************************************************

HRESULT CXmlToWmi::MapContextObject (IXMLDOMNode *pContextNode, IWbemContext **ppContext)
{
	HRESULT hr = WBEM_E_FAILED;
	*ppContext = NULL;

	// Create an IWbemContext object using the information in the INSTANCE element
	if(SUCCEEDED(hr = CoCreateInstance(CLSID_WbemContext,
		0,
		CLSCTX_INPROC_SERVER,
		IID_IWbemContext, (LPVOID *) ppContext)))
	{
		if(pContextNode)
		{
			// Go through the children of the INSTANCE node
			//**************************************************
			VARIANT_BOOL bHasChildNodes;
			if (SUCCEEDED(pContextNode->hasChildNodes (&bHasChildNodes)) &&
				(VARIANT_TRUE == bHasChildNodes))
			{
				IXMLDOMNodeList *pNodeList = NULL;
				if (SUCCEEDED(pContextNode->get_childNodes (&pNodeList)))
				{
					IXMLDOMNode *pNode = NULL;
					hr = WBEM_S_NO_ERROR;

					while (SUCCEEDED(hr) && SUCCEEDED(pNodeList->nextNode (&pNode)) &&pNode)
					{
						BSTR strNodeName = NULL;

						if (SUCCEEDED(pNode->get_nodeName (&strNodeName)))
						{

							if (0 == _wcsicmp(strNodeName, CONTEXTPROPERTY_TAG))
								hr = MapContextProperty (pNode, *ppContext);
							else if (0 == _wcsicmp(strNodeName, CONTEXTPROPERTYARRAY_TAG))
								hr = MapContextPropertyArray (pNode, *ppContext);
							/* RAJESHR These need to be mapped too !!
							else if (0 == _wcsicmp(strNodeName, CONTEXTPROPERTYOBJECT_TAG))
								hr = MapContextPropertyObject (pNode, *ppContext);
							else if (0 == _wcsicmp(strNodeName, CONTEXTPROPERTYOBJECTARRAY_TAG))
								hr = MapContextPropertyObjectArray (pNode, *ppContext);
							*/
							else
								hr = WBEM_E_FAILED;	// Parse error

							SysFreeString (strNodeName);
						}

						pNode->Release ();
					}
					pNodeList->Release ();
				}
			}
		}
	}

	// Release the context object if the whole function call wasnt successful
	if(!SUCCEEDED(hr) && *ppContext)
	{
		(*ppContext)->Release();
		*ppContext = NULL;
	}

	return hr;
}


HRESULT CXmlToWmi::MapQualifier (
	IXMLDOMNode *pNode,
	IWbemQualifierSet *pQualSet,
	bool bInstance
)
{
	HRESULT hr = S_OK;

	BSTR strName = NULL;
	BSTR strType = NULL;
	BSTR strOverridable = NULL;
	BSTR strToSubclass = NULL;
	BSTR strToInstance = NULL;
	BSTR strAmended = NULL;

	// Get the attributes we need for the mapping
	if(SUCCEEDED(hr))
	{
		if(SUCCEEDED(hr = GetBstrAttribute (pNode, NAME_ATTRIBUTE, &strName)))
		{
			if(strName && bInstance)
			{
				// Dont map certain qualifiers for instances
				if(_wcsicmp(strName, L"CIMTYPE") == 0 ||
					_wcsicmp(strName, L"KEY") == 0 )
				{
					SysFreeString(strName);
					return S_OK;
				}
			}
		}
	}
	if(SUCCEEDED(hr))
		hr = GetBstrAttribute (pNode, TYPE_ATTRIBUTE, &strType);
	if(SUCCEEDED(hr))
		GetBstrAttribute (pNode, OVERRIDABLE_ATTRIBUTE, &strOverridable);
	if(SUCCEEDED(hr))
		GetBstrAttribute (pNode, TOSUBCLASS_ATTRIBUTE, &strToSubclass);
	if(SUCCEEDED(hr))
		GetBstrAttribute (pNode, TOINSTANCE_ATTRIBUTE, &strToInstance);
	if(SUCCEEDED(hr))
		GetBstrAttribute (pNode, AMENDED_ATTRIBUTE, &strAmended);

	// Build up the flavor
	long flavor = 0;

	if(SUCCEEDED(hr))
	{
		if (!strOverridable || (0 == _wcsicmp (strOverridable, L"true")))
			flavor |= WBEM_FLAVOR_OVERRIDABLE;
		else if (0 == _wcsicmp (strOverridable, L"false"))
			flavor |= WBEM_FLAVOR_NOT_OVERRIDABLE;
		else
			hr = WBEM_E_FAILED;
	}

	if (SUCCEEDED(hr))
	{
		if (!strToSubclass || (0 == _wcsicmp (strToSubclass, L"true")))
			flavor |= WBEM_FLAVOR_FLAG_PROPAGATE_TO_DERIVED_CLASS;
		else if (0 != _wcsicmp (strToSubclass, L"false"))
			hr = WBEM_E_FAILED;
	}

	if (SUCCEEDED(hr))
	{
		if (strToInstance && (0 == _wcsicmp (strToInstance, L"true")))
			flavor |= WBEM_FLAVOR_FLAG_PROPAGATE_TO_INSTANCE;
		else if (strToInstance && (0 != _wcsicmp (strToInstance, L"false")))
			hr = WBEM_E_FAILED;
	}

	if (SUCCEEDED(hr))
	{
		if (strAmended && (0 == _wcsicmp (strAmended, L"true")))
			flavor |= WBEM_FLAVOR_AMENDED;
		else if (strAmended && (0 != _wcsicmp (strAmended, L"false")))
			hr = WBEM_E_FAILED;
	}

	// Map the Qualifier type
	CIMTYPE cimtype = CIM_ILLEGAL;

	if (CIM_ILLEGAL == (cimtype = CimtypeFromString (strType)))
		hr = WBEM_E_FAILED;

	// Map the Qualifier value
	VARIANT value;
	VariantInit (&value);

	if (SUCCEEDED (hr))
	{
		IXMLDOMNodeList *pNodeList = NULL;
		long length = 0;
		if (SUCCEEDED(hr = pNode->get_childNodes (&pNodeList)))
		{
			if (SUCCEEDED(hr = pNodeList->get_length (&length)) && (1 == length))
			{
				// Get the first node
				IXMLDOMNode *pValueNode = NULL;
				if (SUCCEEDED(hr = pNodeList->nextNode (&pValueNode)) && pValueNode)
				{
					// Get its name
					BSTR strNodeName = NULL;
					if(SUCCEEDED(hr = pValueNode->get_nodeName(&strNodeName)))
					{
						if (0 == _wcsicmp(strNodeName, VALUE_TAG))
						{
							BSTR bsValue = NULL;
							if(SUCCEEDED(hr = pValueNode->get_text(&bsValue)))
							{
								hr = MapStringValue (bsValue, value, cimtype);
								SysFreeString (bsValue);
							}
						}
						else if (0 == _wcsicmp(strNodeName, VALUEARRAY_TAG))
						{
							hr = MapStringArrayValue (pValueNode, value, cimtype);
						}

						SysFreeString (strNodeName);
					}
					pValueNode->Release ();
				}
			}

			pNodeList->Release ();
		}
	}

	// Put it all together
	if (SUCCEEDED (hr))
		hr = pQualSet->Put (strName, &value, flavor);

	if (strName)
		SysFreeString (strName);

	if (strType)
		SysFreeString (strType);

	if (strOverridable)
		SysFreeString (strOverridable);

	if (strToSubclass)
		SysFreeString (strToSubclass);

	if (strToInstance)
		SysFreeString (strToInstance);

	if (strAmended)
		SysFreeString (strAmended);

	VariantClear (&value);

	return hr;
}

HRESULT CXmlToWmi::MapProperty (
	IXMLDOMNode *pProperty,
	bool bIsArray,
	bool bIsModify, 
	bool bIsInstance
)
{
	HRESULT hr = S_OK;

	BSTR strName = NULL;
	BSTR strType = NULL;
	BSTR strArraySize = NULL;

	// Get the attributes we need for the mapping
	if(SUCCEEDED(hr))
		hr = GetBstrAttribute (pProperty, NAME_ATTRIBUTE, &strName);
	if(SUCCEEDED(hr))
		hr = GetBstrAttribute (pProperty, TYPE_ATTRIBUTE, &strType);

	// This is an optional attribute - hence we dont need to check for success
	if (SUCCEEDED(hr) && (bIsArray))
		GetBstrAttribute (pProperty, ARRAYSIZE_ATTRIBUTE, &strArraySize);

	if (SUCCEEDED(hr) && pProperty && strName && strType)
	{
		// Map the Property type
		CIMTYPE cimtype = CIM_ILLEGAL;

		if (CIM_ILLEGAL == (cimtype = CimtypeFromString (strType)))
			hr = WBEM_E_FAILED;
		else if (bIsArray)
			cimtype |= CIM_FLAG_ARRAY;

		// Does this property exist already? If we're doing a modify it had better!
		hr = m_pWmiObject->Get(strName, 0, NULL, NULL, NULL);

		if (!bIsModify || SUCCEEDED(hr))
		{
			// If we didn't find the property, put a provisional version
			// in so we can get the qualifier set
			if (SUCCEEDED(hr) || SUCCEEDED(hr = m_pWmiObject->Put(strName, 0, NULL, cimtype)))
			{
				IWbemQualifierSet *pQualSet = NULL;
				VARIANT value;
				VariantInit (&value);

				if (SUCCEEDED(hr = m_pWmiObject->GetPropertyQualifierSet (strName, &pQualSet)))
				{
					// If we have been given an ARRAYSIZE value then set this
					// as qualifiers of the property
					if (strArraySize)
						hr = SetArraySize (pQualSet, strArraySize);

					if (SUCCEEDED(hr))
					{
						// The content of this element should be 0 or
						// more QUALIFIER elements followed by an optional VALUE
						// element.
						VARIANT_BOOL bHasChildNodes;

						if (SUCCEEDED(pProperty->hasChildNodes (&bHasChildNodes)) &&
							(VARIANT_TRUE == bHasChildNodes))
						{
							IXMLDOMNodeList *pNodeList = NULL;
							// We can be in one of 3 states whilst iterating
							// this list - parsing qualifiers or parsing the value
							// or value array
							enum {
								parsingQualifiers,
								parsingValue,
								parsingValueArray,
							} parseState = parsingQualifiers;

							if (SUCCEEDED(pProperty->get_childNodes (&pNodeList)))
							{
								IXMLDOMNode *pNode = NULL;
								while (SUCCEEDED(hr) && SUCCEEDED(pNodeList->nextNode (&pNode)) &&pNode)
								{
									BSTR strNodeName = NULL;
									if (SUCCEEDED(pNode->get_nodeName (&strNodeName)))
									{
										if (parsingQualifiers == parseState)
										{
											if (0 == _wcsicmp(strNodeName, QUALIFIER_TAG))
												hr = MapQualifier (pNode, pQualSet, bIsInstance);
											else
												parseState = (bIsArray) ?
													parsingValueArray : parsingValue;
										}

										if (parsingValue == parseState)
										{
											if (0 == _wcsicmp(strNodeName, VALUE_TAG))
											{
												BSTR bsValue = NULL;
												if(SUCCEEDED(hr = pNode->get_text(&bsValue)))
												{
													hr = MapStringValue (bsValue, value, cimtype);
													SysFreeString (bsValue);
												}
											}
											else
												hr = WBEM_E_FAILED;	// Parse error
										}

										if (parsingValueArray == parseState)
										{
											if (0 == _wcsicmp(strNodeName, VALUEARRAY_TAG))
											{
												hr = MapStringArrayValue
														(pNode, value, cimtype);
											}
											else
												hr = WBEM_E_FAILED;
										}

										SysFreeString (strNodeName);
									}

									pNode->Release ();
								}

								pNodeList->Release ();
							}
						}
					}

					pQualSet->Release ();
				}

				// Put it all together - only do this if we have a real value
				if (SUCCEEDED (hr) && (VT_EMPTY != value.vt))
					hr = m_pWmiObject->Put (strName, 0, &value, cimtype);

				VariantClear (&value);
			}
		}
	}

	if (strName)
		SysFreeString (strName);

	if (strType)
		SysFreeString (strType);

	if (strArraySize)
		SysFreeString (strArraySize);

	return hr;
}

HRESULT CXmlToWmi::MapPropertyReference (
	IXMLDOMNode *pProperty,
	bool bIsArray,
	bool bIsModify,
	bool bIsInstance
)
{
	HRESULT hr = S_OK;

	if (pProperty)
	{
		BSTR strName = NULL;
		BSTR strReferenceClass = NULL;
		BSTR strArraySize = NULL;
		CIMTYPE cimtype = CIM_REFERENCE;
		if(bIsArray)
			cimtype |= CIM_FLAG_ARRAY;

		// Get the attributes we need for the mapping
		if(SUCCEEDED(hr))
			hr = GetBstrAttribute (pProperty, NAME_ATTRIBUTE, &strName);
		if(SUCCEEDED(hr))
			hr = GetBstrAttribute (pProperty, REFERENCECLASS_ATTRIBUTE, &strReferenceClass);

		// This is an optional attribute - hence we dont need to check for success
		if (SUCCEEDED(hr) && (bIsArray))
			GetBstrAttribute (pProperty, ARRAYSIZE_ATTRIBUTE, &strArraySize);

		if (pProperty && strName)
		{
			// Does this property exist already? If we're doing a modify it had better!
			hr = m_pWmiObject->Get(strName, 0, NULL, NULL, NULL);

			if (!bIsModify || SUCCEEDED(hr))
			{
				// If we didn't find the property, put a provisional version
				// in so we can get the qualifier set
				if (SUCCEEDED(hr) || SUCCEEDED(hr = m_pWmiObject->Put(strName, 0, NULL, cimtype)))
				{
					IWbemQualifierSet *pQualSet = NULL;
					VARIANT value;
					VariantInit (&value);

					if (SUCCEEDED(hr = m_pWmiObject->GetPropertyQualifierSet (strName, &pQualSet)))
					{
						// If we have been given an ARRAYSIZE value then set this
						// as qualifiers of the property
						if (strArraySize)
							hr = SetArraySize (pQualSet, strArraySize);

						// If we have been given a REFERENCECLASS value then set this
						// as qualifiers of the property
						if (strReferenceClass)
							hr = SetReferenceClass (pQualSet, strReferenceClass);

						if (SUCCEEDED(hr))
						{
							// The content of this element should be 0 or
							// more QUALIFIER elements followed by an optional
							// VALUE.REFERENCE element.
							VARIANT_BOOL bHasChildNodes;

							if (SUCCEEDED(pProperty->hasChildNodes (&bHasChildNodes)) &&
								(VARIANT_TRUE == bHasChildNodes))
							{
								IXMLDOMNodeList *pNodeList = NULL;
								// We can be in one of 3 states whilst iterating
								// this list - parsing qualifiers or parsing the value
								enum {
									parsingQualifiers,
									parsingValue,
									parsingValueArray,

								} parseState = parsingQualifiers;

								if (SUCCEEDED(pProperty->get_childNodes (&pNodeList)))
								{
									IXMLDOMNode *pNode = NULL;

									while (SUCCEEDED(hr) && SUCCEEDED(pNodeList->nextNode (&pNode)) &&pNode)
									{
										BSTR strNodeName = NULL;

										if (SUCCEEDED(pNode->get_nodeName (&strNodeName)))
										{
											if (parsingQualifiers == parseState)
											{
												if (0 == _wcsicmp(strNodeName, QUALIFIER_TAG))
													hr = MapQualifier (pNode, pQualSet, bIsInstance);
												else
													parseState = (bIsArray)? parsingValueArray : parsingValue;
											}

											if (parsingValue == parseState)
											{
												if (0 == _wcsicmp(strNodeName, VALUEREFERENCE_TAG))
												{
													hr = MapReferenceValue (pNode, value);
												}
												else
													hr = WBEM_E_FAILED;	// Parse error
											}

											if (parsingValueArray == parseState)
											{
												if (0 == _wcsicmp(strNodeName, VALUEREFARRAY_TAG))
												{
													hr = MapReferenceArrayValue (pNode, value);
												}
												else
													hr = WBEM_E_FAILED;	// Parse error
											}

											SysFreeString (strNodeName);
										}

										pNode->Release ();
									}

									pNodeList->Release ();
								}
							}
						}

						pQualSet->Release ();
					}

					// Put it all together - only do this if we have a real value
					if (SUCCEEDED (hr) && (VT_EMPTY != value.vt))
						hr = m_pWmiObject->Put (strName, 0, &value, cimtype);

					VariantClear (&value);
				}
			}
		}

		SysFreeString (strName);
		SysFreeString (strReferenceClass);
		SysFreeString (strArraySize);
	}

	return hr;
}

HRESULT CXmlToWmi::MapPropertyObject (
	IXMLDOMNode *pProperty,
	bool bIsArray,
	bool bIsModify,
	bool bIsInstance
)
{
	HRESULT hr = S_OK;

	if (pProperty)
	{
		BSTR strName = NULL;
		BSTR strReferenceClass = NULL;
		BSTR strArraySize = NULL;
		CIMTYPE cimtype = CIM_REFERENCE;
		if(bIsArray)
			cimtype |= CIM_FLAG_ARRAY;

		// Get the attributes we need for the mapping
		if(SUCCEEDED(hr))
			hr = GetBstrAttribute (pProperty, NAME_ATTRIBUTE, &strName);
		if(SUCCEEDED(hr))
			hr = GetBstrAttribute (pProperty, REFERENCECLASS_ATTRIBUTE, &strReferenceClass);

		// This is an optional attribute - hence we dont need to check for success
		if (SUCCEEDED(hr) && (bIsArray))
			GetBstrAttribute (pProperty, ARRAYSIZE_ATTRIBUTE, &strArraySize);

		if (pProperty && strName)
		{
			// Does this property exist already? If we're doing a modify it had better!
			hr = m_pWmiObject->Get(strName, 0, NULL, NULL, NULL);

			if (!bIsModify || SUCCEEDED(hr))
			{
				// If we didn't find the property, put a provisional version
				// in so we can get the qualifier set
				if (SUCCEEDED(hr) || SUCCEEDED(hr = m_pWmiObject->Put(strName, 0, NULL, cimtype)))
				{
					IWbemQualifierSet *pQualSet = NULL;
					VARIANT value;
					VariantInit (&value);

					if (SUCCEEDED(hr = m_pWmiObject->GetPropertyQualifierSet (strName, &pQualSet)))
					{
						// If we have been given an ARRAYSIZE value then set this
						// as qualifiers of the property
						if (strArraySize)
							hr = SetArraySize (pQualSet, strArraySize);

						// If we have been given a REFERENCECLASS value then set this
						// as qualifiers of the property
						if (strReferenceClass)
							hr = SetObjectClass (pQualSet, strReferenceClass);

						if (SUCCEEDED(hr))
						{
							// The content of this element should be 0 or
							// more QUALIFIER elements followed by an optional
							// VALUE.OBJECT element.
							VARIANT_BOOL bHasChildNodes;

							if (SUCCEEDED(pProperty->hasChildNodes (&bHasChildNodes)) &&
								(VARIANT_TRUE == bHasChildNodes))
							{
								IXMLDOMNodeList *pNodeList = NULL;
								// We can be in one of 3 states whilst iterating
								// this list - parsing qualifiers or parsing the value
								enum {
									parsingQualifiers,
									parsingValue,
									parsingValueArray,

								} parseState = parsingQualifiers;

								if (SUCCEEDED(pProperty->get_childNodes (&pNodeList)))
								{
									IXMLDOMNode *pNode = NULL;

									while (SUCCEEDED(hr) && SUCCEEDED(pNodeList->nextNode (&pNode)) &&pNode)
									{
										BSTR strNodeName = NULL;

										if (SUCCEEDED(pNode->get_nodeName (&strNodeName)))
										{
											if (parsingQualifiers == parseState)
											{
												if (0 == _wcsicmp(strNodeName, QUALIFIER_TAG))
													hr = MapQualifier (pNode, pQualSet, bIsInstance);
												else
													parseState = (bIsArray)? parsingValueArray : parsingValue;
											}

											if (parsingValue == parseState)
											{
												if (0 == _wcsicmp(strNodeName, VALUEOBJECT_TAG))
												{
													hr = MapObjectValue (pNode, value);
												}
												else
													hr = WBEM_E_FAILED;	// Parse error
											}

											if (parsingValueArray == parseState)
											{
												if (0 == _wcsicmp(strNodeName, VALUEOBJECTARRAY_TAG))
												{
													hr = MapObjectArrayValue (pNode, value);
												}
												else
													hr = WBEM_E_FAILED;	// Parse error
											}

											SysFreeString (strNodeName);
										}

										pNode->Release ();
									}

									pNodeList->Release ();
								}
							}
						}

						pQualSet->Release ();
					}

					// Put it all together - only do this if we have a real value
					if (SUCCEEDED (hr) && (VT_EMPTY != value.vt))
						hr = m_pWmiObject->Put (strName, 0, &value, cimtype);

					VariantClear (&value);
				}
			}
		}

		SysFreeString (strName);
		SysFreeString (strReferenceClass);
		SysFreeString (strArraySize);
	}

	return hr;
}

HRESULT CXmlToWmi::MapMethod (
	IXMLDOMNode *pMethod,
	bool bIsModify
)
{
	HRESULT hr = WBEM_E_FAILED;

	if (pMethod)
	{
		BSTR strName = NULL;
		BSTR strType = NULL;

		// Get the attributes we need for the mapping
		GetBstrAttribute (pMethod, NAME_ATTRIBUTE, &strName);
		GetBstrAttribute (pMethod, TYPE_ATTRIBUTE, &strType);

		if (pMethod && strName)
		{

			// Does this method exist already? If we're doing a modify it had better!
			hr = m_pWmiObject->GetMethod(strName, 0, NULL, NULL);

			if (!bIsModify || SUCCEEDED(hr))
			{
				// If we didn't find the method, put a provisional version
				// in so we can get the qualifier set
				if (SUCCEEDED(hr) ||
					SUCCEEDED(hr = m_pWmiObject->PutMethod(strName, 0, NULL, NULL)))
				{
					IWbemQualifierSet *pQualSet = NULL;
					IWbemClassObject *pInParameters = NULL;
					IWbemClassObject *pOutParameters = NULL;

					if (SUCCEEDED(hr = m_pWmiObject->GetMethodQualifierSet (strName, &pQualSet)))
					{
						// If we have a return value, set that
						if (strType && (0 < wcslen (strType)))
						{
							CIMTYPE cimtype = CIM_ILLEGAL;

							if (CIM_ILLEGAL == (cimtype = CimtypeFromString (strType)))
								hr = WBEM_E_FAILED;
							else if (SUCCEEDED(hr = m_pServices->GetObject
								(L"__PARAMETERS", 0, NULL, &pOutParameters, NULL)))
								hr = pOutParameters->Put (L"ReturnValue", 0, NULL, cimtype);
						}


						// The content of this element should be 0 or
						// more QUALIFIER elements followed by 0 or more
						// PARAMETER.* elements.
						VARIANT_BOOL bHasChildNodes;

						if (SUCCEEDED(pMethod->hasChildNodes (&bHasChildNodes)) &&
							(VARIANT_TRUE == bHasChildNodes))
						{
							IXMLDOMNodeList *pNodeList = NULL;
							// We can be in one of 3 states whilst iterating
							// this list - parsing qualifiers or parsing the value
							enum {
								parsingQualifiers,
								parsingParameters
							} parseState = parsingQualifiers;

							if (SUCCEEDED(pMethod->get_childNodes (&pNodeList)))
							{
								IXMLDOMNode *pNode = NULL;
								ULONG paramId = 0;

								while (SUCCEEDED(hr) && SUCCEEDED(pNodeList->nextNode (&pNode)) &&pNode)
								{
									BSTR strNodeName = NULL;

									if (SUCCEEDED(pNode->get_nodeName (&strNodeName)))
									{
										if (parsingQualifiers == parseState)
										{
											if (0 == _wcsicmp(strNodeName, QUALIFIER_TAG))
												hr = MapQualifier (pNode, pQualSet);
											else
												parseState = parsingParameters;
										}

										if (parsingParameters == parseState)
										{
											if (0 == _wcsicmp(strNodeName, PARAMETER_TAG))
											{
												hr = MapParameter (pNode, &pInParameters,
														&pOutParameters,
														m_pServices, paramId);
												paramId++;
											}
											else if (0 == _wcsicmp(strNodeName,
														PARAMETERREFERENCE_TAG))
											{
												hr = MapReferenceParameter (pNode,
														&pInParameters, &pOutParameters,
														m_pServices, paramId);
												paramId++;
											}
											else if (0 == _wcsicmp(strNodeName,
														PARAMETERARRAY_TAG))
											{
												hr = MapParameter (pNode,
														&pInParameters, &pOutParameters,
														m_pServices, paramId, true);
										 		paramId++;
											}
											else if (0 == _wcsicmp(strNodeName,
														PARAMETERREFARRAY_TAG))
											{
												hr = MapReferenceParameter (pNode,
														&pInParameters, &pOutParameters,
														m_pServices, paramId, true);
												paramId++;
											}
											else
												hr = WBEM_E_FAILED;	// Parse error
										}

										SysFreeString (strNodeName);
									}

									pNode->Release ();
								}

								pNodeList->Release ();
							}
						}

						pQualSet->Release ();
					}

					// Put it all together
					if (SUCCEEDED (hr))
						hr = m_pWmiObject->PutMethod (strName, 0, pInParameters, pOutParameters);

					if (pInParameters)
						pInParameters->Release ();

					if (pOutParameters)
						pOutParameters->Release ();
				}
			}
		}

		if (strName)
			SysFreeString (strName);

		if (strType)
			SysFreeString (strType);
	}

	return hr;
}

HRESULT CXmlToWmi::MapParameter (
	IXMLDOMNode *pParameter,
	IWbemClassObject **ppInParameters,
	IWbemClassObject **ppOutParameters,
	IWbemServices *pService,
	ULONG paramId,
	bool bIsArray
)
{
	HRESULT hr = WBEM_E_FAILED;
	bool bIsInParameter = false;
	bool bIsOutParameter = false;
	BSTR bsName = NULL;
	CIMTYPE cimtype = CIM_ILLEGAL;
	long iArraySize = 0;

	if (DetermineParameterCharacteristics (pParameter, bIsArray, bIsInParameter,
					bIsOutParameter, bsName, cimtype, iArraySize))
	{
		if (bIsInParameter)
		{
			if (!(*ppInParameters))
				pService->GetObject (L"__PARAMETERS", 0, NULL, ppInParameters, NULL);

			if (*ppInParameters)
			{
				if (SUCCEEDED(hr = (*ppInParameters)->Put (bsName, 0, NULL, cimtype)))
				{
					// Now do the qualifiers
					IWbemQualifierSet *pQualSet = NULL;

					if (SUCCEEDED(hr = (*ppInParameters)->GetPropertyQualifierSet
												(bsName, &pQualSet)))
					{
						hr = MapParameterQualifiers (pParameter, pQualSet, paramId,
														bIsArray, iArraySize, true);
						pQualSet->Release ();
					}
				}
			}
		}

		if (bIsOutParameter)
		{
			if (!(*ppOutParameters))
				pService->GetObject (L"__PARAMETERS", 0, NULL, ppOutParameters, NULL);

			if (*ppOutParameters)
			{
				if (SUCCEEDED(hr = (*ppOutParameters)->Put (bsName, 0, NULL, cimtype)))
				{
					// Now do the qualifiers
					IWbemQualifierSet *pQualSet = NULL;

					if (SUCCEEDED(hr = (*ppOutParameters)->GetPropertyQualifierSet
												(bsName, &pQualSet)))
					{
						hr = MapParameterQualifiers (pParameter, pQualSet, paramId,
														bIsArray, iArraySize);
						pQualSet->Release ();
					}
				}
			}
		}

		SysFreeString (bsName);
	}

	return hr;
}

bool CXmlToWmi::DetermineParameterCharacteristics (
	IXMLDOMNode *pParameter,
	bool bIsArray,
	bool &bIsInParameter,
	bool &bIsOutParameter,
	BSTR &bsName,
	CIMTYPE &cimtype,
	long &iArraySize,
	bool bIsReference,
	BSTR *pbsReferenceClass)
{
	bool result = false;
	bIsInParameter = false;
	bIsOutParameter = false;

	// Get name
	GetBstrAttribute (pParameter, NAME_ATTRIBUTE, &bsName);

	if (bsName)
	{
		if (bIsArray)
		{
			// Get the arraysize (if any)
			BSTR bsArraySize = NULL;
			GetBstrAttribute (pParameter, ARRAYSIZE_ATTRIBUTE, &bsArraySize);

			if (bsArraySize)
			{
				iArraySize = wcstol (bsArraySize, NULL, 0);
				SysFreeString (bsArraySize);
			}
		}

		// Now get the cimtype
		if (bIsReference)
		{
			cimtype = CIM_REFERENCE;

			if (pbsReferenceClass)
				GetBstrAttribute (pParameter, REFERENCECLASS_ATTRIBUTE, pbsReferenceClass);
		}
		else
		{
			BSTR bsCimtype = NULL;
			GetBstrAttribute (pParameter, TYPE_ATTRIBUTE, &bsCimtype);
			cimtype = CimtypeFromString (bsCimtype);

			if (bsCimtype)
				SysFreeString (bsCimtype);
		}

		if (CIM_ILLEGAL != cimtype)
		{
			if (bIsArray)
				cimtype |= CIM_FLAG_ARRAY;

			result = true;
			// Now find out if the method is an in or out
			// (or both) parameter - need to go through
			// qualifier list
			IXMLDOMNodeList *pNodeList = NULL;

			if (SUCCEEDED(pParameter->get_childNodes (&pNodeList)))
			{
				IXMLDOMNode *pNode = NULL;
				HRESULT hr = S_OK;

				while (SUCCEEDED(hr) && SUCCEEDED(pNodeList->nextNode (&pNode)) &&pNode)
				{
					BSTR strNodeName = NULL;

					if (SUCCEEDED(pNode->get_nodeName (&strNodeName)))
					{
						if (0 == _wcsicmp(strNodeName, QUALIFIER_TAG))
						{
							BSTR bsName = NULL;
							GetBstrAttribute (pNode, NAME_ATTRIBUTE, &bsName);

							if (bsName)
							{
								bool bCandidate = false;
								bool bsIn = true;

								if (0 == _wcsicmp (bsName, L"IN"))
									bCandidate = true;
								else if (0 == _wcsicmp (bsName, L"OUT"))
								{
									bCandidate = true;
									bsIn = false;
								}

								if (bCandidate)
								{
									BSTR bsType = NULL;
									GetBstrAttribute (pNode, TYPE_ATTRIBUTE, &bsType);

									if (bsType && (0 == _wcsicmp (bsType, L"boolean")))
									{
										BSTR bsValue = NULL;

										if (SUCCEEDED(pNode->get_text(&bsValue)) &&
											bsValue && (0 == _wcsicmp (bsValue, L"TRUE")))
										{
											if (bsIn)
												bIsInParameter = true;
											else
												bIsOutParameter = true;
										}
									}

									SysFreeString (bsType);
								}

								SysFreeString (bsName);
							}
						}

						SysFreeString (strNodeName);
					}

					pNode->Release ();
				}

				pNodeList->Release ();
			}
		}
	}

	if (!result)
	{
		if (bsName)
		{
			SysFreeString (bsName);
			bsName = NULL;
		}
	}

	return result;
}

HRESULT CXmlToWmi::MapParameterQualifiers (
	IXMLDOMNode *pParameter,
	IWbemQualifierSet *pQualSet,
	ULONG paramId,
	bool bIsArray,
	long iArraySize,
	bool bIsInParameter
)
{
	HRESULT hr = S_OK;
	IXMLDOMNodeList *pNodeList = NULL;

	if (SUCCEEDED(pParameter->get_childNodes (&pNodeList)))
	{
		IXMLDOMNode *pNode = NULL;

		while (SUCCEEDED(hr) && SUCCEEDED(pNodeList->nextNode (&pNode)) &&pNode)
		{
			BSTR strNodeName = NULL;

			if (SUCCEEDED(pNode->get_nodeName (&strNodeName)))
			{
				if (0 == _wcsicmp(strNodeName, QUALIFIER_TAG))
				{
					// We must only add the IN qualifier to an In parameter,
					// and the OUT parameter to an Out parameter
					BSTR bsName = NULL;
					GetBstrAttribute (pNode, NAME_ATTRIBUTE, &bsName);

					if (bsName)
					{
						if (0 == _wcsicmp (bsName, L"IN"))
						{
							if (bIsInParameter)
								hr = MapQualifier (pNode, pQualSet);
						}
						else if (0 == _wcsicmp (bsName, L"OUT"))
						{
							if (!bIsInParameter)
								hr = MapQualifier (pNode, pQualSet);
						}
						else
							hr = MapQualifier (pNode, pQualSet);

						SysFreeString (bsName);
					}
				}
				else
					hr = WBEM_E_FAILED;
				SysFreeString (strNodeName);
			}

			pNode->Release ();
		}

		if (SUCCEEDED(hr))
		{
			long flavor = WBEM_FLAVOR_NOT_OVERRIDABLE |
										WBEM_FLAVOR_FLAG_PROPAGATE_TO_DERIVED_CLASS;
			// Add in the parameter id
			VARIANT var;
			VariantInit (&var);
			var.vt = VT_I4;
			var.lVal = paramId;
			hr = pQualSet->Put (L"ID", &var, flavor);
			VariantClear (&var);

			if (SUCCEEDED(hr) && bIsArray && (0 < iArraySize))
			{
				// Add in MIN and MAX qualifiers
				var.vt = VT_I4;
				var.lVal = iArraySize;

				if (SUCCEEDED(hr = pQualSet->Put (L"MAX", &var, flavor)))
					hr = pQualSet->Put (L"MIN", &var, flavor);
			}
		}

		pNodeList->Release ();
	}

	return hr;
}

HRESULT CXmlToWmi::MapReferenceParameter (
	IXMLDOMNode *pParameter,
	IWbemClassObject **ppInParameters,
	IWbemClassObject **ppOutParameters,
	IWbemServices *pService,
	ULONG paramId,
	bool bIsArray
)
{
	HRESULT hr = WBEM_E_FAILED;
	bool bIsInParameter = false;
	bool bIsOutParameter = false;
	BSTR bsName = NULL;
	BSTR bsReferenceClass = NULL;
	long iArraySize = 0;
	CIMTYPE cimtype = CIM_ILLEGAL;

	if (DetermineParameterCharacteristics (pParameter, bIsArray, bIsInParameter,
					bIsOutParameter, bsName, cimtype, iArraySize,
					true, &bsReferenceClass))
	{
		if (bIsInParameter)
		{
			if (!(*ppInParameters))
				pService->GetObject (L"__PARAMETERS", 0, NULL, ppInParameters, NULL);

			if (*ppInParameters)
			{
				if (SUCCEEDED(hr = (*ppInParameters)->Put (bsName, 0, NULL, cimtype)))
				{
					// Now do the qualifiers
					IWbemQualifierSet *pQualSet = NULL;

					if (SUCCEEDED(hr = (*ppInParameters)->GetPropertyQualifierSet
												(bsName, &pQualSet)))
					{
						hr = MapParameterQualifiers (pParameter, pQualSet, paramId,
										bIsArray, iArraySize, true);

						// If a strong reference, add it now
						if (bsReferenceClass)
							SetReferenceClass (pQualSet, bsReferenceClass);

						pQualSet->Release ();
					}
				}
			}
		}

		if (bIsOutParameter)
		{
			if (!(*ppOutParameters))
				pService->GetObject (L"__PARAMETERS", 0, NULL, ppOutParameters, NULL);

			if (*ppOutParameters)
			{
				if (SUCCEEDED(hr = (*ppOutParameters)->Put (bsName, 0, NULL, cimtype)))
				{
					// Now do the qualifiers
					IWbemQualifierSet *pQualSet = NULL;

					if (SUCCEEDED(hr = (*ppOutParameters)->GetPropertyQualifierSet
												(bsName, &pQualSet)))
					{
						hr = MapParameterQualifiers (pParameter, pQualSet, paramId,
														bIsArray, iArraySize);
						// If a strong reference, add it now
						if (bsReferenceClass)
							SetReferenceClass (pQualSet, bsReferenceClass);

						pQualSet->Release ();
					}
				}
			}
		}

		SysFreeString (bsName);
	}

	if (bsReferenceClass)
		SysFreeString (bsReferenceClass);

	return hr;
}

//***************************************************************************
//
//  HRESULT CXmlToWmi::MapPropertyValue
//
//  DESCRIPTION:
//
//  Maps an XML property value into its WMI VARIANT equivalent form
//
//  PARAMETERS:
//
//		curValue		Placeholder for new value (set on return)
//		cimtype			CIMTYPE of property (needed for mapping)
//
//  RETURN VALUES:
//
//
//***************************************************************************

HRESULT CXmlToWmi::MapPropertyValue (
	VARIANT &curValue,
	CIMTYPE cimtype)
{
	HRESULT hr = WBEM_E_FAILED;

	// Parse the XML body to extract the value - we
	// are expecting (VALUE|VALUE.ARRAY|VALUE.REFERENCE)?

	// Get its name
	BSTR strNodeName = NULL;
	if(m_pXml && SUCCEEDED(m_pXml->get_nodeName(&strNodeName)))
	{
		if (_wcsicmp(strNodeName, VALUE_TAG) == 0)
		{
			// RAJESHR - check only one node
			BSTR bsValue = NULL;
			m_pXml->get_text(&bsValue);
			hr = MapStringValue (bsValue, curValue, cimtype);
			SysFreeString (bsValue);
		}
		else if (_wcsicmp(strNodeName, VALUEARRAY_TAG) == 0)
		{
			hr = MapStringArrayValue (m_pXml, curValue, cimtype);
		}
		else if (_wcsicmp(strNodeName, VALUEREFERENCE_TAG) == 0)
		{
			if (CIM_REFERENCE == cimtype)
				hr = MapReferenceValue (m_pXml, curValue);
			else
				hr = WBEM_E_TYPE_MISMATCH;
		}

		SysFreeString (strNodeName);
	}
	else
	{
		// Assume value is NULL
		VariantClear (&curValue);
		curValue.vt = VT_NULL;
		hr = S_OK;
	}

	return hr;
}




//***************************************************************************
//
//  HRESULT CXmlToWmi::MapStringValue
//
//  DESCRIPTION:
//
//  Maps XML VALUE element content into its WMI VARIANT equivalent form
//
//  PARAMETERS:
//
//		bsValue			the VALUE element content
//		curValue		Placeholder for new value (set on return)
//		cimtype			for mapping purposes
//
//  RETURN VALUES:
//
//
//***************************************************************************

HRESULT CXmlToWmi::MapStringValue (BSTR bsValue, VARIANT &curValue, CIMTYPE cimtype)
{
	// RAJESHR First we need to remove any CDATA section from the string value
	// Even though the WMI implementation used CDATA (if necessary) only for CIM_STRING and CIM_DATETIME,
	// other implementations might use a CDATA to escape other values as well

	HRESULT hr = WBEM_E_TYPE_MISMATCH;

	// We're assuming it's not an array
	if (!(cimtype & CIM_FLAG_ARRAY))
	{
		switch (cimtype)
		{
			// RAJESHR - more rigorous syntax checking
			case CIM_UINT8:
			{
				VariantClear (&curValue);
				curValue.vt = VT_UI1;
				curValue.bVal = (BYTE) wcstol (bsValue, NULL, 0);
				hr = S_OK;
			}
				break;

			case CIM_SINT8:
			case CIM_SINT16:
			{
				VariantClear (&curValue);
				curValue.vt = VT_I2;
				curValue.iVal = (short) wcstol (bsValue, NULL, 0);
				hr = S_OK;
			}
				break;

			case CIM_UINT16:
			case CIM_UINT32:
			case CIM_SINT32:
			{
				VariantClear (&curValue);
				curValue.vt = VT_I4;
				curValue.lVal = wcstol (bsValue, NULL, 0);
				hr = S_OK;
			}
				break;

			case CIM_REAL32:
			{
				VariantClear (&curValue);
				curValue.vt = VT_R4;
				curValue.fltVal = (float) wcstod (bsValue, NULL);
				hr = S_OK;
			}
				break;

			case CIM_REAL64:
			{
				VariantClear (&curValue);
				curValue.vt = VT_R8;
				curValue.dblVal = wcstod (bsValue, NULL);
				hr = S_OK;
			}
				break;

			case CIM_BOOLEAN:
			{
				VariantClear (&curValue);
				curValue.vt = VT_BOOL;
				curValue.boolVal = (0 == _wcsicmp (bsValue, L"TRUE")) ?
							VARIANT_TRUE : VARIANT_FALSE;
				hr = S_OK;
			}
				break;

			case CIM_CHAR16:
			{
				// As per the XML Spec, the following are invalid character values in an XML Stream:
				// Char ::=  #x9 | #xA | #xD | [#x20-#xD7FF] | [#xE000-#xFFFD] | [#x10000-#x10FFFF]

				// As per the CIM Operations spec, they need to be escaped as follows:
				//	If the value is not a legal XML character
				//  (as defined in [2, section 2.2] by the Char production)
				//	then it MUST be escaped using a \x<hex> escape convention
				//	where <hex> is a hexadecimal constant consisting of
				//	between one and four digits

				VariantClear (&curValue);
				curValue.vt = VT_I2;
				if(_wcsnicmp(bsValue, L"\\x", 2) == 0)
					// It is an escaped value
					swscanf (bsValue+2, L"%x", &(curValue.iVal));
				else
					// It is a normal value
					swscanf (bsValue, L"%c", &(curValue.iVal));
				hr = S_OK;
			}
				break;

			case CIM_STRING:
			case CIM_UINT64:
			case CIM_SINT64:
			case CIM_DATETIME:
			{
				VariantClear (&curValue);
				curValue.vt = VT_BSTR;
				curValue.bstrVal = SysAllocString (bsValue);
				hr = S_OK;
			}
				break;
		}
	}

	return hr;
}

//***************************************************************************
//
//  HRESULT CXmlToWmi::MapStringArrayValue
//
//  DESCRIPTION:
//
//  Maps XML VALUE.ARRAY element content into its WMI VARIANT equivalent form
//
//  PARAMETERS:
//
//		pValueNode		the VALUE.ARRAY node
//		curValue		Placeholder for new value (set on return)
//		cimtype			for mapping purposes
//
//  RETURN VALUES:
//
//
//***************************************************************************

HRESULT CXmlToWmi::MapStringArrayValue (
	IXMLDOMNode *pValueNode,
	VARIANT &curValue,
	CIMTYPE cimtype
)
{
	HRESULT hr = WBEM_E_TYPE_MISMATCH;

	// Build a safearray value from the node list
	IXMLDOMNodeList *pValueList = NULL;
	if (SUCCEEDED (pValueNode->get_childNodes (&pValueList)))
	{
		long length = 0;
		pValueList->get_length (&length);
		SAFEARRAYBOUND	rgsabound [1];
		rgsabound [0].lLbound = 0;
		rgsabound [0].cElements = length;
		VARTYPE vt = VTFromCIMType (cimtype & ~CIM_FLAG_ARRAY);
		SAFEARRAY *pArray = NULL;
		
		if(pArray = SafeArrayCreate (vt, 1, rgsabound))
		{
			IXMLDOMNode *pValue = NULL;
			long ix = 0;
			bool error = false;

			while (!error &&
					SUCCEEDED(pValueList->nextNode(&pValue)) && pValue)
			{
				BSTR strValName = NULL;

				if (SUCCEEDED(pValue->get_nodeName (&strValName)))
				{
					if (0 == _wcsicmp (strValName, VALUE_TAG))
					{
						BSTR bsValue = NULL;
						pValue->get_text (&bsValue);
						if(FAILED(MapStringValueIntoArray (bsValue, pArray, &ix, vt,
							cimtype & ~CIM_FLAG_ARRAY)))
							error = true;

						SysFreeString (bsValue);
						ix++;
					}
					else
					{
						// unexpected element
						error = true;
					}

					SysFreeString (strValName);
				}

				pValue->Release ();
				pValue = NULL;
			}

			if (error)
				SafeArrayDestroy(pArray);
			else
			{
				curValue.vt = VT_ARRAY|vt;
				curValue.parray = pArray;
				hr = S_OK;
			}
		}
		else
			hr = E_OUTOFMEMORY;
		pValueList->Release();
	}

	return hr;
}

//***************************************************************************
//
//  HRESULT CXmlToWmi::MapStringValueIntoArray
//
//  DESCRIPTION:
//
//  Maps XML VALUE.ARRAY/VALUE element content into its WMI VARIANT equivalent form
//
//  PARAMETERS:
//
//		bsValue			the VALUE element content
//		pArray			SAFEARRAY in which to map the value
//		ix				index to map the value into
//		vt				VARTYPE of the SAFEARRAY
//		cimtype			for mapping purposes
//
//  RETURN VALUES:
//
//
//***************************************************************************

HRESULT CXmlToWmi::MapStringValueIntoArray (
	BSTR bsValue,
	SAFEARRAY *pArray,
	long *ix,
	VARTYPE vt,
	CIMTYPE cimtype)
{
	HRESULT hr = E_FAIL;
	switch (vt)
	{
		case VT_UI1:
		{
			BYTE bVal = (BYTE) wcstol (bsValue, NULL, 0);
			hr = SafeArrayPutElement (pArray, ix, &bVal);
		}
			break;

		case VT_I2:
		{
			short iVal;

			if (CIM_CHAR16 == cimtype)
				swscanf (bsValue, L"%c", &(iVal));
			else
				iVal = (short) wcstol (bsValue, NULL, 0);

			hr = SafeArrayPutElement (pArray, ix, &iVal);
		}
			break;

		case VT_I4:
		{
			long lVal = wcstol (bsValue, NULL, 0);
			hr = SafeArrayPutElement (pArray, ix, &lVal);
		}
			break;

		case VT_R4:
		{
			float fltVal = (float) wcstod (bsValue, NULL);
			hr = SafeArrayPutElement (pArray, ix, &fltVal);
		}
			break;

		case VT_R8:
		{
			double dblVal = wcstod (bsValue, NULL);
			hr = SafeArrayPutElement (pArray, ix, &dblVal);
		}
			break;

		case VT_BOOL:
		{
			VARIANT_BOOL boolVal = (0 == _wcsicmp (bsValue, L"TRUE")) ?
						VARIANT_TRUE : VARIANT_FALSE;
			hr = SafeArrayPutElement (pArray, ix, &boolVal);
		}
			break;

		case VT_BSTR:
			hr = SafeArrayPutElement (pArray, ix, bsValue);
			break;
	}
	return hr;
}

//***************************************************************************
//
//  HRESULT CXmlToWmi::MapReferenceValue
//
//  DESCRIPTION:
//
//  Maps XML VALUE.REFERENCE element content into its WMI VARIANT equivalent form
//
//  PARAMETERS:
//
//		curValue		Placeholder for new value (set on return)
//		cimtype			for mapping purposes
//
//  RETURN VALUES:
//
//
//***************************************************************************

HRESULT CXmlToWmi::MapReferenceValue (IXMLDOMNode *pValue, VARIANT &curValue)
{
	HRESULT hr = WBEM_E_FAILED;
	curValue.vt = VT_BSTR;
	if(SUCCEEDED(hr = ParseOneReferenceValue(pValue, &curValue.bstrVal)))
	{
	}
	return hr;
}



//***************************************************************************
//
//  HRESULT CXmlToWmi::MapReferenceArrayValue
//
//  DESCRIPTION:
//
//  Maps XML VALUE.REFARRAY element content into its WMI VARIANT equivalent form
//
//  PARAMETERS:
//
//		pValueNode		the VALUE.REFARRAY node
//		curValue		Placeholder for new value (set on return)
//
//  RETURN VALUES:
//
//
//***************************************************************************

HRESULT CXmlToWmi::MapReferenceArrayValue (
	IXMLDOMNode *pValueNode,
	VARIANT &curValue
)
{
	HRESULT hr = WBEM_E_TYPE_MISMATCH;

	// Build a safearray value from the node list underneath VALUE.REFARRAY
	// Each such node is a VALUE.REFERENCE
	IXMLDOMNodeList *pValueList = NULL;
	if (SUCCEEDED (pValueNode->get_childNodes (&pValueList)))
	{
		long length = 0;
		pValueList->get_length (&length);
		SAFEARRAYBOUND	rgsabound [1];
		rgsabound [0].lLbound = 0;
		rgsabound [0].cElements = length;
		VARTYPE vt = VTFromCIMType (CIM_REFERENCE & ~CIM_FLAG_ARRAY);
		SAFEARRAY *pArray = NULL;
		
		if(pArray = SafeArrayCreate (vt, 1, rgsabound))
		{
			IXMLDOMNode *pValue = NULL;
			long ix = 0;
			bool error = false;

			while (!error &&
					SUCCEEDED(pValueList->nextNode(&pValue)) && pValue)
			{
				BSTR strValName = NULL;

				if (SUCCEEDED(pValue->get_nodeName (&strValName)))
				{
					if (0 == _wcsicmp (strValName, VALUEREFERENCE_TAG))
					{
						BSTR strNextValue = NULL;
						if(SUCCEEDED(ParseOneReferenceValue(pValue, &strNextValue)))
						{
							if(FAILED(SafeArrayPutElement (pArray, &ix, strNextValue)))
								error = true;
							SysFreeString(strNextValue);
						}
						ix++;
					}
					else
					{
						// unexpected element
						error = true;
					}

					SysFreeString (strValName);
				}

				pValue->Release ();
				pValue = NULL;
			}

			if (error)
				SafeArrayDestroy(pArray);
			else
			{
				curValue.vt = VT_ARRAY|vt;
				curValue.parray = pArray;
				hr = S_OK;
			}
		}
		else
			hr = E_OUTOFMEMORY;
		pValueList->Release();
	}

	return hr;
}

//***************************************************************************
//
//  HRESULT CXmlToWmi::MapObjectValue
//
//  DESCRIPTION:
//
//  Maps XML VALUE.OBJECT element content into its WMI VARIANT equivalent form
//
//  PARAMETERS:
//
//		curValue		Placeholder for new value (set on return)
//		cimtype			for mapping purposes
//
//  RETURN VALUES:
//
//
//***************************************************************************

HRESULT CXmlToWmi::MapObjectValue (IXMLDOMNode *pValue, VARIANT &curValue)
{
	HRESULT hr = WBEM_E_FAILED;
	curValue.vt = VT_UNKNOWN;
	if(SUCCEEDED(hr = MapOneObjectValue(pValue, &curValue.punkVal)))
	{
	}
	return hr;
}

HRESULT CXmlToWmi::MapOneObjectValue (IXMLDOMNode *pValueRef, IUnknown **ppunkValue)
{
	HRESULT hr = E_FAIL;
	// Let's look at the child of the VALUE.OBJECT tag
	IXMLDOMNode *pChild = NULL;
	if (SUCCEEDED(pValueRef->get_firstChild (&pChild)) && pChild)
	{
		// Next node should be a CLASS or an INSTANCE element
		BSTR strNodeName = NULL;
		if(SUCCEEDED(pChild->get_nodeName(&strNodeName)))
		{
			// In this case, we need the superclass (if any)
			// to spawn a derived class
			if (_wcsicmp(strNodeName, CLASS_TAG) == 0)
			{
				// Should have a CLASS element - does it have a SUPERCLASS attribute?
				BSTR strSuperClass = NULL;
				GetBstrAttribute (pChild, SUPERCLASS_ATTRIBUTE, &strSuperClass);
				IWbemClassObject *pObject = NULL;
				if (WBEM_S_NO_ERROR == (hr = m_pServices->GetObject (strSuperClass, 0, NULL, &pObject, NULL)))
				{
					// Got the underlying class - now map the new value 
					if (strSuperClass && (0 < wcslen (strSuperClass)))
					{
						IWbemClassObject *pSubClass = NULL;
						if (SUCCEEDED(hr = pObject->SpawnDerivedClass (0, &pSubClass)))
						{
							CXmlToWmi xmlToWmi;
							if(SUCCEEDED(hr = xmlToWmi.Initialize(pChild, m_pServices, pSubClass)))
							{
								if(SUCCEEDED(hr = xmlToWmi.MapClass ()))
								{
									*ppunkValue = pSubClass;
									pSubClass->AddRef();
								}
							}

							pSubClass->Release ();
						}
					}
					else
					{
						CXmlToWmi xmlToWmi;
						if(SUCCEEDED(hr = xmlToWmi.Initialize(pChild, m_pServices, pObject)))
						{
							hr = xmlToWmi.MapClass ();
						}
					}

					pObject->Release ();
				}
				SysFreeString(strSuperClass);
			}
			else if (_wcsicmp(strNodeName, INSTANCE_TAG) == 0)
			{
				// In this case, we need the class object of the instance
				// to spawn an instance
				IWbemClassObject *pObject = NULL;

				// Should have a CLASSNAME attribute
				BSTR strClassName = NULL;
				GetBstrAttribute (pChild, CLASS_NAME_ATTRIBUTE, &strClassName);

				if (strClassName && (0 < wcslen (strClassName)) &&
					WBEM_S_NO_ERROR == (hr = m_pServices->GetObject (strClassName, 0, NULL, &pObject, NULL)))
				{
					// Got the underlying class - now map the new value 
					IWbemClassObject *pNewInstance = NULL;
					if (SUCCEEDED(hr = pObject->SpawnInstance (0, &pNewInstance)))
					{
						CXmlToWmi xmlToWmi;
						if(SUCCEEDED(hr = xmlToWmi.Initialize(pChild, m_pServices, pNewInstance)))
						{
							if (SUCCEEDED (hr = xmlToWmi.MapInstance ()))
							{
								*ppunkValue = pNewInstance;
								pNewInstance->AddRef();
							}
						}
						pNewInstance->Release ();
					}
					pObject->Release ();
				}
				else
					hr = WBEM_E_FAILED;
				SysFreeString (strClassName);
			}

			SysFreeString(strNodeName);
		}
		pChild->Release();
	}

	return hr;
}


//***************************************************************************
//
//  HRESULT CXmlToWmi::MapObjectArrayValue
//
//  DESCRIPTION:
//
//  Maps XML VALUE.OBJECTARRAY element content into its WMI VARIANT equivalent form
//
//  PARAMETERS:
//
//		pValueNode		the VALUE.OBJECTARRAY node
//		curValue		Placeholder for new value (set on return)
//
//  RETURN VALUES:
//
//
//***************************************************************************

HRESULT CXmlToWmi::MapObjectArrayValue (
	IXMLDOMNode *pValueNode,
	VARIANT &curValue)
{
	HRESULT hr = WBEM_E_TYPE_MISMATCH;

	// Build a safearray value from the node list underneath VALUE.OBJECTARRAY
	// Each such node is a VALUE.OBJECT
	IXMLDOMNodeList *pValueList = NULL;
	if (SUCCEEDED (pValueNode->get_childNodes (&pValueList)))
	{
		long length = 0;
		pValueList->get_length (&length);
		SAFEARRAYBOUND	rgsabound [1];
		rgsabound [0].lLbound = 0;
		rgsabound [0].cElements = length;
		VARTYPE vt = VTFromCIMType (CIM_OBJECT & ~CIM_FLAG_ARRAY);
		SAFEARRAY *pArray = NULL;
		if(pArray = SafeArrayCreate (vt, 1, rgsabound))
		{
			IXMLDOMNode *pValue = NULL;
			long ix = 0;
			bool error = false;

			while (!error &&
					SUCCEEDED(pValueList->nextNode(&pValue)) && pValue)
			{
				BSTR strValName = NULL;

				if (SUCCEEDED(pValue->get_nodeName (&strValName)))
				{
					if (0 == _wcsicmp (strValName, VALUEOBJECT_TAG))
					{
						IUnknown *pNextValue = NULL;
						if(SUCCEEDED(MapOneObjectValue(pValue, &pNextValue)))
						{
							if(FAILED(SafeArrayPutElement (pArray, &ix, pNextValue)))
								error = true;
							pNextValue->Release();;
						}
						ix++;
					}
					else
					{
						// unexpected element
						error = true;
					}

					SysFreeString (strValName);
				}

				pValue->Release ();
				pValue = NULL;
			}

			if (error)
				SafeArrayDestroy(pArray);
			else
			{
				curValue.vt = VT_ARRAY|vt;
				curValue.parray = pArray;
				hr = S_OK;
			}
		}
		else
			hr = E_OUTOFMEMORY;
		pValueList->Release();
	}

	return hr;
}

//***************************************************************************
//
//  HRESULT CXmlToWmi::VTFromCIMType
//
//  DESCRIPTION:
//
//  Utility function to map CIMTYPE to its VARTYPE equivalent
//
//  PARAMETERS:
//
//		cimtype			the CIMTYPE to be mapped
//
//  RETURN VALUES:
//
//		The corresponding VARTYPE, or VT_NULL if error
//
//***************************************************************************

VARTYPE CXmlToWmi::VTFromCIMType (CIMTYPE cimtype)
{
	VARTYPE vt = VT_NULL;

	switch (cimtype & ~CIM_FLAG_ARRAY)
	{
		case CIM_UINT8:
			vt = VT_UI1;
			break;

		case CIM_SINT8:
		case CIM_SINT16:
			vt = VT_I2;
			break;

		case CIM_UINT16:
		case CIM_UINT32:
		case CIM_SINT32:
			vt = VT_I4;
			break;

		case CIM_REAL32:
			vt = VT_R4;
			break;

		case CIM_REAL64:
			vt = VT_R8;
			break;

		case CIM_BOOLEAN:
			vt = VT_BOOL;
			break;

		case CIM_CHAR16:
			vt = VT_I2;
			break;

		case CIM_STRING:
		case CIM_UINT64:
		case CIM_SINT64:
		case CIM_DATETIME:
			vt = VT_BSTR;
			break;
	}

	return vt;
}

//***************************************************************************
//
//  HRESULT CXmlToWmi::CIMTypeFromString
//
//  DESCRIPTION:
//
//  Utility function to map type attribute string to its CIMTYPE equivalent
//
//  PARAMETERS:
//
//		bsType			the type string to be mapped
//
//  RETURN VALUES:
//
//		The corresponding CIMTYPE, or CIM_ILLEGAL if error
//
//***************************************************************************
CIMTYPE CXmlToWmi::CimtypeFromString (BSTR bsType)
{
	CIMTYPE cimtype = CIM_ILLEGAL;

	if (bsType)
	{
		if (0 == _wcsicmp (bsType, L"string"))
			cimtype = CIM_STRING;
		else if (0 == _wcsicmp (bsType, L"uint32"))
			cimtype = CIM_UINT32;
		else if (0 == _wcsicmp (bsType, L"boolean"))
			cimtype = CIM_BOOLEAN;
		else if (0 == _wcsicmp (bsType, L"sint32"))
			cimtype = CIM_SINT32;
		else if (0 == _wcsicmp (bsType, L"char16"))
			cimtype = CIM_CHAR16;
		else if (0 == _wcsicmp (bsType, L"uint8"))
			cimtype = CIM_UINT8;
		else if (0 == _wcsicmp (bsType, L"uint16"))
			cimtype = CIM_UINT16;
		else if (0 == _wcsicmp (bsType, L"sint16"))
			cimtype = CIM_SINT16;
		else if (0 == _wcsicmp (bsType, L"uint64"))
			cimtype = CIM_UINT64;
		else if (0 == _wcsicmp (bsType, L"sint64"))
			cimtype = CIM_SINT64;
		else if (0 == _wcsicmp (bsType, L"datetime"))
			cimtype = CIM_DATETIME;
		else if (0 == _wcsicmp (bsType, L"real32"))
			cimtype = CIM_REAL32;
		else if (0 == _wcsicmp (bsType, L"real64"))
			cimtype = CIM_REAL64;
	}

	return cimtype;
}

HRESULT CXmlToWmi::SetArraySize (
	IWbemQualifierSet *pQualSet,
	BSTR strArraySize
)
{
	HRESULT hr = WBEM_E_FAILED;

	if (strArraySize)
	{
		VARIANT curValue;
		VariantInit (&curValue);
		curValue.vt = VT_I4;
		curValue.lVal = wcstol (strArraySize, NULL, 0);

		if (0 < curValue.lVal)
		{
			if (SUCCEEDED(hr = pQualSet->Put(L"MAX", &curValue,
					WBEM_FLAVOR_FLAG_PROPAGATE_TO_DERIVED_CLASS|
					WBEM_FLAVOR_FLAG_PROPAGATE_TO_INSTANCE|
					WBEM_FLAVOR_NOT_OVERRIDABLE)))
				hr = pQualSet->Put(L"MIN", &curValue,
					WBEM_FLAVOR_FLAG_PROPAGATE_TO_DERIVED_CLASS|
					WBEM_FLAVOR_FLAG_PROPAGATE_TO_INSTANCE|
					WBEM_FLAVOR_NOT_OVERRIDABLE);
		}

		VariantClear (&curValue);
	}

	return hr;
}

HRESULT CXmlToWmi::SetReferenceClass (
	IWbemQualifierSet *pQualSet,
	BSTR strReferenceClass
)
{
#define	REF_STR	L"ref"

	HRESULT hr = WBEM_E_FAILED;
	int strLen = wcslen(REF_STR);
	bool bIsStrongReference = (strReferenceClass && (0 < wcslen(strReferenceClass)));

	if (bIsStrongReference)
		strLen += wcslen(strReferenceClass) + 1;	// 1 for the ":" separator

	WCHAR *pRef = new WCHAR [strLen + 1];
	wcscpy (pRef, REF_STR);

	if (bIsStrongReference)
	{
		wcscat (pRef, L":");
		wcscat (pRef, strReferenceClass);
	}

	VARIANT curValue;
	VariantInit (&curValue);
	curValue.vt = VT_BSTR;
	curValue.bstrVal = SysAllocString (pRef);
	delete [] pRef;

	hr = pQualSet->Put(L"CIMTYPE", &curValue,
					WBEM_FLAVOR_FLAG_PROPAGATE_TO_DERIVED_CLASS|
					WBEM_FLAVOR_FLAG_PROPAGATE_TO_INSTANCE|
					WBEM_FLAVOR_NOT_OVERRIDABLE);

	VariantClear (&curValue);

	return hr;
#undef REF_STR
}


HRESULT CXmlToWmi::SetObjectClass (
	IWbemQualifierSet *pQualSet,
	BSTR strReferenceClass
)
{
#define	OBJ_STR	L"obj"

	HRESULT hr = WBEM_E_FAILED;
	int strLen = wcslen(OBJ_STR);
	bool bIsStrongReference = (strReferenceClass && (0 < wcslen(strReferenceClass)));

	if (bIsStrongReference)
		strLen += wcslen(strReferenceClass) + 1;	// 1 for the ":" separator

	WCHAR *pRef = new WCHAR [strLen + 1];
	wcscpy (pRef, OBJ_STR);

	if (bIsStrongReference)
	{
		wcscat (pRef, L":");
		wcscat (pRef, strReferenceClass);
	}

	VARIANT curValue;
	VariantInit (&curValue);
	curValue.vt = VT_BSTR;
	curValue.bstrVal = SysAllocString (pRef);
	delete [] pRef;

	hr = pQualSet->Put(L"CIMTYPE", &curValue,
					WBEM_FLAVOR_FLAG_PROPAGATE_TO_DERIVED_CLASS|
					WBEM_FLAVOR_FLAG_PROPAGATE_TO_INSTANCE|
					WBEM_FLAVOR_NOT_OVERRIDABLE);

	VariantClear (&curValue);

	return hr;
#undef OBJ_STR
}


HRESULT CXmlToWmi::MapContextProperty (
	IXMLDOMNode *pProperty,
	IWbemContext *pContext
)
{
	HRESULT hr = WBEM_E_FAILED;

	BSTR strName = NULL;
	BSTR strType = NULL;

	// Get the NAMEof the property
	if(SUCCEEDED(hr = GetBstrAttribute (pProperty, NAME_ATTRIBUTE, &strName)) && strName)
	{
		// Get the VTTYPE of the property
		if(SUCCEEDED(hr = GetBstrAttribute (pProperty, VTTYPE_ATTRIBUTE, &strType)) && strType)
		{
			// Map the Property type
			VARTYPE vartype = VT_EMPTY;
			if (VT_EMPTY != (vartype = VarTypeFromString (strType)))
			{

				// Get the child element of type "VALUE"
				VARIANT_BOOL bHasChildNodes;
				if (SUCCEEDED(pProperty->hasChildNodes (&bHasChildNodes)) &&
					(VARIANT_TRUE == bHasChildNodes))
				{
					IXMLDOMNodeList *pNodeList = NULL;
					if (SUCCEEDED(pProperty->get_childNodes (&pNodeList)))
					{
						IXMLDOMNode *pNode = NULL;

						while (SUCCEEDED(hr) && SUCCEEDED(pNodeList->nextNode (&pNode)) &&pNode)
						{
							BSTR strNodeName = NULL;

							if (SUCCEEDED(pNode->get_nodeName (&strNodeName)))
							{
								if (0 == _wcsicmp(strNodeName, VALUE_TAG))
								{
									BSTR bsValue = NULL;
									pNode->get_text(&bsValue);

									// Map the Qualifier value
									VARIANT value;
									VariantInit (&value);

									// Map the value to a variant
									if(SUCCEEDED(hr = MapContextStringValue (bsValue, value, vartype)))
									{
										// Put the value in the context
										hr = pContext->SetValue (strName, 0, &value);
										VariantClear (&value);
									}
									SysFreeString (bsValue);
								}
								SysFreeString (strNodeName);
							}

							pNode->Release ();
							pNode = NULL;
						}

						pNodeList->Release ();
					}
				}
			}
			SysFreeString(strType);
		}
		SysFreeString(strName);
	}

	return hr;
}


HRESULT CXmlToWmi::MapContextPropertyArray (
	IXMLDOMNode *pProperty,
	IWbemContext *pContext
)
{
	HRESULT hr = WBEM_E_FAILED;

	BSTR strName = NULL;
	BSTR strType = NULL;
	BSTR strArraySize = NULL;

	// Get the NAME of the property
	if(SUCCEEDED(hr = GetBstrAttribute (pProperty, NAME_ATTRIBUTE, &strName)) && strName)
	{
		// Get the VTTYPE of the property
		if(SUCCEEDED(hr = GetBstrAttribute (pProperty, VTTYPE_ATTRIBUTE, &strType)) && strType)
		{
			// Get the size of the array
			if(SUCCEEDED(hr = GetBstrAttribute (pProperty, ARRAYSIZE_ATTRIBUTE, &strArraySize)) && strArraySize)
			{
				// Map the Property type
				VARTYPE vartype = VT_EMPTY;
				if (VT_EMPTY != (vartype = VarTypeFromString (strType)))
				{
					// Get the child element of type "VALUE.ARRAY"
					VARIANT_BOOL bHasChildNodes;
					if (SUCCEEDED(pProperty->hasChildNodes (&bHasChildNodes)) &&
						(VARIANT_TRUE == bHasChildNodes))
					{
						IXMLDOMNodeList *pNodeList = NULL;
						if (SUCCEEDED(pProperty->get_childNodes (&pNodeList)))
						{
							IXMLDOMNode *pNode = NULL;

							while (SUCCEEDED(hr) && SUCCEEDED(pNodeList->nextNode (&pNode)) &&pNode)
							{
								BSTR strNodeName = NULL;

								if (SUCCEEDED(pNode->get_nodeName (&strNodeName)))
								{
									if (0 == _wcsicmp(strNodeName, VALUEARRAY_TAG))
									{
										VARIANT value;
										VariantInit(&value);

										// Map the value to a variant
										if(SUCCEEDED(hr = MapContextStringArrayValue (pNode, value, vartype)))
										{
											// Put the value in the context
											hr = pContext->SetValue (strName, 0, &value);
											VariantClear (&value);
										}
									}
									else
										hr = WBEM_E_FAILED;	// Parse error
									SysFreeString (strNodeName);
								}

								pNode->Release ();
								pNode = NULL;
							}

							pNodeList->Release ();
						}
					}
				}
				SysFreeString(strArraySize);
			}
			SysFreeString(strType);
		}
		SysFreeString(strName);
	}

	return hr;
}

//***************************************************************************
//
//  HRESULT CXmlToWmi::VarTypeFromString
//
//  DESCRIPTION:
//
//  Utility function to map type attribute string to its VARTYPE equivalent
//
//  PARAMETERS:
//
//		bsType			the type string to be mapped
//
//  RETURN VALUES:
//
//		The corresponding VARTYPE, or VT_EMPTY if error
//
//***************************************************************************
VARTYPE CXmlToWmi::VarTypeFromString (BSTR bsType)
{
	VARTYPE vartype = VT_EMPTY;

	if (bsType)
	{
		if (0 == _wcsicmp (bsType, L"VT_I4"))
			vartype = VT_I4;
		else if (0 == _wcsicmp (bsType, L"VT_R8"))
			vartype = VT_R8;
		else if (0 == _wcsicmp (bsType, L"VT_BOOL"))
			vartype = VT_BOOL;
		else if (0 == _wcsicmp (bsType, L"VT_BSTR"))
			vartype = VT_BSTR;
	}

	return vartype;
}

//***************************************************************************
//
//  HRESULT CXmlToWmi::MapContextStringValue
//
//  DESCRIPTION:
//
//  Maps XML VALUE element content into its WMI VARIANT equivalent form
//
//  PARAMETERS:
//
//		bsValue			the VALUE element content
//		curValue		Placeholder for new value (set on return)
//		cimtype			for mapping purposes
//
//  RETURN VALUES:
//
//
//***************************************************************************

HRESULT CXmlToWmi::MapContextStringValue (BSTR bsValue, VARIANT &curValue, VARTYPE vartype)
{
	HRESULT hr = WBEM_E_TYPE_MISMATCH;

	// We're assuming it's not an array
	switch (vartype)
	{
		// RAJESHR - more rigorous syntax checking
		case VT_I4:
		{
			VariantClear (&curValue);
			curValue.vt = VT_I4;
			curValue.lVal = wcstol (bsValue, NULL, 0);
			hr = S_OK;
		}
			break;

		case VT_R8:
		{
			VariantClear (&curValue);
			curValue.vt = VT_R8;
			curValue.dblVal = wcstod (bsValue, NULL);
			hr = S_OK;
		}
			break;

		case VT_BOOL:
		{
			VariantClear (&curValue);
			curValue.vt = VT_BOOL;
			curValue.boolVal = (0 == _wcsicmp (bsValue, L"TRUE")) ?
						VARIANT_TRUE : VARIANT_FALSE;
			hr = S_OK;
		}
			break;

		case VT_BSTR:
		{
			VariantClear (&curValue);
			curValue.vt = VT_BSTR;
			curValue.bstrVal = SysAllocString (bsValue);
			hr = S_OK;
		}
			break;
	}

	return hr;
}

//***************************************************************************
//
//  HRESULT CXmlToWmi::MapContextStringArrayValue
//
//  DESCRIPTION:
//
//  Maps XML VALUE.ARRAY element content into its WMI VARIANT equivalent form
//
//  PARAMETERS:
//
//		pValueNode		the VALUE.ARRAY node
//		curValue		Placeholder for new value (set on return)
//		cimtype			for mapping purposes
//
//  RETURN VALUES:
//
//
//***************************************************************************

HRESULT CXmlToWmi::MapContextStringArrayValue (
	IXMLDOMNode *pValueNode,
	VARIANT &curValue,
	VARTYPE vartype
)
{
	HRESULT hr = WBEM_E_TYPE_MISMATCH;

	// Build a safearray value from the node list
	IXMLDOMNodeList *pValueList = NULL;

	if (SUCCEEDED (pValueNode->get_childNodes (&pValueList)))
	{
		long length = 0;
		pValueList->get_length (&length);
		SAFEARRAYBOUND	rgsabound [1];
		rgsabound [0].lLbound = 0;
		rgsabound [0].cElements = length;
		SAFEARRAY *pArray = NULL;
		if(pArray = SafeArrayCreate (vartype, 1, rgsabound))
		{
			IXMLDOMNode *pValue = NULL;
			long ix = 0;
			bool error = false;

			while (!error &&
					SUCCEEDED(pValueList->nextNode(&pValue)) && pValue)
			{
				BSTR strValName = NULL;

				if (SUCCEEDED(pValue->get_nodeName (&strValName)))
				{
					if (0 == _wcsicmp (strValName, VALUE_TAG))
					{
						BSTR bsValue = NULL;
						pValue->get_text (&bsValue);
						if(FAILED(MapContextStringValueIntoArray (bsValue, pArray, &ix, vartype)))
							error = true;
						SysFreeString (bsValue);
						ix++;
					}
					else
					{
						// unexpected element
						error = true;
					}

					SysFreeString (strValName);
				}

				pValue->Release ();
				pValue = NULL;
			}

			if (error)
				SafeArrayDestroy(pArray);
			else
			{
				curValue.vt = VT_ARRAY|vartype;
				curValue.parray = pArray;
				hr = S_OK;
			}
		}
		else
			hr = E_OUTOFMEMORY;
		pValueList->Release();
	}

	return hr;
}

//***************************************************************************
//
//  HRESULT CXmlToWmi::MapContextStringValueIntoArray
//
//  DESCRIPTION:
//
//  Maps XML VALUE.ARRAY/VALUE element content into its WMI VARIANT equivalent form
//
//  PARAMETERS:
//
//		bsValue			the VALUE element content
//		pArray			SAFEARRAY in which to map the value
//		ix				index to map the value into
//		vt				VARTYPE of the SAFEARRAY
//		cimtype			for mapping purposes
//
//  RETURN VALUES:
//
//
//***************************************************************************

HRESULT CXmlToWmi::MapContextStringValueIntoArray (
	BSTR bsValue,
	SAFEARRAY *pArray,
	long *ix,
	VARTYPE vt)
{
	HRESULT hr = E_FAIL;
	switch (vt)
	{
		case VT_I4:
		{
			long lVal = wcstol (bsValue, NULL, 0);
			hr = SafeArrayPutElement (pArray, ix, &lVal);
		}
			break;

		case VT_R8:
		{
			double dblVal = wcstod (bsValue, NULL);
			hr = SafeArrayPutElement (pArray, ix, &dblVal);
		}
			break;

		case VT_BOOL:
		{
			VARIANT_BOOL boolVal = (0 == _wcsicmp (bsValue, L"TRUE")) ?
						VARIANT_TRUE : VARIANT_FALSE;
			hr = SafeArrayPutElement (pArray, ix, &boolVal);
		}
			break;

		case VT_BSTR:
			hr = SafeArrayPutElement (pArray, ix, bsValue);
			break;
	}
	return hr;
}