

#include "precomp.h"
#include <olectl.h>
#include <wbemidl.h>
#include <wbemint.h>

#include "wmiconv.h"
#include "maindll.h"

/* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 
 * Conversion to Text to Wbem Object has been cut from the WHistler Feature List and hence commented out 
 *!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!


HRESULT CXml2Wmi::AddQualifier (
	IXMLDOMNode *pNode, // A <QUALIFIER> element
	IWbemQualifierSet *pQualSet,
	bool bIsObjectQualifier // Indicates whether this is for an object or for a property
)
{
	HRESULT hr = S_OK;

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

	// Get the Name of the Qualifier - this is a mandatory attribute
	if(SUCCEEDED(hr))
		hr = GetBstrAttribute (pNode, g_strName, &strName);

	// Dont map the CIMTYPE QUalifier
	// Dont map the "abstract" qualifiers for objects, but map them for properties (for whatever reason)
	if(SUCCEEDED(hr) && _wcsicmp(strName, L"CIMTYPE") == 0 ||
		(bIsObjectQualifier && _wcsicmp(strName, L"abstract") == 0))
	{
		SysFreeString(strName);
		return S_OK;
	}

	// Get a few more attributes - some of these are optional
	// In such cases, we dont check the return value
	if(SUCCEEDED(hr))
		hr = GetBstrAttribute (pNode, g_strType, &strType);
	if(SUCCEEDED(hr))
		GetBstrAttribute (pNode, g_strOverridable, &strOverridable);
	if(SUCCEEDED(hr))
		GetBstrAttribute (pNode, g_strToSubClass, &strToSubclass);
	if(SUCCEEDED(hr))
		GetBstrAttribute (pNode, g_strToInstance, &strToInstance);
	if(SUCCEEDED(hr))
		GetBstrAttribute (pNode, g_strAmended, &strAmended);

	// Build up the flavor of the Qualifier
	//======================================================
	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 = MapStringQualiferValue (bsValue, value, cimtype);
								SysFreeString (bsValue);
							}
						}
						else if (0 == _wcsicmp(strNodeName, VALUEARRAY_TAG))
						{
							hr = MapStringArrayQualiferValue (pValueNode, value, cimtype);
						}

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

			pNodeList->Release ();
		}
	}

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

	SysFreeString (strName);
	SysFreeString (strType);
	SysFreeString (strOverridable);
	SysFreeString (strToSubclass);
	SysFreeString (strToInstance);
	SysFreeString (strAmended);

	VariantClear (&value);

	return hr;
}

//***************************************************************************
//
//  HRESULT CXml2Wmi::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 CXml2Wmi::MapStringQualiferValue (BSTR bsValue, VARIANT &curValue, CIMTYPE cimtype)
{
	HRESULT hr = WBEM_E_TYPE_MISMATCH;
	VariantInit (&curValue);

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

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

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

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

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

			case CIM_BOOLEAN:
			{
				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

				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:
			{
				curValue.vt = VT_BSTR;
				curValue.bstrVal = SysAllocString (bsValue);
				hr = S_OK;
			}
			break;
		}
	}

	return hr;
}

//***************************************************************************
//
//  HRESULT CXml2Wmi::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 CXml2Wmi::MapStringArrayQualiferValue (
	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)
			{
				// Check whether this is a VALUE element
				BSTR strValName = NULL;
				if (SUCCEEDED(pValue->get_nodeName (&strValName)))
				{
					if (0 == _wcsicmp (strValName, VALUE_TAG))
					{
						BSTR bsValue = NULL;
						pValue->get_text (&bsValue);
						if(FAILED(MapStringQualiferValueIntoArray (bsValue, pArray, &ix, vt,
							cimtype & ~CIM_FLAG_ARRAY)))
								error = true;

						SysFreeString (bsValue);
						ix++;
					}
					else
						error = true;

					SysFreeString (strValName);
				}
				else
					error = true;

				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 CXml2Wmi::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 CXml2Wmi::MapStringQualiferValueIntoArray (
	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:
			// No need to SysAllocString() since SafeArrayPutElement() does this automatically
			hr = SafeArrayPutElement (pArray, ix, bsValue);
			break;
	}
	return hr;
}

//***************************************************************************
//
//  HRESULT CXml2Wmi::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 CXml2Wmi::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 CXml2Wmi::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 CXml2Wmi::MakeObjectAbstract(IWbemClassObject *pObj, IXMLDOMNode *pAbstractQualifierNode)
{
	HRESULT hr = E_FAIL;

	// Get the object qualifeir set
	IWbemQualifierSet *pQuals = NULL;
	if(SUCCEEDED(hr = pObj->GetQualifierSet(&pQuals)))
	{
		// Add the "abstract" qualiifer
		hr = AddQualifier(pAbstractQualifierNode, pQuals);
		pQuals->Release();
	}
	return hr;
}

  */