//======================================================================= // // 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 #include #include //#include "iu.h" #include #include "schemamisc.h" #include #include "regutil.h" #include "fileutil.h" #include "stringutil.h" #include // pathappend() api #include "schemakeys.h" #include #include #include // // 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 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 nodes have // 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 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 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; }