Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

2209 lines
53 KiB

//=======================================================================
//
// Copyright (c) 1998-2000 Microsoft Corporation. All Rights Reserved.
//
// File: SchemaMisc.CPP
//
// Author: Charles Ma
// 2000.10.27
//
// Description:
//
// Implement helper functions related to IU schemas
//
//=======================================================================
//#include "iuengine.h" // PCH - must include first
#include <windows.h>
#include <tchar.h>
#include <ole2.h>
//#include "iu.h"
#include <iucommon.h>
#include "schemamisc.h"
#include <MemUtil.h>
#include "regutil.h"
#include "fileutil.h"
#include "stringutil.h"
#include <shlwapi.h> // pathappend() api
#include "schemakeys.h"
#include <URLLogging.h>
#include <MISTSAFE.h>
#include<wusafefn.h>
//
// max length of platform when being converted into string
// this is an artificial number that we think enough to
// take any MS platform data.
//
const UINT MAX_PLATFORM_STR_LEN = 1024;
//
// private flags used by functions to retrieve string data
//
const DWORD SKIP_SUITES = 0x1;
const DWORD SKIP_SERVICEPACK_VER = 0x2;
const long MAX_VERSION = 256;
const TCHAR REGKEY_IUCTL[] = _T("Software\\Microsoft\\Windows\\CurrentVersion\\WindowsUpdate\\IUControl");
const TCHAR REGVAL_SCHEMAVALIDATION[] = _T("ValidateSchema");
//
// Global pointer gets initialized to NULL by runtime. Any module including schemamisc.h must
// allocate this object following its call to CoInitialize, and delete the object before
// calling CoUninitialize.
//
CSchemaKeys * g_pGlobalSchemaKeys /* = NULL */;
#define QuitIfNull(p) {if (NULL == p) {hr = E_INVALIDARG; return hr;}}
#define QuitIfFail(x) {hr = x; if (FAILED(hr)) goto CleanUp;}
/////////////////////////////////////////////////////////////////////////////
// FindSingleDOMNode()
//
// Retrieve the first xml node with the given tag name under the given parent node
// Return value:
// S_OK if *ppNode returns matching node value
// HRESULT_FROM_WIN32(ERROR_NOT_FOUND) if node not found
// FAILED() otherwise
// Caller is responsible for releasing *ppNode.
/////////////////////////////////////////////////////////////////////////////
HRESULT FindSingleDOMNode(IXMLDOMNode* pParentNode, BSTR bstrName, IXMLDOMNode** ppNode)
{
HRESULT hr = S_OK;
QuitIfNull(ppNode);
*ppNode = NULL;
QuitIfNull(pParentNode);
QuitIfNull(bstrName);
hr = pParentNode->selectSingleNode(bstrName, ppNode);
if (S_FALSE == hr)
{
hr = HRESULT_FROM_WIN32(ERROR_NOT_FOUND);
}
if (FAILED(hr))
{
*ppNode = NULL;
}
return hr;
}
/////////////////////////////////////////////////////////////////////////////
// FindSingleDOMNode()
//
// Retrieve the first xml node with the given tag name in the given xml doc
// Return value:
// S_OK if *ppNode returns matching node value
// HRESULT_FROM_WIN32(ERROR_NOT_FOUND) if node not found
// FAILED() otherwise
// Caller is responsible for releasing *ppNode.
/////////////////////////////////////////////////////////////////////////////
HRESULT FindSingleDOMNode(IXMLDOMDocument* pDoc, BSTR bstrName, IXMLDOMNode** ppNode)
{
HRESULT hr = S_OK;
IXMLDOMNode *pParentNode = NULL;
QuitIfNull(ppNode);
*ppNode = NULL;
QuitIfNull(pDoc);
QuitIfNull(bstrName);
if (SUCCEEDED(hr = pDoc->QueryInterface(IID_IXMLDOMNode, (void**)&pParentNode)))
{
hr = FindSingleDOMNode(pParentNode, bstrName, ppNode);
SafeRelease(pParentNode);
}
return hr;
}
/////////////////////////////////////////////////////////////////////////////
// FindDOMNodeList()
//
// Retrieve the xml nodelist with the given tag name under the given parent node
// Return value: NULL if failed or no match; matching node list otherwise.
/////////////////////////////////////////////////////////////////////////////
IXMLDOMNodeList* FindDOMNodeList(IXMLDOMNode* pParentNode, BSTR bstrName)
{
HRESULT hr = S_OK;
IXMLDOMNodeList *pNodeList = NULL;
LONG lLength = 0;
if (NULL == pParentNode ||
NULL == bstrName ||
FAILED(pParentNode->selectNodes(bstrName, &pNodeList)) ||
NULL == pNodeList)
{
return NULL;
}
if (SUCCEEDED(pNodeList->get_length(&lLength)) &&
lLength > 0)
{
return pNodeList;
}
SafeRelease(pNodeList);
return NULL;
}
/////////////////////////////////////////////////////////////////////////////
// FindDOMNodeList()
//
// Retrieve the xml nodelist with the given tag name in the given xml doc
// Return value: NULL if failed or no match; matching node list otherwise.
/////////////////////////////////////////////////////////////////////////////
IXMLDOMNodeList* FindDOMNodeList(IXMLDOMDocument* pDoc, BSTR bstrName)
{
IXMLDOMNode *pParentNode = NULL;
IXMLDOMNodeList *pNodeList = NULL;
if (NULL != pDoc &&
NULL != bstrName &&
SUCCEEDED(pDoc->QueryInterface(IID_IXMLDOMNode, (void**)&pParentNode)))
{
pNodeList = FindDOMNodeList(pParentNode, bstrName);
pParentNode->Release();
}
return pNodeList;
}
/////////////////////////////////////////////////////////////////////////////
// CreateDOMNode()
//
// Create an xml node of the given type
/////////////////////////////////////////////////////////////////////////////
IXMLDOMNode* CreateDOMNode(IXMLDOMDocument* pDoc, SHORT nType, BSTR bstrName, BSTR bstrNamespaceURI /*= NULL*/)
{
if (NULL == pDoc ||
(NODE_TEXT != nType && NULL == bstrName))
{
return NULL;
}
IXMLDOMNode *pNode = NULL;
VARIANT vType;
VariantInit(&vType);
vType.vt = VT_I2;
vType.iVal = nType;
if (S_OK != pDoc->createNode(vType, bstrName, bstrNamespaceURI, &pNode))
{
return NULL;
}
return pNode;
}
/////////////////////////////////////////////////////////////////////////////
// GetAttribute()
//
// Get attribute (integer) from the xml node
// If function fails, *piAttr preserves original value.
/////////////////////////////////////////////////////////////////////////////
HRESULT GetAttribute(IXMLDOMNode* pNode, BSTR bstrName, INT* piAttr)
{
HRESULT hr = S_OK;
QuitIfNull(pNode);
QuitIfNull(bstrName);
QuitIfNull(piAttr);
VARIANT vAttr;
IXMLDOMElement *pElement = NULL;
IXMLDOMAttribute *pAttrNode = NULL;;
QuitIfFail(pNode->QueryInterface(IID_IXMLDOMElement, (void**)&pElement));
QuitIfFail(pElement->getAttributeNode(bstrName, &pAttrNode));
if (NULL == pAttrNode) goto CleanUp;
QuitIfFail(pAttrNode->get_value(&vAttr));
if (VT_INT == vAttr.vt)
{
*piAttr = vAttr.intVal;
}
else if (VT_BSTR == vAttr.vt)
{
*piAttr = (INT)MyBSTR2L(vAttr.bstrVal);
}
else if (VT_I2 == vAttr.vt)
{
*piAttr = vAttr.iVal;
}
else
{
hr = E_FAIL;
}
VariantClear(&vAttr);
CleanUp:
SafeRelease(pElement);
SafeRelease(pAttrNode);
return hr;
}
/////////////////////////////////////////////////////////////////////////////
// GetAttribute()
//
// Get attribute (long) from the xml node
// If function fails, *piAttr preservers original value.
/////////////////////////////////////////////////////////////////////////////
HRESULT GetAttribute(IXMLDOMNode* pNode, BSTR bstrName, LONG* plAttr)
{
HRESULT hr = S_OK;
QuitIfNull(pNode);
QuitIfNull(bstrName);
QuitIfNull(plAttr);
VARIANT vAttr;
IXMLDOMElement *pElement = NULL;
IXMLDOMAttribute *pAttrNode = NULL;;
QuitIfFail(pNode->QueryInterface(IID_IXMLDOMElement, (void**)&pElement));
QuitIfFail(pElement->getAttributeNode(bstrName, &pAttrNode));
if (NULL == pAttrNode) goto CleanUp;
QuitIfFail(pAttrNode->get_value(&vAttr));
if (VT_I4 == vAttr.vt)
{
*plAttr = vAttr.lVal;
}
else if (VT_BSTR == vAttr.vt)
{
*plAttr = MyBSTR2L(vAttr.bstrVal);
}
else
{
hr = E_FAIL;
}
VariantClear(&vAttr);
CleanUp:
SafeRelease(pElement);
SafeRelease(pAttrNode);
return hr;
}
/////////////////////////////////////////////////////////////////////////////
// GetAttribute()
//
// Get attribute (BOOL) from the xml node
// If function fails, *piAttr preservers original value.
/////////////////////////////////////////////////////////////////////////////
HRESULT GetAttributeBOOL(IXMLDOMNode* pNode, BSTR bstrName, BOOL * pfAttr)
{
HRESULT hr = S_OK;
QuitIfNull(pNode);
QuitIfNull(bstrName);
QuitIfNull(pfAttr);
VARIANT vAttr;
VARIANT vAttrBool;
IXMLDOMElement *pElement = NULL;
IXMLDOMAttribute *pAttrNode = NULL;;
QuitIfFail(pNode->QueryInterface(IID_IXMLDOMElement, (void**)&pElement));
QuitIfFail(pElement->getAttributeNode(bstrName, &pAttrNode));
if (NULL == pAttrNode) goto CleanUp;
QuitIfFail(pAttrNode->get_value(&vAttr));
QuitIfFail(VariantChangeType(&vAttr, &vAttrBool, 0, VT_BOOL));
VariantClear(&vAttr);
*pfAttr = (VARIANT_TRUE == vAttrBool.boolVal) ? TRUE : FALSE;
CleanUp:
SafeRelease(pElement);
SafeRelease(pAttrNode);
return hr;
}
/////////////////////////////////////////////////////////////////////////////
// GetAttribute()
//
// Get attribute (BSTR) from the xml node
/////////////////////////////////////////////////////////////////////////////
HRESULT GetAttribute(IXMLDOMNode* pNode, BSTR bstrName, BSTR* pbstrAttr)
{
HRESULT hr = S_OK;
QuitIfNull(pbstrAttr);
*pbstrAttr = NULL;
QuitIfNull(pNode);
QuitIfNull(bstrName);
VARIANT vAttr;
IXMLDOMElement *pElement = NULL;
IXMLDOMAttribute *pAttrNode = NULL;;
QuitIfFail(pNode->QueryInterface(IID_IXMLDOMElement, (void**)&pElement));
QuitIfFail(pElement->getAttributeNode(bstrName, &pAttrNode));
if (NULL == pAttrNode) goto CleanUp;
QuitIfFail(pAttrNode->get_value(&vAttr));
if (VT_BSTR == vAttr.vt)
{
*pbstrAttr = SysAllocString(vAttr.bstrVal);
}
else
{
hr = E_FAIL;
}
VariantClear(&vAttr);
CleanUp:
SafeRelease(pElement);
SafeRelease(pAttrNode);
return hr;
}
/////////////////////////////////////////////////////////////////////////////
// SetAttribute()
//
// Set attribute (integer) to the xml element
/////////////////////////////////////////////////////////////////////////////
HRESULT SetAttribute(IXMLDOMNode* pNode, BSTR bstrName, INT iAttr)
{
VARIANT vAttr;
VariantInit(&vAttr);
vAttr.vt = VT_INT;
vAttr.intVal = iAttr;
return SetAttribute(pNode, bstrName, vAttr);
}
/////////////////////////////////////////////////////////////////////////////
// SetAttribute()
//
// Set attribute (BSTR) to the xml element
/////////////////////////////////////////////////////////////////////////////
HRESULT SetAttribute(IXMLDOMNode* pNode, BSTR bstrName, BSTR bstrAttr)
{
HRESULT hr = S_OK;
QuitIfNull(bstrAttr);
VARIANT vAttr;
VariantInit(&vAttr);
vAttr.vt = VT_BSTR;
vAttr.bstrVal = bstrAttr;
return SetAttribute(pNode, bstrName, vAttr);
}
/////////////////////////////////////////////////////////////////////////////
// SetAttribute()
//
// Set attribute (VARIANT) to the xml element
/////////////////////////////////////////////////////////////////////////////
HRESULT SetAttribute(IXMLDOMNode* pNode, BSTR bstrName, VARIANT vAttr)
{
HRESULT hr = S_OK;
QuitIfNull(pNode);
QuitIfNull(bstrName);
IXMLDOMElement *pElement = NULL;
QuitIfFail(pNode->QueryInterface(IID_IXMLDOMElement, (void**)&pElement));
QuitIfFail(pElement->setAttribute(bstrName, vAttr));
CleanUp:
SafeRelease(pElement);
return hr;
}
/////////////////////////////////////////////////////////////////////////////
// GetText()
//
// Get text (BSTR) from the xml node
// Returns
// S_OK if *pbstrText returns text of 1st child of the given node
// S_FALSE if node has no child or 1st child has no text
// FAILED() otherwise
/////////////////////////////////////////////////////////////////////////////
HRESULT GetText(IXMLDOMNode* pNode, BSTR* pbstrText)
{
//USES_IU_CONVERSION;
HRESULT hr = E_FAIL;
QuitIfNull(pbstrText);
*pbstrText = NULL;
QuitIfNull(pNode);
DOMNodeType nNodeType;
IXMLDOMNode* pNodeText = NULL;
QuitIfFail(pNode->get_firstChild(&pNodeText));
if (NULL == pNodeText) goto CleanUp;
QuitIfFail(pNodeText->get_nodeType(&nNodeType));
if (NODE_TEXT == nNodeType)
{
QuitIfFail(pNodeText->get_text(pbstrText));
}
else
{
hr = E_UNEXPECTED;
}
CleanUp:
SafeRelease(pNodeText);
return hr;
}
/////////////////////////////////////////////////////////////////////////////
// SetValue()
//
// Set value (integer) for the xml node
/////////////////////////////////////////////////////////////////////////////
HRESULT SetValue(IXMLDOMNode* pNode, INT iValue)
{
HRESULT hr = S_OK;
QuitIfNull(pNode);
VARIANT vValue;
VariantInit(&vValue);
vValue.vt = VT_INT;
vValue.intVal = iValue;
return (pNode->put_nodeValue(vValue));
}
/////////////////////////////////////////////////////////////////////////////
// SetValue()
//
// Set value (BSTR) for the xml node
/////////////////////////////////////////////////////////////////////////////
HRESULT SetValue(IXMLDOMNode* pNode, BSTR bstrValue)
{
HRESULT hr = S_OK;
QuitIfNull(pNode);
VARIANT vValue;
VariantInit(&vValue);
vValue.vt = VT_BSTR;
vValue.bstrVal = bstrValue;
return (pNode->put_nodeValue(vValue));
}
/////////////////////////////////////////////////////////////////////////////
// InsertNode()
//
// Insert a child node to the parent node
/////////////////////////////////////////////////////////////////////////////
HRESULT InsertNode(IXMLDOMNode* pParentNode, IXMLDOMNode* pChildNode, IXMLDOMNode* pChildNodeRef /*= NULL*/)
{
HRESULT hr = S_OK;
QuitIfNull(pParentNode);
QuitIfNull(pChildNode);
IXMLDOMNode *p = NULL;
if (NULL != pChildNodeRef) // insert before the ref child node
{
VARIANT vChildNodeRef;
VariantInit(&vChildNodeRef);
vChildNodeRef.vt = VT_UNKNOWN;
vChildNodeRef.punkVal = pChildNodeRef;
QuitIfFail(pParentNode->insertBefore(pChildNode, vChildNodeRef, &p));
}
else // append to the child list
{
VARIANT vEmpty;
VariantInit(&vEmpty);
vEmpty.vt = VT_EMPTY;
QuitIfFail(pParentNode->insertBefore(pChildNode, vEmpty, &p));
}
CleanUp:
SafeRelease(p);
return hr;
}
/////////////////////////////////////////////////////////////////////////////
// CopyNode()
//
// Create an xml node as a copy of the given node;
// this is different from cloneNode() as it copies node across xml document
/////////////////////////////////////////////////////////////////////////////
HRESULT CopyNode(IXMLDOMNode* pNodeSrc, IXMLDOMDocument* pDocDes, IXMLDOMNode** ppNodeDes)
{
HRESULT hr = S_OK;
BSTR bstrNodeName = NULL;
BSTR bstrText = NULL;
BSTR bstrAttrName = NULL;
IXMLDOMNode *pChild = NULL;
IXMLDOMNamedNodeMap *pAttrs = NULL;
LOG_Block("CopyNode()");
QuitIfNull(ppNodeDes);
*ppNodeDes = NULL;
QuitIfNull(pNodeSrc);
QuitIfNull(pDocDes);
DOMNodeType nNodeType;
CleanUpIfFailedAndSetHrMsg(pNodeSrc->get_nodeType(&nNodeType));
switch (nNodeType)
{
case NODE_TEXT:
{
CleanUpFailedAllocSetHrMsg(*ppNodeDes = CreateDOMNode(pDocDes, NODE_TEXT, NULL));
CleanUpIfFailedAndSetHrMsg(pNodeSrc->get_text(&bstrText));
CleanUpIfFailedAndSetHrMsg(SetValue(*ppNodeDes, bstrText));
break;
}
case NODE_ELEMENT:
{
CleanUpIfFailedAndSetHrMsg(pNodeSrc->get_nodeName(&bstrNodeName));
CleanUpFailedAllocSetHrMsg(*ppNodeDes = CreateDOMNode(pDocDes, NODE_ELEMENT, bstrNodeName));
if (SUCCEEDED(pNodeSrc->get_attributes(&pAttrs)) && (NULL != pAttrs))
{
pAttrs->nextNode(&pChild);
while (pChild)
{
CleanUpIfFailedAndSetHrMsg(pChild->get_nodeName(&bstrAttrName));
VARIANT vAttrValue;
CleanUpIfFailedAndSetHrMsg(pChild->get_nodeValue(&vAttrValue));
hr = SetAttribute(*ppNodeDes, bstrAttrName, vAttrValue);
VariantClear(&vAttrValue);
CleanUpIfFailedAndMsg(hr);
SafeSysFreeString(bstrAttrName);
SafeReleaseNULL(pChild);
pAttrs->nextNode(&pChild);
}
pAttrs->Release();
pAttrs = NULL;
}
pNodeSrc->get_firstChild(&pChild);
while (pChild)
{
IXMLDOMNode *pChildDes = NULL;
CleanUpIfFailedAndSetHrMsg(CopyNode(pChild, pDocDes, &pChildDes));
hr = InsertNode(*ppNodeDes, pChildDes);
SafeRelease(pChildDes);
CleanUpIfFailedAndMsg(hr);
IXMLDOMNode *pNext = NULL;
CleanUpIfFailedAndMsg(pChild->get_nextSibling(&pNext));
pChild->Release();
pChild = pNext;
}
hr = S_OK;
break;
}
default:
//
// for now, do nothing for other node types
//
;
}
CleanUp:
if (FAILED(hr))
{
SafeReleaseNULL(*ppNodeDes);
}
SysFreeString(bstrNodeName);
SysFreeString(bstrText);
SysFreeString(bstrAttrName);
SafeRelease(pChild);
SafeRelease(pAttrs);
return hr;
}
/////////////////////////////////////////////////////////////////////////////
// AreNodesEqual()
//
// Return TRUE if two nodes are identical, return FALSE if function failed or
// if they're different (including order of attributes).
/////////////////////////////////////////////////////////////////////////////
BOOL AreNodesEqual(IXMLDOMNode* pNode1, IXMLDOMNode* pNode2)
{
if (pNode1 == pNode2)
{
return TRUE;
}
if ((NULL == pNode1) || (NULL == pNode2))
{
return FALSE;
}
BOOL fResult = FALSE;
BOOL fSkipAttribute = FALSE;
BOOL fSkipChildNode = FALSE;
LONG lenAttr1= -1 , lenAttr2= -1;
LONG lenNode1= -1 , lenNode2= -1;
DOMNodeType nNodeType1, nNodeType2;
BSTR bstrText1 = NULL, bstrText2 = NULL;
BSTR bstrNodeName1 = NULL, bstrNodeName2 = NULL;
BSTR bstrAttrName1 = NULL, bstrAttrName2 = NULL;
IXMLDOMNodeList *pChildNodes1 = NULL, *pChildNodes2 = NULL;
IXMLDOMNode *pChild1= NULL, *pNext1 = NULL;
IXMLDOMNode *pChild2= NULL, *pNext2 = NULL;
IXMLDOMNamedNodeMap *pAttrs1 = NULL, *pAttrs2 = NULL;
VARIANT vAttrValue1, vAttrValue2;
VariantInit(&vAttrValue1);
VariantInit(&vAttrValue2);
if (FAILED(pNode1->get_nodeType(&nNodeType1)) ||
FAILED(pNode2->get_nodeType(&nNodeType2)) ||
(nNodeType1 != nNodeType2))
{
goto CleanUp;
}
switch (nNodeType1)
{
case NODE_TEXT:
{
if (FAILED(pNode1->get_text(&bstrText1)) ||
FAILED(pNode2->get_text(&bstrText2)) ||
!CompareBSTRsEqual(bstrText1, bstrText2))
{
goto CleanUp;
}
break;
}
case NODE_ELEMENT:
{
if (FAILED(pNode1->get_nodeName(&bstrNodeName1)) ||
FAILED(pNode2->get_nodeName(&bstrNodeName2)) ||
!CompareBSTRsEqual(bstrNodeName1, bstrNodeName2))
{
goto CleanUp;
}
//
// 1. compare number of attributes
//
if (FAILED(pNode1->get_attributes(&pAttrs1)) ||
FAILED(pNode2->get_attributes(&pAttrs2)))
{
// this shouldn't happen, but...
goto CleanUp;
}
if ((NULL != pAttrs1) && (NULL != pAttrs2))
{
if (FAILED(pAttrs1->get_length(&lenAttr1)) ||
FAILED(pAttrs2->get_length(&lenAttr2)) ||
(abs(lenAttr1-lenAttr2) > 1))
{
// known bug in MSXML3.dll: xmlns="" could be one of the attribute
goto CleanUp;
}
}
else if (pAttrs1 == pAttrs2)
{
// pAttrs1 and pAttrs2 are both NULL,
// set flag to ingore comparison of each individual attribute,
// go ahead compare the number of child nodes
fSkipAttribute = TRUE;
}
else
{
// one of pAttrs1 and pAttrs2 is NULL, the nodes are obviously different
goto CleanUp;
}
//
// 2. compare number of child nodes
//
if (FAILED(pNode1->get_childNodes(&pChildNodes1)) ||
FAILED(pNode2->get_childNodes(&pChildNodes2)))
{
// this shouldn't happen, but...
goto CleanUp;
}
if ((NULL != pChildNodes1) && (NULL != pChildNodes2))
{
if (FAILED(pChildNodes1->get_length(&lenNode1)) ||
FAILED(pChildNodes2->get_length(&lenNode2)) ||
(lenNode1 != lenNode2))
{
goto CleanUp;
}
}
else if (pChildNodes1 == pChildNodes2)
{
// pChildNodes1 and pChildNodes2 are both NULL,
// set flag to ingore comparison of each individual child node,
// go ahead compare each attribute in next step
fSkipChildNode = TRUE;
}
else
{
// one of pChildNodes1 and pChildNodes2 is NULL, the nodes are obviously different
goto CleanUp;
}
//
// 3. compare each attribute
//
if (!fSkipAttribute)
{
pAttrs1->nextNode(&pChild1);
pAttrs2->nextNode(&pChild2);
while (pChild1 && pChild2)
{
if (NULL == bstrAttrName1)
{
if (FAILED(pChild1->get_nodeName(&bstrAttrName1)))
{
goto CleanUp;
}
}
if (NULL == bstrAttrName2)
{
if (FAILED(pChild2->get_nodeName(&bstrAttrName2)))
{
goto CleanUp;
}
}
if (!CompareBSTRsEqual(bstrAttrName1, bstrAttrName2))
{
if (CompareBSTRsEqual(bstrAttrName1, KEY_XML_NAMESPACE) && lenAttr1 == lenAttr2+1)
{
// ignore xmlns=""
SafeSysFreeString(bstrAttrName1);
pChild1->Release();
pAttrs1->nextNode(&pChild1);
continue;
}
else if (CompareBSTRsEqual(bstrAttrName2, KEY_XML_NAMESPACE) && lenAttr1 == lenAttr2-1)
{
// ignore xmlns=""
SafeSysFreeString(bstrAttrName2);
pChild2->Release();
pAttrs2->nextNode(&pChild2);
continue;
}
else
{
goto CleanUp;
}
}
else
{
VariantInit(&vAttrValue1);
VariantInit(&vAttrValue2);
if (FAILED(pChild1->get_nodeValue(&vAttrValue1)) ||
FAILED(pChild2->get_nodeValue(&vAttrValue2)) ||
(vAttrValue1.vt != vAttrValue2.vt))
{
goto CleanUp;
}
switch (vAttrValue1.vt)
{
case VT_INT: // integer
{
if (vAttrValue1.intVal != vAttrValue2.intVal)
{
goto CleanUp;
}
break;
}
case VT_I2: // short
{
if (vAttrValue1.iVal != vAttrValue2.iVal)
{
goto CleanUp;
}
break;
}
case VT_I4: // long
{
if (vAttrValue1.lVal != vAttrValue2.lVal)
{
goto CleanUp;
}
break;
}
case VT_BOOL: // bool
{
if (vAttrValue1.boolVal != vAttrValue2.boolVal)
{
goto CleanUp;
}
break;
}
case VT_BSTR: // BSTR
{
if (!CompareBSTRsEqual(vAttrValue1.bstrVal, vAttrValue2.bstrVal))
{
goto CleanUp;
}
break;
}
default:
//
// for now, do nothing for other attribute types
//
;
}
SafeSysFreeString(bstrAttrName1);
SafeSysFreeString(bstrAttrName2);
VariantClear(&vAttrValue1);
VariantClear(&vAttrValue2);
pChild1->Release();
pChild2->Release();
pAttrs1->nextNode(&pChild1);
pAttrs2->nextNode(&pChild2);
}
}
if (pChild1 != pChild2)
{
if (NULL == pChild1)
{
// this is the case that we looped through all the attributes in the
// first node but we still found attribute left in the second node;
// if it's xmlns="", that's ok; otherwise these two nodes are different.
if (FAILED(pChild2->get_nodeName(&bstrAttrName2)) ||
(!CompareBSTRsEqual(bstrAttrName2, KEY_XML_NAMESPACE)))
{
goto CleanUp;
}
}
else
{
if (FAILED(pChild1->get_nodeName(&bstrAttrName1)) ||
(!CompareBSTRsEqual(bstrAttrName1, KEY_XML_NAMESPACE)))
{
goto CleanUp;
}
}
}
}
//
// 4. compare each child node
//
if (!fSkipChildNode)
{
pNode1->get_firstChild(&pChild1);
pNode2->get_firstChild(&pChild2);
while (pChild1)
{
if (!pChild2)
{
goto CleanUp;
}
if (!AreNodesEqual(pChild1, pChild2))
{
goto CleanUp;
}
pChild1->get_nextSibling(&pNext1);
pChild2->get_nextSibling(&pNext2);
pChild1->Release();
pChild2->Release();
pChild1 = pNext1;
pChild2 = pNext2;
}
}
break;
}
default:
//
// for now, do nothing for other node types
//
;
}
fResult = TRUE;
CleanUp:
SafeSysFreeString(bstrText1);
SafeSysFreeString(bstrText2);
SafeSysFreeString(bstrNodeName1);
SafeSysFreeString(bstrNodeName2);
SafeSysFreeString(bstrAttrName1);
SafeSysFreeString(bstrAttrName2);
SafeRelease(pChildNodes1);
SafeRelease(pChildNodes2);
SafeRelease(pChild1);
SafeRelease(pChild2);
SafeRelease(pAttrs1);
SafeRelease(pAttrs2);
if (vAttrValue1.vt != VT_EMPTY)
VariantClear(&vAttrValue1);
if (vAttrValue2.vt != VT_EMPTY)
VariantClear(&vAttrValue2);
return fResult;
}
/////////////////////////////////////////////////////////////////////////////
// LoadXMLDoc()
//
// Load an XML Document from string
/////////////////////////////////////////////////////////////////////////////
HRESULT LoadXMLDoc(BSTR bstrXml, IXMLDOMDocument** ppDoc, BOOL fOffline /*= TRUE*/)
{
HRESULT hr = E_FAIL;
VARIANT_BOOL fSuccess = VARIANT_FALSE, fValidate = VARIANT_FALSE;
QuitIfNull(ppDoc);
*ppDoc = NULL;
QuitIfNull(bstrXml);
hr = CoCreateInstance(CLSID_DOMDocument,
NULL,
CLSCTX_INPROC_SERVER,
IID_IXMLDOMDocument,
(void **) ppDoc);
if (FAILED(hr))
{
return hr;
}
fValidate = fOffline ? VARIANT_FALSE : VARIANT_TRUE;
//
// we don't do validation unless the reg key is set on to do so
//
if (fValidate)
{
HKEY hKey = NULL;
DWORD dwValue = 0x0;
DWORD dwSize = sizeof(dwValue);
DWORD dwType = REG_DWORD;
fValidate = VARIANT_FALSE;
if (ERROR_SUCCESS == RegOpenKey(HKEY_LOCAL_MACHINE, REGKEY_IUCTL, &hKey))
{
if (ERROR_SUCCESS == RegQueryValueEx(hKey, REGVAL_SCHEMAVALIDATION, NULL, &dwType, (LPBYTE)&dwValue, &dwSize))
{
if (REG_DWORD == dwType && sizeof(dwValue) == dwSize && 1 == dwValue)
{
fValidate = VARIANT_TRUE;
}
}
RegCloseKey(hKey);
}
}
//
// force validation on parse if not offline
//
hr = (*ppDoc)->put_validateOnParse(fValidate);
if (FAILED(hr))
{
SafeReleaseNULL(*ppDoc);
return hr;
}
//
// force resolving external definition if not offline
//
hr = (*ppDoc)->put_resolveExternals(fValidate);
if (FAILED(hr))
{
SafeReleaseNULL(*ppDoc);
return hr;
}
//
// do synchronized loading
//
hr = (*ppDoc)->put_async(VARIANT_FALSE);
if (FAILED(hr))
{
SafeReleaseNULL(*ppDoc);
return hr;
}
//
// load the XML Doc from input string
//
hr = (*ppDoc)->loadXML(bstrXml, &fSuccess);
if (FAILED(hr))
{
SafeReleaseNULL(*ppDoc);
return hr;
}
//
// S_FALSE may be returned even if load fails, but
// fSuccess will return VARIANT_FALSE if there was
// an error so we call ValidateDoc to log the error
// and get the correct HRESULT.
//
if (S_FALSE == hr || VARIANT_FALSE == fSuccess)
{
hr = ValidateDoc(*ppDoc);
if (SUCCEEDED(hr))
{
hr = E_INVALIDARG;
}
SafeReleaseNULL(*ppDoc);
}
return hr;
}
/////////////////////////////////////////////////////////////////////////////
// LoadDocument()
//
// Load an XML Document from the specified file
/////////////////////////////////////////////////////////////////////////////
HRESULT LoadDocument(BSTR bstrFilePath, IXMLDOMDocument** ppDoc, BOOL fOffline /*= TRUE*/)
{
HRESULT hr = E_FAIL;
VARIANT_BOOL fSuccess = VARIANT_FALSE, fValidate = VARIANT_FALSE;;
VARIANT vFilePath;
QuitIfNull(ppDoc);
*ppDoc = NULL;
QuitIfNull(bstrFilePath);
hr = CoCreateInstance(CLSID_DOMDocument,
NULL,
CLSCTX_INPROC_SERVER,
IID_IXMLDOMDocument,
(void **) ppDoc);
if (FAILED(hr))
{
return hr;
}
//
// do synchronized loading
//
hr = (*ppDoc)->put_async(VARIANT_FALSE);
if (FAILED(hr))
{
SafeReleaseNULL(*ppDoc);
return hr;
}
fValidate = fOffline ? VARIANT_FALSE : VARIANT_TRUE;
//
// force validation on parse if not offline
//
hr = (*ppDoc)->put_validateOnParse(fValidate);
if (FAILED(hr))
{
SafeReleaseNULL(*ppDoc);
return hr;
}
//
// force resolving external definition if not offline
//
hr = (*ppDoc)->put_resolveExternals(fValidate);
if (FAILED(hr))
{
SafeReleaseNULL(*ppDoc);
return hr;
}
//
// load the XML Doc from the given file path
//
VariantInit(&vFilePath);
vFilePath.vt = VT_BSTR;
vFilePath.bstrVal = bstrFilePath;
hr = (*ppDoc)->load(vFilePath, &fSuccess);
if (FAILED(hr))
{
SafeReleaseNULL(*ppDoc);
return hr;
}
//
// S_FALSE may be returned even if load fails, but
// fSuccess will return VARIANT_FALSE if there was
// an error so we call ValidateDoc to log the error
// and get the correct HRESULT.
//
if (VARIANT_FALSE == fSuccess)
{
hr = ValidateDoc(*ppDoc);
if (SUCCEEDED(hr))
{
hr = E_INVALIDARG;
}
SafeReleaseNULL(*ppDoc);
}
return hr;
}
/////////////////////////////////////////////////////////////////////////////
// SaveDocument()
//
// Save an XML Document to the specified location
/////////////////////////////////////////////////////////////////////////////
HRESULT SaveDocument(IXMLDOMDocument* pDoc, BSTR bstrFilePath)
{
HRESULT hr = E_FAIL;
QuitIfNull(pDoc);
QuitIfNull(bstrFilePath);
//
// save the XML Doc to the given location
//
VARIANT vFilePath;
VariantInit(&vFilePath);
vFilePath.vt = VT_BSTR;
vFilePath.bstrVal = bstrFilePath;
hr = pDoc->save(vFilePath);
return hr;
}
/////////////////////////////////////////////////////////////////////////////
// ReportParseError()
//
// Report parsing error information
/////////////////////////////////////////////////////////////////////////////
HRESULT ReportParseError(IXMLDOMParseError *pXMLError)
{
USES_IU_CONVERSION;
HRESULT hr = S_OK;
LONG lLine, lLinePos, lErrCode;
BSTR bstrErrText = NULL, bstrReason = NULL;
QuitIfNull(pXMLError);
QuitIfFail(pXMLError->get_errorCode(&lErrCode));
hr = lErrCode;
QuitIfFail(pXMLError->get_line(&lLine));
QuitIfFail(pXMLError->get_linepos(&lLinePos));
QuitIfFail(pXMLError->get_srcText(&bstrErrText));
QuitIfFail(pXMLError->get_reason(&bstrReason));
if (lLine > 0)
{
LOG_Block("ReportParseError()");
LOG_Error(_T("XML line %ld, pos %ld error 0x%08x: %s)"),
lLine,
lLinePos,
lErrCode,
OLE2T(bstrReason));
LOG_Error(_T("XML starts: %s"), OLE2T(bstrErrText));
#if defined(_UNICODE) || defined(UNICODE)
LogError(lErrCode, "loadXML: line %ld, pos %ld, %S",
lLine,
lLinePos,
bstrReason);
LogMessage("%S", bstrErrText);
#else
LogError(lErrCode, "loadXML: line %ld, pos %ld, %s",
lLine,
lLinePos,
bstrReason);
LogMessage("%s", bstrErrText);
#endif
/*
//
// We want to ping this error even though we don't have the
// client information. This most likely indicates a server
// content error.
//
CUrlLog pingSvr;
#define MAX_XML_PING_MSG 512
TCHAR szMsg[MAX_XML_PING_MSG];
lstrcpyn(szMsg, OLE2T(bstrErrText), MAX_XML_PING_MSG);
pingSvr.Ping(
FALSE, // on-line (we don't know, so be safe)
URLLOGDESTINATION_DEFAULT, //fixcode: should depend of client and corp WU settings
NULL, // pt to cancel events
0, // number of events
URLLOGACTIVITY_Detection, // activity
URLLOGSTATUS_Failed, // status code
lErrCode, // error code
NULL, // itemID
NULL, // device data
szMsg // first MAX_XML_PING_MSG chars of XML for context
);
*/
}
CleanUp:
SysFreeString(bstrErrText);
SysFreeString(bstrReason);
return hr;
}
/////////////////////////////////////////////////////////////////////////////
// ValidateDoc()
//
// Validate the xml doc against the schema
/////////////////////////////////////////////////////////////////////////////
HRESULT ValidateDoc(IXMLDOMDocument* pDoc)
{
HRESULT hr = S_OK;
QuitIfNull(pDoc);
LONG lErrCode = 0;
IXMLDOMParseError *pXMLError = NULL;
QuitIfFail(pDoc->get_parseError(&pXMLError));
QuitIfFail(pXMLError->get_errorCode(&lErrCode));
if (lErrCode != 0)
{
hr = ReportParseError(pXMLError);
}
else
{
//
// no error, so hr = S_FALSE. reset it --- charlma 1/17/01
//
hr = S_OK;
}
CleanUp:
SafeRelease(pXMLError);
return hr;
}
//----------------------------------------------------------------------
//
// Helper function FindNode()
// retrieve the named node
//
// Input:
// an IXMLDomNode and a bstr name
//
// Return:
// BOOL, tells succeed or not
//
// Assumption:
// input parameter not NULL
// in case of fail, variant not touched
//
//----------------------------------------------------------------------
BOOL
FindNode(
IXMLDOMNode* pCurrentNode,
BSTR bstrName,
IXMLDOMNode** ppFoundNode
)
{
BSTR bstrTag = NULL;
LONG lLength = 0L;
IXMLDOMNode* pChild = NULL;
IXMLDOMNode* pNextChild = NULL;
if (NULL == pCurrentNode ||
NULL == bstrName ||
NULL == ppFoundNode)
{
return FALSE;
}
*ppFoundNode = NULL;
if (S_OK == pCurrentNode->selectSingleNode(bstrName, &pChild))
{
*ppFoundNode = pChild;
return TRUE;
}
else
{
return FALSE;
}
}
//----------------------------------------------------------------------
//
// Helper function FindNodeValue()
// retrieve the named data from child of the current node,
//
// Input:
// an IXMLDomNode
//
// Return:
// BOOL, tells succeed or not
//
// Assumption:
// input parameter not NULL
// in case of fail, variant not touched
//
//----------------------------------------------------------------------
BOOL
FindNodeValue(
IXMLDOMNode* pCurrentNode,
BSTR bstrName,
BSTR* pbstrValue)
{
IXMLDOMNode* pChild = NULL;
if (NULL == pbstrValue)
{
return FALSE;
}
*pbstrValue = NULL;
if (FindNode(pCurrentNode, bstrName, &pChild))
{
pChild->get_text(pbstrValue);
SafeRelease(pChild);
return TRUE;
}
return FALSE;
}
//----------------------------------------------------------------------
//
// public function Get3IdentiStrFromIdentNode()
// retrieve the name, publisherName and GUID from an identity node
//
// Return:
// HREUSLT - error code
//
//----------------------------------------------------------------------
HRESULT Get3IdentiStrFromIdentNode(IXMLDOMNode* pIdentityNode, BSTR* pbstrName, BSTR* pbstrPublisherName, BSTR* pbstrGUID)
{
HRESULT hr = E_FAIL;
BOOL fPublisherNameExist = FALSE, fGUIDExist = FALSE;
LOG_Block("Get3IdentiStrFromIdentNode()");
if (NULL == pIdentityNode || NULL == pbstrName || NULL == pbstrPublisherName || NULL == pbstrGUID)
{
return E_INVALIDARG;
}
*pbstrName = NULL;
*pbstrPublisherName = NULL;
*pbstrGUID = NULL;
//
// get name attr
//
hr = GetAttribute(pIdentityNode, KEY_NAME, pbstrName);
CleanUpIfFailedAndMsg(hr);
//
// try to get publisherName
//
fPublisherNameExist = FindNodeValue(pIdentityNode, KEY_PUBLISHERNAME, pbstrPublisherName);
fGUIDExist = FindNodeValue(pIdentityNode, KEY_GUID, pbstrGUID);
hr = (fPublisherNameExist || fGUIDExist) ? S_OK : E_FAIL;
CleanUp:
if (FAILED(hr))
{
SysFreeString(*pbstrName);
SysFreeString(*pbstrPublisherName);
SysFreeString(*pbstrGUID);
*pbstrName = NULL;
*pbstrPublisherName = NULL;
*pbstrGUID = NULL;
}
return hr;
}
/////////////////////////////////////////////////////////////////////////////
// MakeUniqNameString()
//
// This is a utility function to construct the identity name string
// based on name|publiser|GUID and the rule to make this name string.
//
// This function defines the logic about what components can be used
// to define the uniqueness of an item based on the 3 parts of data from
// GetIdentity().
//
/////////////////////////////////////////////////////////////////////////////
HRESULT MakeUniqNameString(
BSTR bstrName,
BSTR bstrPublisher,
BSTR bstrGUID,
BSTR* pbstrUniqIdentifierString)
{
LPWSTR pszResult = NULL;
DWORD dwLen=0;
HRESULT hr=S_OK;
if (NULL == bstrName || SysStringLen(bstrName) == 0 || NULL == pbstrUniqIdentifierString)
{
return E_INVALIDARG;
}
*pbstrUniqIdentifierString = NULL;
if (NULL != bstrPublisher && SysStringLen(bstrPublisher) > 0)
{
//
// if we have publisherName, we expect it is
// reverse DNS name (e.g., com.microsoft), and Name is
// the reverse DNS name (e.g., windowsupdate.autoupdate.client)
// inside that publisher. We combine them with a dot (.)
//
// Length of Publisher + Length of Name + 1 for the dot + 1 for null
dwLen=(SysStringLen(bstrPublisher) + SysStringLen(bstrName) + 2);
pszResult = (LPWSTR) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwLen * sizeof(WCHAR));
if (NULL == pszResult)
{
return E_OUTOFMEMORY;
}
//
// since we need to work on Win9x too, so we can not use Win32 API
// for UNICODE, and have to use shlwapi verison
//
hr=StringCchCopyExW(pszResult,dwLen,bstrPublisher,NULL,NULL,MISTSAFE_STRING_FLAGS);
if(FAILED(hr))
{
SafeHeapFree(pszResult);
return hr;
}
hr=StringCchCatExW(pszResult,dwLen,L".",NULL,NULL,MISTSAFE_STRING_FLAGS);
if(FAILED(hr))
{
SafeHeapFree(pszResult);
return hr;
}
hr=StringCchCatExW(pszResult,dwLen,bstrName,NULL,NULL,MISTSAFE_STRING_FLAGS);
if(FAILED(hr))
{
SafeHeapFree(pszResult);
return hr;
}
*pbstrUniqIdentifierString = SysAllocString(pszResult);
SafeHeapFree(pszResult);
if (NULL == *pbstrUniqIdentifierString)
{
return E_OUTOFMEMORY;
}
}
else
{
if (NULL == bstrGUID || SysStringLen(bstrGUID) == 0)
{
return E_INVALIDARG;
}
//
// if no suitable publisherName, then we use GUID
//
*pbstrUniqIdentifierString = SysAllocString(bstrGUID);
if (NULL == *pbstrUniqIdentifierString)
{
return E_OUTOFMEMORY;
}
}
return S_OK;
}
//----------------------------------------------------------------------
//
// public function UtilGetUniqIdentityStr()
// retrieve the unique string that make this <identity> node unique
//
// Return:
// HREUSLT - error code
//
//----------------------------------------------------------------------
HRESULT
UtilGetUniqIdentityStr(
IXMLDOMNode* pIdentityNode,
BSTR* pbstrUniqIdentifierString,
DWORD dwFlag)
{
DWORD dwLen=0;
LOG_Block("UtilGetUniqIdentityStr");
IXMLDOMNode *pNodeVersion = NULL;
IXMLDOMNode *pNodeIdentity = NULL;
BSTR bstrName = NULL,
bstrPublisher = NULL,
bstrGuid = NULL,
bstrResult = NULL;
USES_IU_CONVERSION;
if (NULL == pIdentityNode || NULL == pbstrUniqIdentifierString)
{
return E_INVALIDARG;
}
//
// retrive string
//
HRESULT hr = Get3IdentiStrFromIdentNode(pIdentityNode, &bstrName, &bstrPublisher, &bstrGuid);
CleanUpIfFailedAndMsg(hr);
//
// construct string to make it unique
//
hr = MakeUniqNameString(bstrName, bstrPublisher, bstrGuid, &bstrResult);
CleanUpIfFailedAndMsg(hr);
//
// check if this identity has version node. not all have <identity> nodes have <version>
//
if (FindNode(pNodeIdentity, KEY_VERSION, &pNodeVersion) && NULL != pNodeVersion)
{
TCHAR szVersion[MAX_VERSION];
LPWSTR pszUniqueString = NULL;
hr = UtilGetVersionStr(pNodeVersion, szVersion, dwFlag);
CleanUpIfFailedAndMsg(hr);
dwLen=(SysStringLen(bstrResult) + lstrlen(szVersion) + 2);
pszUniqueString = (LPWSTR) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwLen* sizeof(WCHAR));
CleanUpFailedAllocSetHrMsg(pszUniqueString);
hr=StringCchCopyExW(pszUniqueString,dwLen,bstrResult,NULL,NULL,MISTSAFE_STRING_FLAGS);
if(FAILED(hr))
{
SafeHeapFree(pszUniqueString);
SetHrMsgAndGotoCleanUp(hr);
}
hr=StringCchCatExW(pszUniqueString,dwLen,L".",NULL,NULL,MISTSAFE_STRING_FLAGS);
if(FAILED(hr))
{
SafeHeapFree(pszUniqueString);
SetHrMsgAndGotoCleanUp(hr);
}
hr=StringCchCatExW(pszUniqueString,dwLen,T2W(szVersion),NULL,NULL,MISTSAFE_STRING_FLAGS);
if(FAILED(hr))
{
SafeHeapFree(pszUniqueString);
SetHrMsgAndGotoCleanUp(hr);
}
*pbstrUniqIdentifierString = SysAllocString(pszUniqueString);
SafeHeapFree(pszUniqueString);
}
else
{
*pbstrUniqIdentifierString = SysAllocString(bstrResult);
}
CleanUpFailedAllocSetHrMsg(*pbstrUniqIdentifierString);
hr = S_OK;
CleanUp:
SysFreeString(bstrName);
SysFreeString(bstrPublisher);
SysFreeString(bstrGuid);
SysFreeString(bstrResult);
SafeRelease(pNodeVersion);
SafeRelease(pNodeIdentity);
return hr;
}
//----------------------------------------------------------------------
//
// public function UtilGetPlatformStr()
// retrieve the unique string that make this <platform> node unique
//
// Return:
// HREUSLT - error code
//
//----------------------------------------------------------------------
HRESULT
UtilGetPlatformStr(
IXMLDOMNode* pNodePlatform,
BSTR* pbstrPlatform,
DWORD dwFlag)
{
HRESULT hr = E_INVALIDARG;
IXMLDOMNode* pNodeVersion = NULL;
IXMLDOMNode* pNodeSuite = NULL;
IXMLDOMNodeList* pSuiteList = NULL;
IXMLDOMElement* pElement = NULL;
TCHAR szPlatformStr[MAX_PLATFORM_STR_LEN],
szVersion[256]; // should be enough for any version
const TCHAR PART_CONNECTOR[2] = _T("_");
const HRESULT RET_OVERFLOW = HRESULT_FROM_WIN32(ERROR_BUFFER_OVERFLOW);
BSTR bstrName = NULL,
bstrProcessor = NULL,
bstrType = NULL,
bstrSuite = NULL;
long iCount = 0,
iLength = 0;
LOG_Block("UtilGetPlatformStr");
USES_IU_CONVERSION;
szPlatformStr[0] = _T('\0');
if (NULL == pNodePlatform || NULL == pbstrPlatform)
{
return E_INVALIDARG;
}
//
// get platform name
//
if (SUCCEEDED(GetAttribute(pNodePlatform, KEY_NAME, &bstrName)) &&
NULL != bstrName && SysStringLen(bstrName) > 0)
{
iLength = SysStringLen(bstrName);
CleanUpIfFalseAndSetHrMsg(iLength >= MAX_PLATFORM_STR_LEN, RET_OVERFLOW);
CleanUpIfFailedAndSetHrMsg(StringCchCatEx(szPlatformStr,ARRAYSIZE(szPlatformStr),OLE2T(bstrName),NULL,NULL,MISTSAFE_STRING_FLAGS));
}
//
// if there is a valid processor architecture, like x86 or alpha, append it
//
if (FindNodeValue(pNodePlatform, KEY_PROCESSORARCHITECTURE, &bstrProcessor) &&
NULL != bstrProcessor && SysStringLen(bstrProcessor) > 0)
{
//
// processor architector should directly append to name, without
// the connect char "_"
iLength += SysStringLen(bstrProcessor) ;
CleanUpIfFalseAndSetHrMsg(iLength >= MAX_PLATFORM_STR_LEN, RET_OVERFLOW);
CleanUpIfFailedAndSetHrMsg(StringCchCatEx(szPlatformStr,ARRAYSIZE(szPlatformStr),OLE2T(bstrProcessor),NULL,NULL,MISTSAFE_STRING_FLAGS));
}
//
// try to get version code
//
hr = (TRUE == FindNode(pNodePlatform, KEY_VERSION, &pNodeVersion)) ? S_OK : E_FAIL;
//
// if return code is not saying we don't have version node,
// then it must be an error
//
if (FAILED(hr) && HRESULT_FROM_WIN32(ERROR_NOT_FOUND) != hr)
{
LOG_ErrorMsg(hr);
goto CleanUp;
}
//
// if we have a version node, try to find the version string
//
if (SUCCEEDED(hr))
{
hr = UtilGetVersionStr(pNodeVersion, szVersion, dwFlag);
SafeReleaseNULL(pNodeVersion);
//
// if we have a version node, it better be a good one
//
CleanUpIfFailedAndMsg(hr);
iLength += lstrlen(szVersion) + 1 ;
CleanUpIfFalseAndSetHrMsg(iLength >= MAX_PLATFORM_STR_LEN, RET_OVERFLOW);
CleanUpIfFailedAndSetHrMsg(StringCchCatEx(szPlatformStr,ARRAYSIZE(szPlatformStr),PART_CONNECTOR,NULL,NULL,MISTSAFE_STRING_FLAGS));
CleanUpIfFailedAndSetHrMsg(StringCchCatEx(szPlatformStr,ARRAYSIZE(szPlatformStr),szVersion,NULL,NULL,MISTSAFE_STRING_FLAGS));
}
//
// try to get a list of suite nodes
//
if (0x0 == (dwFlag & SKIP_SUITES))
{
hr = pNodePlatform->QueryInterface(IID_IXMLDOMElement, (void**)&pElement);
CleanUpIfFailedAndMsg(hr);
hr = pElement->getElementsByTagName(KEY_SUITE, &pSuiteList);
CleanUpIfFailedAndMsg(hr);
//
// try to get the length of the list, i.e., how many suite node(s)
//
hr = pSuiteList->get_length(&iCount);
CleanUpIfFailedAndMsg(hr);
//
// loop through each suite, if any
//
pSuiteList->reset();
for (int i = 0; i < iCount; i++)
{
hr = pSuiteList->get_item(i, &pNodeSuite);
CleanUpIfFailedAndMsg(hr);
if (pNodeSuite)
{
hr = pNodeSuite->get_text(&bstrSuite);
CleanUpIfFailedAndMsg(hr);
iLength += SysStringLen(bstrSuite) + 1;
CleanUpIfFalseAndSetHrMsg(iLength >= MAX_PLATFORM_STR_LEN, RET_OVERFLOW);
CleanUpIfFailedAndSetHrMsg(StringCchCatEx(szPlatformStr,ARRAYSIZE(szPlatformStr),PART_CONNECTOR,NULL,NULL,MISTSAFE_STRING_FLAGS));
CleanUpIfFailedAndSetHrMsg(StringCchCatEx(szPlatformStr,ARRAYSIZE(szPlatformStr),OLE2T(bstrSuite),NULL,NULL,MISTSAFE_STRING_FLAGS));
pNodeSuite->Release();
pNodeSuite = NULL;
SafeSysFreeString(bstrSuite);
}
}
pSuiteList->Release();
pSuiteList = NULL;
}
//
// if we find a productType node, append its text data
//
if (FindNodeValue(pNodePlatform, KEY_PRODUCTTYPE, &bstrType) &&
NULL != bstrType && SysStringLen(bstrType) > 0)
{
iLength += SysStringLen(bstrType) + 1;
CleanUpIfFalseAndSetHrMsg(iLength >= MAX_PLATFORM_STR_LEN, RET_OVERFLOW);
CleanUpIfFailedAndSetHrMsg(StringCchCatEx(szPlatformStr,ARRAYSIZE(szPlatformStr),PART_CONNECTOR,NULL,NULL,MISTSAFE_STRING_FLAGS));
CleanUpIfFailedAndSetHrMsg(StringCchCatEx(szPlatformStr,ARRAYSIZE(szPlatformStr),OLE2T(bstrType),NULL,NULL,MISTSAFE_STRING_FLAGS));
}
*pbstrPlatform = SysAllocString(T2OLE(szPlatformStr));
LOG_XML(_T("Got platform string %s"), szPlatformStr);
hr = S_OK;
CleanUp:
SysFreeString(bstrName);
SysFreeString(bstrProcessor);
SysFreeString(bstrSuite);
SysFreeString(bstrType);
SafeRelease(pNodeVersion);
SafeRelease(pNodeSuite);
SafeRelease(pSuiteList);
SafeRelease(pElement);
return hr;
}
//----------------------------------------------------------------------
//
// public function UtilGetVersionStr()
// retrieve the data from this <version> in string format
//
// Return:
// HREUSLT - error code
//
//----------------------------------------------------------------------
HRESULT
UtilGetVersionStr(
IXMLDOMNode* pVersionNode,
LPTSTR pszVersion,
DWORD dwFlag)
{
HRESULT hr = E_INVALIDARG;
LONG iMajor = -1,
iMinor = -1,
iBuild = -1,
iSvcPackMajor = -1,
iSvcPackMinor = -1;
LOG_Block("UtilGetVersionStr()");
BSTR bstrTimestamp = NULL;
BSTR bstrVersion = NULL;
TCHAR szNumber[16]; // enough to store a positive integer
BOOL fLastChunkExists = FALSE;
USES_IU_CONVERSION;
if (NULL == pVersionNode || NULL == pszVersion)
{
return hr;
}
*pszVersion = _T('\0');
//
// a version node can contain either text version data (for binaries),
// or attribute version data (for OS). If both exist, we prefer text data
//
if (SUCCEEDED(pVersionNode->get_text(&bstrVersion)) && NULL != bstrVersion &&
SysStringLen(bstrVersion) > 0)
{
lstrcpyn(pszVersion, OLE2T(bstrVersion), MAX_VERSION);
}
else
{
if (SUCCEEDED(GetAttribute(pVersionNode, KEY_MAJOR, &iMajor)) && iMajor > 0)
{
//It's an assumption that the pszVersion will be atleast MAX_VERSION characters wide
CleanUpIfFailedAndSetHrMsg(StringCchPrintfEx(pszVersion,MAX_VERSION,NULL,NULL,MISTSAFE_STRING_FLAGS, _T("%d"),iMajor));
if (SUCCEEDED(GetAttribute(pVersionNode, KEY_MINOR, &iMinor)) && iMinor >= 0)
{
CleanUpIfFailedAndSetHrMsg(StringCchPrintfEx(szNumber,ARRAYSIZE(szNumber),NULL,NULL,MISTSAFE_STRING_FLAGS, _T(".%d"),iMinor));
CleanUpIfFailedAndSetHrMsg(StringCchCatEx(pszVersion,MAX_VERSION,szNumber,NULL,NULL,MISTSAFE_STRING_FLAGS));
if (SUCCEEDED(GetAttribute(pVersionNode, KEY_BUILD, &iBuild)) && iBuild >= 0)
{
CleanUpIfFailedAndSetHrMsg(StringCchPrintfEx(szNumber,ARRAYSIZE(szNumber),NULL,NULL,MISTSAFE_STRING_FLAGS, _T(".%d"),iBuild));
CleanUpIfFailedAndSetHrMsg(StringCchCatEx(pszVersion,MAX_VERSION,szNumber,NULL,NULL,MISTSAFE_STRING_FLAGS));
}
}
fLastChunkExists = TRUE;
}
if (0x0 == (dwFlag & SKIP_SERVICEPACK_VER) &&
SUCCEEDED(GetAttribute(pVersionNode, KEY_SERVICEPACKMAJOR, &iSvcPackMajor)) &&
iSvcPackMajor > 0)
{
if (fLastChunkExists)
{
CleanUpIfFailedAndSetHrMsg(StringCchCatEx(pszVersion,MAX_VERSION,_T(","),NULL,NULL,MISTSAFE_STRING_FLAGS));
}
CleanUpIfFailedAndSetHrMsg(StringCchPrintfEx(szNumber,ARRAYSIZE(szNumber),NULL,NULL,MISTSAFE_STRING_FLAGS, _T("%d"),iSvcPackMajor));
CleanUpIfFailedAndSetHrMsg(StringCchCatEx(pszVersion,MAX_VERSION,szNumber,NULL,NULL,MISTSAFE_STRING_FLAGS));
if (SUCCEEDED(GetAttribute(pVersionNode, KEY_SERVICEPACKMINOR, &iSvcPackMinor)) &&
iSvcPackMinor >= 0)
{
CleanUpIfFailedAndSetHrMsg(StringCchPrintfEx(szNumber,ARRAYSIZE(szNumber),NULL,NULL,MISTSAFE_STRING_FLAGS,_T(".%d"),iSvcPackMinor));
CleanUpIfFailedAndSetHrMsg(StringCchCatEx(pszVersion,MAX_VERSION,szNumber,NULL,NULL,MISTSAFE_STRING_FLAGS));
}
fLastChunkExists = TRUE;
}
else
{
fLastChunkExists = FALSE;
}
if (SUCCEEDED(GetAttribute(pVersionNode, KEY_TIMESTAMP, &bstrTimestamp)) &&
NULL != bstrTimestamp && SysStringLen(bstrTimestamp) > 0)
{
if (fLastChunkExists)
{
CleanUpIfFailedAndSetHrMsg(StringCchCatEx(pszVersion,MAX_VERSION,_T(","),NULL,NULL,MISTSAFE_STRING_FLAGS));
}
else
{
//
// if we need to append timestamp, and we didn't get service pack
// data, we want to leave extra separator "," to tell the following
// part is timestamp and service pack data missing.
//
if (*pszVersion != _T('\0'))
{
CleanUpIfFailedAndSetHrMsg(StringCchCatEx(pszVersion,MAX_VERSION,_T(",,"),NULL,NULL,MISTSAFE_STRING_FLAGS));
}
//
// if this is the first chunk we found, then no prefix needed
//
}
CleanUpIfFailedAndSetHrMsg(StringCchCatEx(pszVersion,MAX_VERSION,OLE2T(bstrTimestamp),NULL,NULL,MISTSAFE_STRING_FLAGS));
}
}
//
// if we got something, then this is a valid version node and
// we can pass back whatever we got. Otherwise we return E_INVALIDARG
//
if (*pszVersion != _T('\0'))
{
LOG_XML(_T("Got version str %s"), pszVersion);
hr = S_OK;
}
CleanUp:
SysFreeString(bstrTimestamp);
SysFreeString(bstrVersion);
return hr;
}
//-----------------------------------------------------------------------
//
// function GetFullFilePathFromFilePathNode()
//
// retrieve the full qualified file path from a filePath node
//
// Input:
// a filePath XMLDom node
// a pointer to a buffer to receive path, assumes MAX_PATH long.
//
// Return:
// HRESULT
// Found path: S_OK
// Not found path: S_FALSE, lpszFilePath is empty
// otherwise, error code
//
//
//-----------------------------------------------------------------------
HRESULT GetFullFilePathFromFilePathNode(
IXMLDOMNode* pFilePathNode,
LPTSTR lpszFilePath
)
{
HRESULT hr = S_OK;
LOG_Block("GetFullFilePathFromFilePathNode");
USES_IU_CONVERSION;
IXMLDOMNode* pRegKeyNode = NULL;
TCHAR szPath[MAX_PATH] = {_T('\0')};
LPTSTR lpszFileName = NULL;
LPTSTR lpszKey = NULL;
LPTSTR lpszValue = NULL;
LPTSTR lpszPath = NULL;
BSTR bstrName = NULL;
BSTR bstrPath = NULL;
BSTR bstrKey = NULL;
BSTR bstrValue = NULL;
BOOL fPathExists = FALSE;
UINT nReqSize = 0;
if (NULL == pFilePathNode || NULL == lpszFilePath)
{
hr = E_INVALIDARG;
LOG_ErrorMsg(hr);
goto CleanUp;
}
//
// init path buffer
//
*lpszFilePath = _T('\0');
//
// try to get name data, note: S_FALSE won't do, it means everything is
// fine but this attribute does not exist.
//
if (S_OK == (hr = GetAttribute(pFilePathNode, KEY_NAME, &bstrName)))
{
//
// found name attribute
//
lpszFileName = OLE2T(bstrName);
LOG_XML(_T(" file name=%s"), lpszFileName);
fPathExists = TRUE;
}
if (FindNode(pFilePathNode, KEY_REGKEY, &pRegKeyNode) && NULL != pRegKeyNode)
{
//
// found a reg key node
//
if (!FindNodeValue(pRegKeyNode, KEY_KEY, &bstrKey))
{
//
// key node is required!
//
hr = E_INVALIDARG;
LOG_ErrorMsg(hr);
goto CleanUp;
}
lpszKey = OLE2T(bstrKey);
LOG_XML(_T("Found key=%s"), lpszKey);
//
// get optional value name
//
if (FindNodeValue(pRegKeyNode, KEY_ENTRY, &bstrValue))
{
lpszValue = OLE2T(bstrValue);
LOG_XML(_T("found entry=%s"), lpszValue);
}
else
{
LOG_XML(_T("found no value, use default"));
}
if (GetFilePathFromReg(lpszKey, lpszValue, NULL, NULL, szPath) && _T('\0') != *szPath)
{
//
// various reason can me this call fail, such as
// reg key wrong, no access to reg key, out of memory, etc
//
fPathExists = TRUE;
}
}
if (FindNodeValue(pFilePathNode, KEY_PATH, &bstrPath) && SysStringLen(bstrPath) > 0)
{
//
// found path element
//
lpszPath = OLE2T(bstrPath);
fPathExists = TRUE;
}
if (!fPathExists)
{
//
// nothing exist
//
lpszFilePath[0] = _T('\0');
LOG_XML(_T("empty node!"));
hr = S_FALSE;
goto CleanUp;
}
nReqSize = lstrlen(szPath) + SysStringLen(bstrPath) + SysStringLen(bstrName);
if (nReqSize >= MAX_PATH ||
NULL != lpszPath && FAILED(PathCchAppend(szPath,MAX_PATH,lpszPath)) || // append path to reg path
NULL != lpszFileName && FAILED(PathCchAppend(szPath,MAX_PATH,lpszFileName))) // append name
{
LOG_ErrorMsg(ERROR_BUFFER_OVERFLOW);
hr = HRESULT_FROM_WIN32(ERROR_BUFFER_OVERFLOW);
goto CleanUp;
}
if (FAILED (hr = ExpandFilePath(szPath, lpszFilePath, MAX_PATH)))
{
LOG_ErrorMsg(hr);
goto CleanUp;
}
CleanUp:
SysFreeString(bstrName);
SysFreeString(bstrPath);
SysFreeString(bstrKey);
SysFreeString(bstrValue);
SafeRelease(pRegKeyNode);
return hr;
}
HRESULT GetBstrFullFilePathFromFilePathNode(
IXMLDOMNode* pFilePathNode,
BSTR* pbstrFilePath
)
{
HRESULT hr = S_OK;
USES_IU_CONVERSION;
TCHAR szPath[MAX_PATH];
QuitIfNull(pbstrFilePath);
*pbstrFilePath = NULL;
if (SUCCEEDED(hr = GetFullFilePathFromFilePathNode(pFilePathNode, szPath)))
{
*pbstrFilePath = SysAllocString(T2OLE(szPath));
}
return hr;
}
/////////////////////////////////////////////////////////////////////////////
//
// Helper function DoesNodeHaveName()
//
// find out the the current node has a matching name
//
// Input:
// a node
//
// Return:
// TRUE/FALSE
//
/////////////////////////////////////////////////////////////////////////////
BOOL DoesNodeHaveName(IXMLDOMNode* pNode, BSTR bstrTagName)
{
BSTR bstrName;
BOOL fRet = FALSE;
IXMLDOMElement* pElement = NULL;
if (NULL == pNode)
{
return fRet;
}
if (FAILED(pNode->QueryInterface(IID_IXMLDOMElement, (void**) &pElement)) || NULL == pElement)
{
return FALSE;
}
if (SUCCEEDED(pElement->get_nodeName(&bstrName)))
{
fRet = CompareBSTRsEqual(bstrName, bstrTagName);
}
SysFreeString(bstrName);
SafeReleaseNULL(pElement);
return fRet;
}