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

  1. //=======================================================================
  2. //
  3. // Copyright (c) 1998-2000 Microsoft Corporation. All Rights Reserved.
  4. //
  5. // File: SchemaMisc.CPP
  6. //
  7. // Author: Charles Ma
  8. // 2000.10.27
  9. //
  10. // Description:
  11. //
  12. // Implement helper functions related to IU schemas
  13. //
  14. //=======================================================================
  15. //#include "iuengine.h" // PCH - must include first
  16. #include <windows.h>
  17. #include <tchar.h>
  18. #include <ole2.h>
  19. //#include "iu.h"
  20. #include <iucommon.h>
  21. #include "schemamisc.h"
  22. #include <MemUtil.h>
  23. #include "regutil.h"
  24. #include "fileutil.h"
  25. #include "stringutil.h"
  26. #include <shlwapi.h> // pathappend() api
  27. #include "schemakeys.h"
  28. #include <URLLogging.h>
  29. #include <MISTSAFE.h>
  30. #include<wusafefn.h>
  31. //
  32. // max length of platform when being converted into string
  33. // this is an artificial number that we think enough to
  34. // take any MS platform data.
  35. //
  36. const UINT MAX_PLATFORM_STR_LEN = 1024;
  37. //
  38. // private flags used by functions to retrieve string data
  39. //
  40. const DWORD SKIP_SUITES = 0x1;
  41. const DWORD SKIP_SERVICEPACK_VER = 0x2;
  42. const long MAX_VERSION = 256;
  43. const TCHAR REGKEY_IUCTL[] = _T("Software\\Microsoft\\Windows\\CurrentVersion\\WindowsUpdate\\IUControl");
  44. const TCHAR REGVAL_SCHEMAVALIDATION[] = _T("ValidateSchema");
  45. //
  46. // Global pointer gets initialized to NULL by runtime. Any module including schemamisc.h must
  47. // allocate this object following its call to CoInitialize, and delete the object before
  48. // calling CoUninitialize.
  49. //
  50. CSchemaKeys * g_pGlobalSchemaKeys /* = NULL */;
  51. #define QuitIfNull(p) {if (NULL == p) {hr = E_INVALIDARG; return hr;}}
  52. #define QuitIfFail(x) {hr = x; if (FAILED(hr)) goto CleanUp;}
  53. /////////////////////////////////////////////////////////////////////////////
  54. // FindSingleDOMNode()
  55. //
  56. // Retrieve the first xml node with the given tag name under the given parent node
  57. // Return value:
  58. // S_OK if *ppNode returns matching node value
  59. // HRESULT_FROM_WIN32(ERROR_NOT_FOUND) if node not found
  60. // FAILED() otherwise
  61. // Caller is responsible for releasing *ppNode.
  62. /////////////////////////////////////////////////////////////////////////////
  63. HRESULT FindSingleDOMNode(IXMLDOMNode* pParentNode, BSTR bstrName, IXMLDOMNode** ppNode)
  64. {
  65. HRESULT hr = S_OK;
  66. QuitIfNull(ppNode);
  67. *ppNode = NULL;
  68. QuitIfNull(pParentNode);
  69. QuitIfNull(bstrName);
  70. hr = pParentNode->selectSingleNode(bstrName, ppNode);
  71. if (S_FALSE == hr)
  72. {
  73. hr = HRESULT_FROM_WIN32(ERROR_NOT_FOUND);
  74. }
  75. if (FAILED(hr))
  76. {
  77. *ppNode = NULL;
  78. }
  79. return hr;
  80. }
  81. /////////////////////////////////////////////////////////////////////////////
  82. // FindSingleDOMNode()
  83. //
  84. // Retrieve the first xml node with the given tag name in the given xml doc
  85. // Return value:
  86. // S_OK if *ppNode returns matching node value
  87. // HRESULT_FROM_WIN32(ERROR_NOT_FOUND) if node not found
  88. // FAILED() otherwise
  89. // Caller is responsible for releasing *ppNode.
  90. /////////////////////////////////////////////////////////////////////////////
  91. HRESULT FindSingleDOMNode(IXMLDOMDocument* pDoc, BSTR bstrName, IXMLDOMNode** ppNode)
  92. {
  93. HRESULT hr = S_OK;
  94. IXMLDOMNode *pParentNode = NULL;
  95. QuitIfNull(ppNode);
  96. *ppNode = NULL;
  97. QuitIfNull(pDoc);
  98. QuitIfNull(bstrName);
  99. if (SUCCEEDED(hr = pDoc->QueryInterface(IID_IXMLDOMNode, (void**)&pParentNode)))
  100. {
  101. hr = FindSingleDOMNode(pParentNode, bstrName, ppNode);
  102. SafeRelease(pParentNode);
  103. }
  104. return hr;
  105. }
  106. /////////////////////////////////////////////////////////////////////////////
  107. // FindDOMNodeList()
  108. //
  109. // Retrieve the xml nodelist with the given tag name under the given parent node
  110. // Return value: NULL if failed or no match; matching node list otherwise.
  111. /////////////////////////////////////////////////////////////////////////////
  112. IXMLDOMNodeList* FindDOMNodeList(IXMLDOMNode* pParentNode, BSTR bstrName)
  113. {
  114. HRESULT hr = S_OK;
  115. IXMLDOMNodeList *pNodeList = NULL;
  116. LONG lLength = 0;
  117. if (NULL == pParentNode ||
  118. NULL == bstrName ||
  119. FAILED(pParentNode->selectNodes(bstrName, &pNodeList)) ||
  120. NULL == pNodeList)
  121. {
  122. return NULL;
  123. }
  124. if (SUCCEEDED(pNodeList->get_length(&lLength)) &&
  125. lLength > 0)
  126. {
  127. return pNodeList;
  128. }
  129. SafeRelease(pNodeList);
  130. return NULL;
  131. }
  132. /////////////////////////////////////////////////////////////////////////////
  133. // FindDOMNodeList()
  134. //
  135. // Retrieve the xml nodelist with the given tag name in the given xml doc
  136. // Return value: NULL if failed or no match; matching node list otherwise.
  137. /////////////////////////////////////////////////////////////////////////////
  138. IXMLDOMNodeList* FindDOMNodeList(IXMLDOMDocument* pDoc, BSTR bstrName)
  139. {
  140. IXMLDOMNode *pParentNode = NULL;
  141. IXMLDOMNodeList *pNodeList = NULL;
  142. if (NULL != pDoc &&
  143. NULL != bstrName &&
  144. SUCCEEDED(pDoc->QueryInterface(IID_IXMLDOMNode, (void**)&pParentNode)))
  145. {
  146. pNodeList = FindDOMNodeList(pParentNode, bstrName);
  147. pParentNode->Release();
  148. }
  149. return pNodeList;
  150. }
  151. /////////////////////////////////////////////////////////////////////////////
  152. // CreateDOMNode()
  153. //
  154. // Create an xml node of the given type
  155. /////////////////////////////////////////////////////////////////////////////
  156. IXMLDOMNode* CreateDOMNode(IXMLDOMDocument* pDoc, SHORT nType, BSTR bstrName, BSTR bstrNamespaceURI /*= NULL*/)
  157. {
  158. if (NULL == pDoc ||
  159. (NODE_TEXT != nType && NULL == bstrName))
  160. {
  161. return NULL;
  162. }
  163. IXMLDOMNode *pNode = NULL;
  164. VARIANT vType;
  165. VariantInit(&vType);
  166. vType.vt = VT_I2;
  167. vType.iVal = nType;
  168. if (S_OK != pDoc->createNode(vType, bstrName, bstrNamespaceURI, &pNode))
  169. {
  170. return NULL;
  171. }
  172. return pNode;
  173. }
  174. /////////////////////////////////////////////////////////////////////////////
  175. // GetAttribute()
  176. //
  177. // Get attribute (integer) from the xml node
  178. // If function fails, *piAttr preserves original value.
  179. /////////////////////////////////////////////////////////////////////////////
  180. HRESULT GetAttribute(IXMLDOMNode* pNode, BSTR bstrName, INT* piAttr)
  181. {
  182. HRESULT hr = S_OK;
  183. QuitIfNull(pNode);
  184. QuitIfNull(bstrName);
  185. QuitIfNull(piAttr);
  186. VARIANT vAttr;
  187. IXMLDOMElement *pElement = NULL;
  188. IXMLDOMAttribute *pAttrNode = NULL;;
  189. QuitIfFail(pNode->QueryInterface(IID_IXMLDOMElement, (void**)&pElement));
  190. QuitIfFail(pElement->getAttributeNode(bstrName, &pAttrNode));
  191. if (NULL == pAttrNode) goto CleanUp;
  192. QuitIfFail(pAttrNode->get_value(&vAttr));
  193. if (VT_INT == vAttr.vt)
  194. {
  195. *piAttr = vAttr.intVal;
  196. }
  197. else if (VT_BSTR == vAttr.vt)
  198. {
  199. *piAttr = (INT)MyBSTR2L(vAttr.bstrVal);
  200. }
  201. else if (VT_I2 == vAttr.vt)
  202. {
  203. *piAttr = vAttr.iVal;
  204. }
  205. else
  206. {
  207. hr = E_FAIL;
  208. }
  209. VariantClear(&vAttr);
  210. CleanUp:
  211. SafeRelease(pElement);
  212. SafeRelease(pAttrNode);
  213. return hr;
  214. }
  215. /////////////////////////////////////////////////////////////////////////////
  216. // GetAttribute()
  217. //
  218. // Get attribute (long) from the xml node
  219. // If function fails, *piAttr preservers original value.
  220. /////////////////////////////////////////////////////////////////////////////
  221. HRESULT GetAttribute(IXMLDOMNode* pNode, BSTR bstrName, LONG* plAttr)
  222. {
  223. HRESULT hr = S_OK;
  224. QuitIfNull(pNode);
  225. QuitIfNull(bstrName);
  226. QuitIfNull(plAttr);
  227. VARIANT vAttr;
  228. IXMLDOMElement *pElement = NULL;
  229. IXMLDOMAttribute *pAttrNode = NULL;;
  230. QuitIfFail(pNode->QueryInterface(IID_IXMLDOMElement, (void**)&pElement));
  231. QuitIfFail(pElement->getAttributeNode(bstrName, &pAttrNode));
  232. if (NULL == pAttrNode) goto CleanUp;
  233. QuitIfFail(pAttrNode->get_value(&vAttr));
  234. if (VT_I4 == vAttr.vt)
  235. {
  236. *plAttr = vAttr.lVal;
  237. }
  238. else if (VT_BSTR == vAttr.vt)
  239. {
  240. *plAttr = MyBSTR2L(vAttr.bstrVal);
  241. }
  242. else
  243. {
  244. hr = E_FAIL;
  245. }
  246. VariantClear(&vAttr);
  247. CleanUp:
  248. SafeRelease(pElement);
  249. SafeRelease(pAttrNode);
  250. return hr;
  251. }
  252. /////////////////////////////////////////////////////////////////////////////
  253. // GetAttribute()
  254. //
  255. // Get attribute (BOOL) from the xml node
  256. // If function fails, *piAttr preservers original value.
  257. /////////////////////////////////////////////////////////////////////////////
  258. HRESULT GetAttributeBOOL(IXMLDOMNode* pNode, BSTR bstrName, BOOL * pfAttr)
  259. {
  260. HRESULT hr = S_OK;
  261. QuitIfNull(pNode);
  262. QuitIfNull(bstrName);
  263. QuitIfNull(pfAttr);
  264. VARIANT vAttr;
  265. VARIANT vAttrBool;
  266. IXMLDOMElement *pElement = NULL;
  267. IXMLDOMAttribute *pAttrNode = NULL;;
  268. QuitIfFail(pNode->QueryInterface(IID_IXMLDOMElement, (void**)&pElement));
  269. QuitIfFail(pElement->getAttributeNode(bstrName, &pAttrNode));
  270. if (NULL == pAttrNode) goto CleanUp;
  271. QuitIfFail(pAttrNode->get_value(&vAttr));
  272. QuitIfFail(VariantChangeType(&vAttr, &vAttrBool, 0, VT_BOOL));
  273. VariantClear(&vAttr);
  274. *pfAttr = (VARIANT_TRUE == vAttrBool.boolVal) ? TRUE : FALSE;
  275. CleanUp:
  276. SafeRelease(pElement);
  277. SafeRelease(pAttrNode);
  278. return hr;
  279. }
  280. /////////////////////////////////////////////////////////////////////////////
  281. // GetAttribute()
  282. //
  283. // Get attribute (BSTR) from the xml node
  284. /////////////////////////////////////////////////////////////////////////////
  285. HRESULT GetAttribute(IXMLDOMNode* pNode, BSTR bstrName, BSTR* pbstrAttr)
  286. {
  287. HRESULT hr = S_OK;
  288. QuitIfNull(pbstrAttr);
  289. *pbstrAttr = NULL;
  290. QuitIfNull(pNode);
  291. QuitIfNull(bstrName);
  292. VARIANT vAttr;
  293. IXMLDOMElement *pElement = NULL;
  294. IXMLDOMAttribute *pAttrNode = NULL;;
  295. QuitIfFail(pNode->QueryInterface(IID_IXMLDOMElement, (void**)&pElement));
  296. QuitIfFail(pElement->getAttributeNode(bstrName, &pAttrNode));
  297. if (NULL == pAttrNode) goto CleanUp;
  298. QuitIfFail(pAttrNode->get_value(&vAttr));
  299. if (VT_BSTR == vAttr.vt)
  300. {
  301. *pbstrAttr = SysAllocString(vAttr.bstrVal);
  302. }
  303. else
  304. {
  305. hr = E_FAIL;
  306. }
  307. VariantClear(&vAttr);
  308. CleanUp:
  309. SafeRelease(pElement);
  310. SafeRelease(pAttrNode);
  311. return hr;
  312. }
  313. /////////////////////////////////////////////////////////////////////////////
  314. // SetAttribute()
  315. //
  316. // Set attribute (integer) to the xml element
  317. /////////////////////////////////////////////////////////////////////////////
  318. HRESULT SetAttribute(IXMLDOMNode* pNode, BSTR bstrName, INT iAttr)
  319. {
  320. VARIANT vAttr;
  321. VariantInit(&vAttr);
  322. vAttr.vt = VT_INT;
  323. vAttr.intVal = iAttr;
  324. return SetAttribute(pNode, bstrName, vAttr);
  325. }
  326. /////////////////////////////////////////////////////////////////////////////
  327. // SetAttribute()
  328. //
  329. // Set attribute (BSTR) to the xml element
  330. /////////////////////////////////////////////////////////////////////////////
  331. HRESULT SetAttribute(IXMLDOMNode* pNode, BSTR bstrName, BSTR bstrAttr)
  332. {
  333. HRESULT hr = S_OK;
  334. QuitIfNull(bstrAttr);
  335. VARIANT vAttr;
  336. VariantInit(&vAttr);
  337. vAttr.vt = VT_BSTR;
  338. vAttr.bstrVal = bstrAttr;
  339. return SetAttribute(pNode, bstrName, vAttr);
  340. }
  341. /////////////////////////////////////////////////////////////////////////////
  342. // SetAttribute()
  343. //
  344. // Set attribute (VARIANT) to the xml element
  345. /////////////////////////////////////////////////////////////////////////////
  346. HRESULT SetAttribute(IXMLDOMNode* pNode, BSTR bstrName, VARIANT vAttr)
  347. {
  348. HRESULT hr = S_OK;
  349. QuitIfNull(pNode);
  350. QuitIfNull(bstrName);
  351. IXMLDOMElement *pElement = NULL;
  352. QuitIfFail(pNode->QueryInterface(IID_IXMLDOMElement, (void**)&pElement));
  353. QuitIfFail(pElement->setAttribute(bstrName, vAttr));
  354. CleanUp:
  355. SafeRelease(pElement);
  356. return hr;
  357. }
  358. /////////////////////////////////////////////////////////////////////////////
  359. // GetText()
  360. //
  361. // Get text (BSTR) from the xml node
  362. // Returns
  363. // S_OK if *pbstrText returns text of 1st child of the given node
  364. // S_FALSE if node has no child or 1st child has no text
  365. // FAILED() otherwise
  366. /////////////////////////////////////////////////////////////////////////////
  367. HRESULT GetText(IXMLDOMNode* pNode, BSTR* pbstrText)
  368. {
  369. //USES_IU_CONVERSION;
  370. HRESULT hr = E_FAIL;
  371. QuitIfNull(pbstrText);
  372. *pbstrText = NULL;
  373. QuitIfNull(pNode);
  374. DOMNodeType nNodeType;
  375. IXMLDOMNode* pNodeText = NULL;
  376. QuitIfFail(pNode->get_firstChild(&pNodeText));
  377. if (NULL == pNodeText) goto CleanUp;
  378. QuitIfFail(pNodeText->get_nodeType(&nNodeType));
  379. if (NODE_TEXT == nNodeType)
  380. {
  381. QuitIfFail(pNodeText->get_text(pbstrText));
  382. }
  383. else
  384. {
  385. hr = E_UNEXPECTED;
  386. }
  387. CleanUp:
  388. SafeRelease(pNodeText);
  389. return hr;
  390. }
  391. /////////////////////////////////////////////////////////////////////////////
  392. // SetValue()
  393. //
  394. // Set value (integer) for the xml node
  395. /////////////////////////////////////////////////////////////////////////////
  396. HRESULT SetValue(IXMLDOMNode* pNode, INT iValue)
  397. {
  398. HRESULT hr = S_OK;
  399. QuitIfNull(pNode);
  400. VARIANT vValue;
  401. VariantInit(&vValue);
  402. vValue.vt = VT_INT;
  403. vValue.intVal = iValue;
  404. return (pNode->put_nodeValue(vValue));
  405. }
  406. /////////////////////////////////////////////////////////////////////////////
  407. // SetValue()
  408. //
  409. // Set value (BSTR) for the xml node
  410. /////////////////////////////////////////////////////////////////////////////
  411. HRESULT SetValue(IXMLDOMNode* pNode, BSTR bstrValue)
  412. {
  413. HRESULT hr = S_OK;
  414. QuitIfNull(pNode);
  415. VARIANT vValue;
  416. VariantInit(&vValue);
  417. vValue.vt = VT_BSTR;
  418. vValue.bstrVal = bstrValue;
  419. return (pNode->put_nodeValue(vValue));
  420. }
  421. /////////////////////////////////////////////////////////////////////////////
  422. // InsertNode()
  423. //
  424. // Insert a child node to the parent node
  425. /////////////////////////////////////////////////////////////////////////////
  426. HRESULT InsertNode(IXMLDOMNode* pParentNode, IXMLDOMNode* pChildNode, IXMLDOMNode* pChildNodeRef /*= NULL*/)
  427. {
  428. HRESULT hr = S_OK;
  429. QuitIfNull(pParentNode);
  430. QuitIfNull(pChildNode);
  431. IXMLDOMNode *p = NULL;
  432. if (NULL != pChildNodeRef) // insert before the ref child node
  433. {
  434. VARIANT vChildNodeRef;
  435. VariantInit(&vChildNodeRef);
  436. vChildNodeRef.vt = VT_UNKNOWN;
  437. vChildNodeRef.punkVal = pChildNodeRef;
  438. QuitIfFail(pParentNode->insertBefore(pChildNode, vChildNodeRef, &p));
  439. }
  440. else // append to the child list
  441. {
  442. VARIANT vEmpty;
  443. VariantInit(&vEmpty);
  444. vEmpty.vt = VT_EMPTY;
  445. QuitIfFail(pParentNode->insertBefore(pChildNode, vEmpty, &p));
  446. }
  447. CleanUp:
  448. SafeRelease(p);
  449. return hr;
  450. }
  451. /////////////////////////////////////////////////////////////////////////////
  452. // CopyNode()
  453. //
  454. // Create an xml node as a copy of the given node;
  455. // this is different from cloneNode() as it copies node across xml document
  456. /////////////////////////////////////////////////////////////////////////////
  457. HRESULT CopyNode(IXMLDOMNode* pNodeSrc, IXMLDOMDocument* pDocDes, IXMLDOMNode** ppNodeDes)
  458. {
  459. HRESULT hr = S_OK;
  460. BSTR bstrNodeName = NULL;
  461. BSTR bstrText = NULL;
  462. BSTR bstrAttrName = NULL;
  463. IXMLDOMNode *pChild = NULL;
  464. IXMLDOMNamedNodeMap *pAttrs = NULL;
  465. LOG_Block("CopyNode()");
  466. QuitIfNull(ppNodeDes);
  467. *ppNodeDes = NULL;
  468. QuitIfNull(pNodeSrc);
  469. QuitIfNull(pDocDes);
  470. DOMNodeType nNodeType;
  471. CleanUpIfFailedAndSetHrMsg(pNodeSrc->get_nodeType(&nNodeType));
  472. switch (nNodeType)
  473. {
  474. case NODE_TEXT:
  475. {
  476. CleanUpFailedAllocSetHrMsg(*ppNodeDes = CreateDOMNode(pDocDes, NODE_TEXT, NULL));
  477. CleanUpIfFailedAndSetHrMsg(pNodeSrc->get_text(&bstrText));
  478. CleanUpIfFailedAndSetHrMsg(SetValue(*ppNodeDes, bstrText));
  479. break;
  480. }
  481. case NODE_ELEMENT:
  482. {
  483. CleanUpIfFailedAndSetHrMsg(pNodeSrc->get_nodeName(&bstrNodeName));
  484. CleanUpFailedAllocSetHrMsg(*ppNodeDes = CreateDOMNode(pDocDes, NODE_ELEMENT, bstrNodeName));
  485. if (SUCCEEDED(pNodeSrc->get_attributes(&pAttrs)) && (NULL != pAttrs))
  486. {
  487. pAttrs->nextNode(&pChild);
  488. while (pChild)
  489. {
  490. CleanUpIfFailedAndSetHrMsg(pChild->get_nodeName(&bstrAttrName));
  491. VARIANT vAttrValue;
  492. CleanUpIfFailedAndSetHrMsg(pChild->get_nodeValue(&vAttrValue));
  493. hr = SetAttribute(*ppNodeDes, bstrAttrName, vAttrValue);
  494. VariantClear(&vAttrValue);
  495. CleanUpIfFailedAndMsg(hr);
  496. SafeSysFreeString(bstrAttrName);
  497. SafeReleaseNULL(pChild);
  498. pAttrs->nextNode(&pChild);
  499. }
  500. pAttrs->Release();
  501. pAttrs = NULL;
  502. }
  503. pNodeSrc->get_firstChild(&pChild);
  504. while (pChild)
  505. {
  506. IXMLDOMNode *pChildDes = NULL;
  507. CleanUpIfFailedAndSetHrMsg(CopyNode(pChild, pDocDes, &pChildDes));
  508. hr = InsertNode(*ppNodeDes, pChildDes);
  509. SafeRelease(pChildDes);
  510. CleanUpIfFailedAndMsg(hr);
  511. IXMLDOMNode *pNext = NULL;
  512. CleanUpIfFailedAndMsg(pChild->get_nextSibling(&pNext));
  513. pChild->Release();
  514. pChild = pNext;
  515. }
  516. hr = S_OK;
  517. break;
  518. }
  519. default:
  520. //
  521. // for now, do nothing for other node types
  522. //
  523. ;
  524. }
  525. CleanUp:
  526. if (FAILED(hr))
  527. {
  528. SafeReleaseNULL(*ppNodeDes);
  529. }
  530. SysFreeString(bstrNodeName);
  531. SysFreeString(bstrText);
  532. SysFreeString(bstrAttrName);
  533. SafeRelease(pChild);
  534. SafeRelease(pAttrs);
  535. return hr;
  536. }
  537. /////////////////////////////////////////////////////////////////////////////
  538. // AreNodesEqual()
  539. //
  540. // Return TRUE if two nodes are identical, return FALSE if function failed or
  541. // if they're different (including order of attributes).
  542. /////////////////////////////////////////////////////////////////////////////
  543. BOOL AreNodesEqual(IXMLDOMNode* pNode1, IXMLDOMNode* pNode2)
  544. {
  545. if (pNode1 == pNode2)
  546. {
  547. return TRUE;
  548. }
  549. if ((NULL == pNode1) || (NULL == pNode2))
  550. {
  551. return FALSE;
  552. }
  553. BOOL fResult = FALSE;
  554. BOOL fSkipAttribute = FALSE;
  555. BOOL fSkipChildNode = FALSE;
  556. LONG lenAttr1= -1 , lenAttr2= -1;
  557. LONG lenNode1= -1 , lenNode2= -1;
  558. DOMNodeType nNodeType1, nNodeType2;
  559. BSTR bstrText1 = NULL, bstrText2 = NULL;
  560. BSTR bstrNodeName1 = NULL, bstrNodeName2 = NULL;
  561. BSTR bstrAttrName1 = NULL, bstrAttrName2 = NULL;
  562. IXMLDOMNodeList *pChildNodes1 = NULL, *pChildNodes2 = NULL;
  563. IXMLDOMNode *pChild1= NULL, *pNext1 = NULL;
  564. IXMLDOMNode *pChild2= NULL, *pNext2 = NULL;
  565. IXMLDOMNamedNodeMap *pAttrs1 = NULL, *pAttrs2 = NULL;
  566. VARIANT vAttrValue1, vAttrValue2;
  567. VariantInit(&vAttrValue1);
  568. VariantInit(&vAttrValue2);
  569. if (FAILED(pNode1->get_nodeType(&nNodeType1)) ||
  570. FAILED(pNode2->get_nodeType(&nNodeType2)) ||
  571. (nNodeType1 != nNodeType2))
  572. {
  573. goto CleanUp;
  574. }
  575. switch (nNodeType1)
  576. {
  577. case NODE_TEXT:
  578. {
  579. if (FAILED(pNode1->get_text(&bstrText1)) ||
  580. FAILED(pNode2->get_text(&bstrText2)) ||
  581. !CompareBSTRsEqual(bstrText1, bstrText2))
  582. {
  583. goto CleanUp;
  584. }
  585. break;
  586. }
  587. case NODE_ELEMENT:
  588. {
  589. if (FAILED(pNode1->get_nodeName(&bstrNodeName1)) ||
  590. FAILED(pNode2->get_nodeName(&bstrNodeName2)) ||
  591. !CompareBSTRsEqual(bstrNodeName1, bstrNodeName2))
  592. {
  593. goto CleanUp;
  594. }
  595. //
  596. // 1. compare number of attributes
  597. //
  598. if (FAILED(pNode1->get_attributes(&pAttrs1)) ||
  599. FAILED(pNode2->get_attributes(&pAttrs2)))
  600. {
  601. // this shouldn't happen, but...
  602. goto CleanUp;
  603. }
  604. if ((NULL != pAttrs1) && (NULL != pAttrs2))
  605. {
  606. if (FAILED(pAttrs1->get_length(&lenAttr1)) ||
  607. FAILED(pAttrs2->get_length(&lenAttr2)) ||
  608. (abs(lenAttr1-lenAttr2) > 1))
  609. {
  610. // known bug in MSXML3.dll: xmlns="" could be one of the attribute
  611. goto CleanUp;
  612. }
  613. }
  614. else if (pAttrs1 == pAttrs2)
  615. {
  616. // pAttrs1 and pAttrs2 are both NULL,
  617. // set flag to ingore comparison of each individual attribute,
  618. // go ahead compare the number of child nodes
  619. fSkipAttribute = TRUE;
  620. }
  621. else
  622. {
  623. // one of pAttrs1 and pAttrs2 is NULL, the nodes are obviously different
  624. goto CleanUp;
  625. }
  626. //
  627. // 2. compare number of child nodes
  628. //
  629. if (FAILED(pNode1->get_childNodes(&pChildNodes1)) ||
  630. FAILED(pNode2->get_childNodes(&pChildNodes2)))
  631. {
  632. // this shouldn't happen, but...
  633. goto CleanUp;
  634. }
  635. if ((NULL != pChildNodes1) && (NULL != pChildNodes2))
  636. {
  637. if (FAILED(pChildNodes1->get_length(&lenNode1)) ||
  638. FAILED(pChildNodes2->get_length(&lenNode2)) ||
  639. (lenNode1 != lenNode2))
  640. {
  641. goto CleanUp;
  642. }
  643. }
  644. else if (pChildNodes1 == pChildNodes2)
  645. {
  646. // pChildNodes1 and pChildNodes2 are both NULL,
  647. // set flag to ingore comparison of each individual child node,
  648. // go ahead compare each attribute in next step
  649. fSkipChildNode = TRUE;
  650. }
  651. else
  652. {
  653. // one of pChildNodes1 and pChildNodes2 is NULL, the nodes are obviously different
  654. goto CleanUp;
  655. }
  656. //
  657. // 3. compare each attribute
  658. //
  659. if (!fSkipAttribute)
  660. {
  661. pAttrs1->nextNode(&pChild1);
  662. pAttrs2->nextNode(&pChild2);
  663. while (pChild1 && pChild2)
  664. {
  665. if (NULL == bstrAttrName1)
  666. {
  667. if (FAILED(pChild1->get_nodeName(&bstrAttrName1)))
  668. {
  669. goto CleanUp;
  670. }
  671. }
  672. if (NULL == bstrAttrName2)
  673. {
  674. if (FAILED(pChild2->get_nodeName(&bstrAttrName2)))
  675. {
  676. goto CleanUp;
  677. }
  678. }
  679. if (!CompareBSTRsEqual(bstrAttrName1, bstrAttrName2))
  680. {
  681. if (CompareBSTRsEqual(bstrAttrName1, KEY_XML_NAMESPACE) && lenAttr1 == lenAttr2+1)
  682. {
  683. // ignore xmlns=""
  684. SafeSysFreeString(bstrAttrName1);
  685. pChild1->Release();
  686. pAttrs1->nextNode(&pChild1);
  687. continue;
  688. }
  689. else if (CompareBSTRsEqual(bstrAttrName2, KEY_XML_NAMESPACE) && lenAttr1 == lenAttr2-1)
  690. {
  691. // ignore xmlns=""
  692. SafeSysFreeString(bstrAttrName2);
  693. pChild2->Release();
  694. pAttrs2->nextNode(&pChild2);
  695. continue;
  696. }
  697. else
  698. {
  699. goto CleanUp;
  700. }
  701. }
  702. else
  703. {
  704. VariantInit(&vAttrValue1);
  705. VariantInit(&vAttrValue2);
  706. if (FAILED(pChild1->get_nodeValue(&vAttrValue1)) ||
  707. FAILED(pChild2->get_nodeValue(&vAttrValue2)) ||
  708. (vAttrValue1.vt != vAttrValue2.vt))
  709. {
  710. goto CleanUp;
  711. }
  712. switch (vAttrValue1.vt)
  713. {
  714. case VT_INT: // integer
  715. {
  716. if (vAttrValue1.intVal != vAttrValue2.intVal)
  717. {
  718. goto CleanUp;
  719. }
  720. break;
  721. }
  722. case VT_I2: // short
  723. {
  724. if (vAttrValue1.iVal != vAttrValue2.iVal)
  725. {
  726. goto CleanUp;
  727. }
  728. break;
  729. }
  730. case VT_I4: // long
  731. {
  732. if (vAttrValue1.lVal != vAttrValue2.lVal)
  733. {
  734. goto CleanUp;
  735. }
  736. break;
  737. }
  738. case VT_BOOL: // bool
  739. {
  740. if (vAttrValue1.boolVal != vAttrValue2.boolVal)
  741. {
  742. goto CleanUp;
  743. }
  744. break;
  745. }
  746. case VT_BSTR: // BSTR
  747. {
  748. if (!CompareBSTRsEqual(vAttrValue1.bstrVal, vAttrValue2.bstrVal))
  749. {
  750. goto CleanUp;
  751. }
  752. break;
  753. }
  754. default:
  755. //
  756. // for now, do nothing for other attribute types
  757. //
  758. ;
  759. }
  760. SafeSysFreeString(bstrAttrName1);
  761. SafeSysFreeString(bstrAttrName2);
  762. VariantClear(&vAttrValue1);
  763. VariantClear(&vAttrValue2);
  764. pChild1->Release();
  765. pChild2->Release();
  766. pAttrs1->nextNode(&pChild1);
  767. pAttrs2->nextNode(&pChild2);
  768. }
  769. }
  770. if (pChild1 != pChild2)
  771. {
  772. if (NULL == pChild1)
  773. {
  774. // this is the case that we looped through all the attributes in the
  775. // first node but we still found attribute left in the second node;
  776. // if it's xmlns="", that's ok; otherwise these two nodes are different.
  777. if (FAILED(pChild2->get_nodeName(&bstrAttrName2)) ||
  778. (!CompareBSTRsEqual(bstrAttrName2, KEY_XML_NAMESPACE)))
  779. {
  780. goto CleanUp;
  781. }
  782. }
  783. else
  784. {
  785. if (FAILED(pChild1->get_nodeName(&bstrAttrName1)) ||
  786. (!CompareBSTRsEqual(bstrAttrName1, KEY_XML_NAMESPACE)))
  787. {
  788. goto CleanUp;
  789. }
  790. }
  791. }
  792. }
  793. //
  794. // 4. compare each child node
  795. //
  796. if (!fSkipChildNode)
  797. {
  798. pNode1->get_firstChild(&pChild1);
  799. pNode2->get_firstChild(&pChild2);
  800. while (pChild1)
  801. {
  802. if (!pChild2)
  803. {
  804. goto CleanUp;
  805. }
  806. if (!AreNodesEqual(pChild1, pChild2))
  807. {
  808. goto CleanUp;
  809. }
  810. pChild1->get_nextSibling(&pNext1);
  811. pChild2->get_nextSibling(&pNext2);
  812. pChild1->Release();
  813. pChild2->Release();
  814. pChild1 = pNext1;
  815. pChild2 = pNext2;
  816. }
  817. }
  818. break;
  819. }
  820. default:
  821. //
  822. // for now, do nothing for other node types
  823. //
  824. ;
  825. }
  826. fResult = TRUE;
  827. CleanUp:
  828. SafeSysFreeString(bstrText1);
  829. SafeSysFreeString(bstrText2);
  830. SafeSysFreeString(bstrNodeName1);
  831. SafeSysFreeString(bstrNodeName2);
  832. SafeSysFreeString(bstrAttrName1);
  833. SafeSysFreeString(bstrAttrName2);
  834. SafeRelease(pChildNodes1);
  835. SafeRelease(pChildNodes2);
  836. SafeRelease(pChild1);
  837. SafeRelease(pChild2);
  838. SafeRelease(pAttrs1);
  839. SafeRelease(pAttrs2);
  840. if (vAttrValue1.vt != VT_EMPTY)
  841. VariantClear(&vAttrValue1);
  842. if (vAttrValue2.vt != VT_EMPTY)
  843. VariantClear(&vAttrValue2);
  844. return fResult;
  845. }
  846. /////////////////////////////////////////////////////////////////////////////
  847. // LoadXMLDoc()
  848. //
  849. // Load an XML Document from string
  850. /////////////////////////////////////////////////////////////////////////////
  851. HRESULT LoadXMLDoc(BSTR bstrXml, IXMLDOMDocument** ppDoc, BOOL fOffline /*= TRUE*/)
  852. {
  853. HRESULT hr = E_FAIL;
  854. VARIANT_BOOL fSuccess = VARIANT_FALSE, fValidate = VARIANT_FALSE;
  855. QuitIfNull(ppDoc);
  856. *ppDoc = NULL;
  857. QuitIfNull(bstrXml);
  858. hr = CoCreateInstance(CLSID_DOMDocument,
  859. NULL,
  860. CLSCTX_INPROC_SERVER,
  861. IID_IXMLDOMDocument,
  862. (void **) ppDoc);
  863. if (FAILED(hr))
  864. {
  865. return hr;
  866. }
  867. fValidate = fOffline ? VARIANT_FALSE : VARIANT_TRUE;
  868. //
  869. // we don't do validation unless the reg key is set on to do so
  870. //
  871. if (fValidate)
  872. {
  873. HKEY hKey = NULL;
  874. DWORD dwValue = 0x0;
  875. DWORD dwSize = sizeof(dwValue);
  876. DWORD dwType = REG_DWORD;
  877. fValidate = VARIANT_FALSE;
  878. if (ERROR_SUCCESS == RegOpenKey(HKEY_LOCAL_MACHINE, REGKEY_IUCTL, &hKey))
  879. {
  880. if (ERROR_SUCCESS == RegQueryValueEx(hKey, REGVAL_SCHEMAVALIDATION, NULL, &dwType, (LPBYTE)&dwValue, &dwSize))
  881. {
  882. if (REG_DWORD == dwType && sizeof(dwValue) == dwSize && 1 == dwValue)
  883. {
  884. fValidate = VARIANT_TRUE;
  885. }
  886. }
  887. RegCloseKey(hKey);
  888. }
  889. }
  890. //
  891. // force validation on parse if not offline
  892. //
  893. hr = (*ppDoc)->put_validateOnParse(fValidate);
  894. if (FAILED(hr))
  895. {
  896. SafeReleaseNULL(*ppDoc);
  897. return hr;
  898. }
  899. //
  900. // force resolving external definition if not offline
  901. //
  902. hr = (*ppDoc)->put_resolveExternals(fValidate);
  903. if (FAILED(hr))
  904. {
  905. SafeReleaseNULL(*ppDoc);
  906. return hr;
  907. }
  908. //
  909. // do synchronized loading
  910. //
  911. hr = (*ppDoc)->put_async(VARIANT_FALSE);
  912. if (FAILED(hr))
  913. {
  914. SafeReleaseNULL(*ppDoc);
  915. return hr;
  916. }
  917. //
  918. // load the XML Doc from input string
  919. //
  920. hr = (*ppDoc)->loadXML(bstrXml, &fSuccess);
  921. if (FAILED(hr))
  922. {
  923. SafeReleaseNULL(*ppDoc);
  924. return hr;
  925. }
  926. //
  927. // S_FALSE may be returned even if load fails, but
  928. // fSuccess will return VARIANT_FALSE if there was
  929. // an error so we call ValidateDoc to log the error
  930. // and get the correct HRESULT.
  931. //
  932. if (S_FALSE == hr || VARIANT_FALSE == fSuccess)
  933. {
  934. hr = ValidateDoc(*ppDoc);
  935. if (SUCCEEDED(hr))
  936. {
  937. hr = E_INVALIDARG;
  938. }
  939. SafeReleaseNULL(*ppDoc);
  940. }
  941. return hr;
  942. }
  943. /////////////////////////////////////////////////////////////////////////////
  944. // LoadDocument()
  945. //
  946. // Load an XML Document from the specified file
  947. /////////////////////////////////////////////////////////////////////////////
  948. HRESULT LoadDocument(BSTR bstrFilePath, IXMLDOMDocument** ppDoc, BOOL fOffline /*= TRUE*/)
  949. {
  950. HRESULT hr = E_FAIL;
  951. VARIANT_BOOL fSuccess = VARIANT_FALSE, fValidate = VARIANT_FALSE;;
  952. VARIANT vFilePath;
  953. QuitIfNull(ppDoc);
  954. *ppDoc = NULL;
  955. QuitIfNull(bstrFilePath);
  956. hr = CoCreateInstance(CLSID_DOMDocument,
  957. NULL,
  958. CLSCTX_INPROC_SERVER,
  959. IID_IXMLDOMDocument,
  960. (void **) ppDoc);
  961. if (FAILED(hr))
  962. {
  963. return hr;
  964. }
  965. //
  966. // do synchronized loading
  967. //
  968. hr = (*ppDoc)->put_async(VARIANT_FALSE);
  969. if (FAILED(hr))
  970. {
  971. SafeReleaseNULL(*ppDoc);
  972. return hr;
  973. }
  974. fValidate = fOffline ? VARIANT_FALSE : VARIANT_TRUE;
  975. //
  976. // force validation on parse if not offline
  977. //
  978. hr = (*ppDoc)->put_validateOnParse(fValidate);
  979. if (FAILED(hr))
  980. {
  981. SafeReleaseNULL(*ppDoc);
  982. return hr;
  983. }
  984. //
  985. // force resolving external definition if not offline
  986. //
  987. hr = (*ppDoc)->put_resolveExternals(fValidate);
  988. if (FAILED(hr))
  989. {
  990. SafeReleaseNULL(*ppDoc);
  991. return hr;
  992. }
  993. //
  994. // load the XML Doc from the given file path
  995. //
  996. VariantInit(&vFilePath);
  997. vFilePath.vt = VT_BSTR;
  998. vFilePath.bstrVal = bstrFilePath;
  999. hr = (*ppDoc)->load(vFilePath, &fSuccess);
  1000. if (FAILED(hr))
  1001. {
  1002. SafeReleaseNULL(*ppDoc);
  1003. return hr;
  1004. }
  1005. //
  1006. // S_FALSE may be returned even if load fails, but
  1007. // fSuccess will return VARIANT_FALSE if there was
  1008. // an error so we call ValidateDoc to log the error
  1009. // and get the correct HRESULT.
  1010. //
  1011. if (VARIANT_FALSE == fSuccess)
  1012. {
  1013. hr = ValidateDoc(*ppDoc);
  1014. if (SUCCEEDED(hr))
  1015. {
  1016. hr = E_INVALIDARG;
  1017. }
  1018. SafeReleaseNULL(*ppDoc);
  1019. }
  1020. return hr;
  1021. }
  1022. /////////////////////////////////////////////////////////////////////////////
  1023. // SaveDocument()
  1024. //
  1025. // Save an XML Document to the specified location
  1026. /////////////////////////////////////////////////////////////////////////////
  1027. HRESULT SaveDocument(IXMLDOMDocument* pDoc, BSTR bstrFilePath)
  1028. {
  1029. HRESULT hr = E_FAIL;
  1030. QuitIfNull(pDoc);
  1031. QuitIfNull(bstrFilePath);
  1032. //
  1033. // save the XML Doc to the given location
  1034. //
  1035. VARIANT vFilePath;
  1036. VariantInit(&vFilePath);
  1037. vFilePath.vt = VT_BSTR;
  1038. vFilePath.bstrVal = bstrFilePath;
  1039. hr = pDoc->save(vFilePath);
  1040. return hr;
  1041. }
  1042. /////////////////////////////////////////////////////////////////////////////
  1043. // ReportParseError()
  1044. //
  1045. // Report parsing error information
  1046. /////////////////////////////////////////////////////////////////////////////
  1047. HRESULT ReportParseError(IXMLDOMParseError *pXMLError)
  1048. {
  1049. USES_IU_CONVERSION;
  1050. HRESULT hr = S_OK;
  1051. LONG lLine, lLinePos, lErrCode;
  1052. BSTR bstrErrText = NULL, bstrReason = NULL;
  1053. QuitIfNull(pXMLError);
  1054. QuitIfFail(pXMLError->get_errorCode(&lErrCode));
  1055. hr = lErrCode;
  1056. QuitIfFail(pXMLError->get_line(&lLine));
  1057. QuitIfFail(pXMLError->get_linepos(&lLinePos));
  1058. QuitIfFail(pXMLError->get_srcText(&bstrErrText));
  1059. QuitIfFail(pXMLError->get_reason(&bstrReason));
  1060. if (lLine > 0)
  1061. {
  1062. LOG_Block("ReportParseError()");
  1063. LOG_Error(_T("XML line %ld, pos %ld error 0x%08x: %s)"),
  1064. lLine,
  1065. lLinePos,
  1066. lErrCode,
  1067. OLE2T(bstrReason));
  1068. LOG_Error(_T("XML starts: %s"), OLE2T(bstrErrText));
  1069. #if defined(_UNICODE) || defined(UNICODE)
  1070. LogError(lErrCode, "loadXML: line %ld, pos %ld, %S",
  1071. lLine,
  1072. lLinePos,
  1073. bstrReason);
  1074. LogMessage("%S", bstrErrText);
  1075. #else
  1076. LogError(lErrCode, "loadXML: line %ld, pos %ld, %s",
  1077. lLine,
  1078. lLinePos,
  1079. bstrReason);
  1080. LogMessage("%s", bstrErrText);
  1081. #endif
  1082. /*
  1083. //
  1084. // We want to ping this error even though we don't have the
  1085. // client information. This most likely indicates a server
  1086. // content error.
  1087. //
  1088. CUrlLog pingSvr;
  1089. #define MAX_XML_PING_MSG 512
  1090. TCHAR szMsg[MAX_XML_PING_MSG];
  1091. lstrcpyn(szMsg, OLE2T(bstrErrText), MAX_XML_PING_MSG);
  1092. pingSvr.Ping(
  1093. FALSE, // on-line (we don't know, so be safe)
  1094. URLLOGDESTINATION_DEFAULT, //fixcode: should depend of client and corp WU settings
  1095. NULL, // pt to cancel events
  1096. 0, // number of events
  1097. URLLOGACTIVITY_Detection, // activity
  1098. URLLOGSTATUS_Failed, // status code
  1099. lErrCode, // error code
  1100. NULL, // itemID
  1101. NULL, // device data
  1102. szMsg // first MAX_XML_PING_MSG chars of XML for context
  1103. );
  1104. */
  1105. }
  1106. CleanUp:
  1107. SysFreeString(bstrErrText);
  1108. SysFreeString(bstrReason);
  1109. return hr;
  1110. }
  1111. /////////////////////////////////////////////////////////////////////////////
  1112. // ValidateDoc()
  1113. //
  1114. // Validate the xml doc against the schema
  1115. /////////////////////////////////////////////////////////////////////////////
  1116. HRESULT ValidateDoc(IXMLDOMDocument* pDoc)
  1117. {
  1118. HRESULT hr = S_OK;
  1119. QuitIfNull(pDoc);
  1120. LONG lErrCode = 0;
  1121. IXMLDOMParseError *pXMLError = NULL;
  1122. QuitIfFail(pDoc->get_parseError(&pXMLError));
  1123. QuitIfFail(pXMLError->get_errorCode(&lErrCode));
  1124. if (lErrCode != 0)
  1125. {
  1126. hr = ReportParseError(pXMLError);
  1127. }
  1128. else
  1129. {
  1130. //
  1131. // no error, so hr = S_FALSE. reset it --- charlma 1/17/01
  1132. //
  1133. hr = S_OK;
  1134. }
  1135. CleanUp:
  1136. SafeRelease(pXMLError);
  1137. return hr;
  1138. }
  1139. //----------------------------------------------------------------------
  1140. //
  1141. // Helper function FindNode()
  1142. // retrieve the named node
  1143. //
  1144. // Input:
  1145. // an IXMLDomNode and a bstr name
  1146. //
  1147. // Return:
  1148. // BOOL, tells succeed or not
  1149. //
  1150. // Assumption:
  1151. // input parameter not NULL
  1152. // in case of fail, variant not touched
  1153. //
  1154. //----------------------------------------------------------------------
  1155. BOOL
  1156. FindNode(
  1157. IXMLDOMNode* pCurrentNode,
  1158. BSTR bstrName,
  1159. IXMLDOMNode** ppFoundNode
  1160. )
  1161. {
  1162. BSTR bstrTag = NULL;
  1163. LONG lLength = 0L;
  1164. IXMLDOMNode* pChild = NULL;
  1165. IXMLDOMNode* pNextChild = NULL;
  1166. if (NULL == pCurrentNode ||
  1167. NULL == bstrName ||
  1168. NULL == ppFoundNode)
  1169. {
  1170. return FALSE;
  1171. }
  1172. *ppFoundNode = NULL;
  1173. if (S_OK == pCurrentNode->selectSingleNode(bstrName, &pChild))
  1174. {
  1175. *ppFoundNode = pChild;
  1176. return TRUE;
  1177. }
  1178. else
  1179. {
  1180. return FALSE;
  1181. }
  1182. }
  1183. //----------------------------------------------------------------------
  1184. //
  1185. // Helper function FindNodeValue()
  1186. // retrieve the named data from child of the current node,
  1187. //
  1188. // Input:
  1189. // an IXMLDomNode
  1190. //
  1191. // Return:
  1192. // BOOL, tells succeed or not
  1193. //
  1194. // Assumption:
  1195. // input parameter not NULL
  1196. // in case of fail, variant not touched
  1197. //
  1198. //----------------------------------------------------------------------
  1199. BOOL
  1200. FindNodeValue(
  1201. IXMLDOMNode* pCurrentNode,
  1202. BSTR bstrName,
  1203. BSTR* pbstrValue)
  1204. {
  1205. IXMLDOMNode* pChild = NULL;
  1206. if (NULL == pbstrValue)
  1207. {
  1208. return FALSE;
  1209. }
  1210. *pbstrValue = NULL;
  1211. if (FindNode(pCurrentNode, bstrName, &pChild))
  1212. {
  1213. pChild->get_text(pbstrValue);
  1214. SafeRelease(pChild);
  1215. return TRUE;
  1216. }
  1217. return FALSE;
  1218. }
  1219. //----------------------------------------------------------------------
  1220. //
  1221. // public function Get3IdentiStrFromIdentNode()
  1222. // retrieve the name, publisherName and GUID from an identity node
  1223. //
  1224. // Return:
  1225. // HREUSLT - error code
  1226. //
  1227. //----------------------------------------------------------------------
  1228. HRESULT Get3IdentiStrFromIdentNode(IXMLDOMNode* pIdentityNode, BSTR* pbstrName, BSTR* pbstrPublisherName, BSTR* pbstrGUID)
  1229. {
  1230. HRESULT hr = E_FAIL;
  1231. BOOL fPublisherNameExist = FALSE, fGUIDExist = FALSE;
  1232. LOG_Block("Get3IdentiStrFromIdentNode()");
  1233. if (NULL == pIdentityNode || NULL == pbstrName || NULL == pbstrPublisherName || NULL == pbstrGUID)
  1234. {
  1235. return E_INVALIDARG;
  1236. }
  1237. *pbstrName = NULL;
  1238. *pbstrPublisherName = NULL;
  1239. *pbstrGUID = NULL;
  1240. //
  1241. // get name attr
  1242. //
  1243. hr = GetAttribute(pIdentityNode, KEY_NAME, pbstrName);
  1244. CleanUpIfFailedAndMsg(hr);
  1245. //
  1246. // try to get publisherName
  1247. //
  1248. fPublisherNameExist = FindNodeValue(pIdentityNode, KEY_PUBLISHERNAME, pbstrPublisherName);
  1249. fGUIDExist = FindNodeValue(pIdentityNode, KEY_GUID, pbstrGUID);
  1250. hr = (fPublisherNameExist || fGUIDExist) ? S_OK : E_FAIL;
  1251. CleanUp:
  1252. if (FAILED(hr))
  1253. {
  1254. SysFreeString(*pbstrName);
  1255. SysFreeString(*pbstrPublisherName);
  1256. SysFreeString(*pbstrGUID);
  1257. *pbstrName = NULL;
  1258. *pbstrPublisherName = NULL;
  1259. *pbstrGUID = NULL;
  1260. }
  1261. return hr;
  1262. }
  1263. /////////////////////////////////////////////////////////////////////////////
  1264. // MakeUniqNameString()
  1265. //
  1266. // This is a utility function to construct the identity name string
  1267. // based on name|publiser|GUID and the rule to make this name string.
  1268. //
  1269. // This function defines the logic about what components can be used
  1270. // to define the uniqueness of an item based on the 3 parts of data from
  1271. // GetIdentity().
  1272. //
  1273. /////////////////////////////////////////////////////////////////////////////
  1274. HRESULT MakeUniqNameString(
  1275. BSTR bstrName,
  1276. BSTR bstrPublisher,
  1277. BSTR bstrGUID,
  1278. BSTR* pbstrUniqIdentifierString)
  1279. {
  1280. LPWSTR pszResult = NULL;
  1281. DWORD dwLen=0;
  1282. HRESULT hr=S_OK;
  1283. if (NULL == bstrName || SysStringLen(bstrName) == 0 || NULL == pbstrUniqIdentifierString)
  1284. {
  1285. return E_INVALIDARG;
  1286. }
  1287. *pbstrUniqIdentifierString = NULL;
  1288. if (NULL != bstrPublisher && SysStringLen(bstrPublisher) > 0)
  1289. {
  1290. //
  1291. // if we have publisherName, we expect it is
  1292. // reverse DNS name (e.g., com.microsoft), and Name is
  1293. // the reverse DNS name (e.g., windowsupdate.autoupdate.client)
  1294. // inside that publisher. We combine them with a dot (.)
  1295. //
  1296. // Length of Publisher + Length of Name + 1 for the dot + 1 for null
  1297. dwLen=(SysStringLen(bstrPublisher) + SysStringLen(bstrName) + 2);
  1298. pszResult = (LPWSTR) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwLen * sizeof(WCHAR));
  1299. if (NULL == pszResult)
  1300. {
  1301. return E_OUTOFMEMORY;
  1302. }
  1303. //
  1304. // since we need to work on Win9x too, so we can not use Win32 API
  1305. // for UNICODE, and have to use shlwapi verison
  1306. //
  1307. hr=StringCchCopyExW(pszResult,dwLen,bstrPublisher,NULL,NULL,MISTSAFE_STRING_FLAGS);
  1308. if(FAILED(hr))
  1309. {
  1310. SafeHeapFree(pszResult);
  1311. return hr;
  1312. }
  1313. hr=StringCchCatExW(pszResult,dwLen,L".",NULL,NULL,MISTSAFE_STRING_FLAGS);
  1314. if(FAILED(hr))
  1315. {
  1316. SafeHeapFree(pszResult);
  1317. return hr;
  1318. }
  1319. hr=StringCchCatExW(pszResult,dwLen,bstrName,NULL,NULL,MISTSAFE_STRING_FLAGS);
  1320. if(FAILED(hr))
  1321. {
  1322. SafeHeapFree(pszResult);
  1323. return hr;
  1324. }
  1325. *pbstrUniqIdentifierString = SysAllocString(pszResult);
  1326. SafeHeapFree(pszResult);
  1327. if (NULL == *pbstrUniqIdentifierString)
  1328. {
  1329. return E_OUTOFMEMORY;
  1330. }
  1331. }
  1332. else
  1333. {
  1334. if (NULL == bstrGUID || SysStringLen(bstrGUID) == 0)
  1335. {
  1336. return E_INVALIDARG;
  1337. }
  1338. //
  1339. // if no suitable publisherName, then we use GUID
  1340. //
  1341. *pbstrUniqIdentifierString = SysAllocString(bstrGUID);
  1342. if (NULL == *pbstrUniqIdentifierString)
  1343. {
  1344. return E_OUTOFMEMORY;
  1345. }
  1346. }
  1347. return S_OK;
  1348. }
  1349. //----------------------------------------------------------------------
  1350. //
  1351. // public function UtilGetUniqIdentityStr()
  1352. // retrieve the unique string that make this <identity> node unique
  1353. //
  1354. // Return:
  1355. // HREUSLT - error code
  1356. //
  1357. //----------------------------------------------------------------------
  1358. HRESULT
  1359. UtilGetUniqIdentityStr(
  1360. IXMLDOMNode* pIdentityNode,
  1361. BSTR* pbstrUniqIdentifierString,
  1362. DWORD dwFlag)
  1363. {
  1364. DWORD dwLen=0;
  1365. LOG_Block("UtilGetUniqIdentityStr");
  1366. IXMLDOMNode *pNodeVersion = NULL;
  1367. IXMLDOMNode *pNodeIdentity = NULL;
  1368. BSTR bstrName = NULL,
  1369. bstrPublisher = NULL,
  1370. bstrGuid = NULL,
  1371. bstrResult = NULL;
  1372. USES_IU_CONVERSION;
  1373. if (NULL == pIdentityNode || NULL == pbstrUniqIdentifierString)
  1374. {
  1375. return E_INVALIDARG;
  1376. }
  1377. //
  1378. // retrive string
  1379. //
  1380. HRESULT hr = Get3IdentiStrFromIdentNode(pIdentityNode, &bstrName, &bstrPublisher, &bstrGuid);
  1381. CleanUpIfFailedAndMsg(hr);
  1382. //
  1383. // construct string to make it unique
  1384. //
  1385. hr = MakeUniqNameString(bstrName, bstrPublisher, bstrGuid, &bstrResult);
  1386. CleanUpIfFailedAndMsg(hr);
  1387. //
  1388. // check if this identity has version node. not all have <identity> nodes have <version>
  1389. //
  1390. if (FindNode(pNodeIdentity, KEY_VERSION, &pNodeVersion) && NULL != pNodeVersion)
  1391. {
  1392. TCHAR szVersion[MAX_VERSION];
  1393. LPWSTR pszUniqueString = NULL;
  1394. hr = UtilGetVersionStr(pNodeVersion, szVersion, dwFlag);
  1395. CleanUpIfFailedAndMsg(hr);
  1396. dwLen=(SysStringLen(bstrResult) + lstrlen(szVersion) + 2);
  1397. pszUniqueString = (LPWSTR) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwLen* sizeof(WCHAR));
  1398. CleanUpFailedAllocSetHrMsg(pszUniqueString);
  1399. hr=StringCchCopyExW(pszUniqueString,dwLen,bstrResult,NULL,NULL,MISTSAFE_STRING_FLAGS);
  1400. if(FAILED(hr))
  1401. {
  1402. SafeHeapFree(pszUniqueString);
  1403. SetHrMsgAndGotoCleanUp(hr);
  1404. }
  1405. hr=StringCchCatExW(pszUniqueString,dwLen,L".",NULL,NULL,MISTSAFE_STRING_FLAGS);
  1406. if(FAILED(hr))
  1407. {
  1408. SafeHeapFree(pszUniqueString);
  1409. SetHrMsgAndGotoCleanUp(hr);
  1410. }
  1411. hr=StringCchCatExW(pszUniqueString,dwLen,T2W(szVersion),NULL,NULL,MISTSAFE_STRING_FLAGS);
  1412. if(FAILED(hr))
  1413. {
  1414. SafeHeapFree(pszUniqueString);
  1415. SetHrMsgAndGotoCleanUp(hr);
  1416. }
  1417. *pbstrUniqIdentifierString = SysAllocString(pszUniqueString);
  1418. SafeHeapFree(pszUniqueString);
  1419. }
  1420. else
  1421. {
  1422. *pbstrUniqIdentifierString = SysAllocString(bstrResult);
  1423. }
  1424. CleanUpFailedAllocSetHrMsg(*pbstrUniqIdentifierString);
  1425. hr = S_OK;
  1426. CleanUp:
  1427. SysFreeString(bstrName);
  1428. SysFreeString(bstrPublisher);
  1429. SysFreeString(bstrGuid);
  1430. SysFreeString(bstrResult);
  1431. SafeRelease(pNodeVersion);
  1432. SafeRelease(pNodeIdentity);
  1433. return hr;
  1434. }
  1435. //----------------------------------------------------------------------
  1436. //
  1437. // public function UtilGetPlatformStr()
  1438. // retrieve the unique string that make this <platform> node unique
  1439. //
  1440. // Return:
  1441. // HREUSLT - error code
  1442. //
  1443. //----------------------------------------------------------------------
  1444. HRESULT
  1445. UtilGetPlatformStr(
  1446. IXMLDOMNode* pNodePlatform,
  1447. BSTR* pbstrPlatform,
  1448. DWORD dwFlag)
  1449. {
  1450. HRESULT hr = E_INVALIDARG;
  1451. IXMLDOMNode* pNodeVersion = NULL;
  1452. IXMLDOMNode* pNodeSuite = NULL;
  1453. IXMLDOMNodeList* pSuiteList = NULL;
  1454. IXMLDOMElement* pElement = NULL;
  1455. TCHAR szPlatformStr[MAX_PLATFORM_STR_LEN],
  1456. szVersion[256]; // should be enough for any version
  1457. const TCHAR PART_CONNECTOR[2] = _T("_");
  1458. const HRESULT RET_OVERFLOW = HRESULT_FROM_WIN32(ERROR_BUFFER_OVERFLOW);
  1459. BSTR bstrName = NULL,
  1460. bstrProcessor = NULL,
  1461. bstrType = NULL,
  1462. bstrSuite = NULL;
  1463. long iCount = 0,
  1464. iLength = 0;
  1465. LOG_Block("UtilGetPlatformStr");
  1466. USES_IU_CONVERSION;
  1467. szPlatformStr[0] = _T('\0');
  1468. if (NULL == pNodePlatform || NULL == pbstrPlatform)
  1469. {
  1470. return E_INVALIDARG;
  1471. }
  1472. //
  1473. // get platform name
  1474. //
  1475. if (SUCCEEDED(GetAttribute(pNodePlatform, KEY_NAME, &bstrName)) &&
  1476. NULL != bstrName && SysStringLen(bstrName) > 0)
  1477. {
  1478. iLength = SysStringLen(bstrName);
  1479. CleanUpIfFalseAndSetHrMsg(iLength >= MAX_PLATFORM_STR_LEN, RET_OVERFLOW);
  1480. CleanUpIfFailedAndSetHrMsg(StringCchCatEx(szPlatformStr,ARRAYSIZE(szPlatformStr),OLE2T(bstrName),NULL,NULL,MISTSAFE_STRING_FLAGS));
  1481. }
  1482. //
  1483. // if there is a valid processor architecture, like x86 or alpha, append it
  1484. //
  1485. if (FindNodeValue(pNodePlatform, KEY_PROCESSORARCHITECTURE, &bstrProcessor) &&
  1486. NULL != bstrProcessor && SysStringLen(bstrProcessor) > 0)
  1487. {
  1488. //
  1489. // processor architector should directly append to name, without
  1490. // the connect char "_"
  1491. iLength += SysStringLen(bstrProcessor) ;
  1492. CleanUpIfFalseAndSetHrMsg(iLength >= MAX_PLATFORM_STR_LEN, RET_OVERFLOW);
  1493. CleanUpIfFailedAndSetHrMsg(StringCchCatEx(szPlatformStr,ARRAYSIZE(szPlatformStr),OLE2T(bstrProcessor),NULL,NULL,MISTSAFE_STRING_FLAGS));
  1494. }
  1495. //
  1496. // try to get version code
  1497. //
  1498. hr = (TRUE == FindNode(pNodePlatform, KEY_VERSION, &pNodeVersion)) ? S_OK : E_FAIL;
  1499. //
  1500. // if return code is not saying we don't have version node,
  1501. // then it must be an error
  1502. //
  1503. if (FAILED(hr) && HRESULT_FROM_WIN32(ERROR_NOT_FOUND) != hr)
  1504. {
  1505. LOG_ErrorMsg(hr);
  1506. goto CleanUp;
  1507. }
  1508. //
  1509. // if we have a version node, try to find the version string
  1510. //
  1511. if (SUCCEEDED(hr))
  1512. {
  1513. hr = UtilGetVersionStr(pNodeVersion, szVersion, dwFlag);
  1514. SafeReleaseNULL(pNodeVersion);
  1515. //
  1516. // if we have a version node, it better be a good one
  1517. //
  1518. CleanUpIfFailedAndMsg(hr);
  1519. iLength += lstrlen(szVersion) + 1 ;
  1520. CleanUpIfFalseAndSetHrMsg(iLength >= MAX_PLATFORM_STR_LEN, RET_OVERFLOW);
  1521. CleanUpIfFailedAndSetHrMsg(StringCchCatEx(szPlatformStr,ARRAYSIZE(szPlatformStr),PART_CONNECTOR,NULL,NULL,MISTSAFE_STRING_FLAGS));
  1522. CleanUpIfFailedAndSetHrMsg(StringCchCatEx(szPlatformStr,ARRAYSIZE(szPlatformStr),szVersion,NULL,NULL,MISTSAFE_STRING_FLAGS));
  1523. }
  1524. //
  1525. // try to get a list of suite nodes
  1526. //
  1527. if (0x0 == (dwFlag & SKIP_SUITES))
  1528. {
  1529. hr = pNodePlatform->QueryInterface(IID_IXMLDOMElement, (void**)&pElement);
  1530. CleanUpIfFailedAndMsg(hr);
  1531. hr = pElement->getElementsByTagName(KEY_SUITE, &pSuiteList);
  1532. CleanUpIfFailedAndMsg(hr);
  1533. //
  1534. // try to get the length of the list, i.e., how many suite node(s)
  1535. //
  1536. hr = pSuiteList->get_length(&iCount);
  1537. CleanUpIfFailedAndMsg(hr);
  1538. //
  1539. // loop through each suite, if any
  1540. //
  1541. pSuiteList->reset();
  1542. for (int i = 0; i < iCount; i++)
  1543. {
  1544. hr = pSuiteList->get_item(i, &pNodeSuite);
  1545. CleanUpIfFailedAndMsg(hr);
  1546. if (pNodeSuite)
  1547. {
  1548. hr = pNodeSuite->get_text(&bstrSuite);
  1549. CleanUpIfFailedAndMsg(hr);
  1550. iLength += SysStringLen(bstrSuite) + 1;
  1551. CleanUpIfFalseAndSetHrMsg(iLength >= MAX_PLATFORM_STR_LEN, RET_OVERFLOW);
  1552. CleanUpIfFailedAndSetHrMsg(StringCchCatEx(szPlatformStr,ARRAYSIZE(szPlatformStr),PART_CONNECTOR,NULL,NULL,MISTSAFE_STRING_FLAGS));
  1553. CleanUpIfFailedAndSetHrMsg(StringCchCatEx(szPlatformStr,ARRAYSIZE(szPlatformStr),OLE2T(bstrSuite),NULL,NULL,MISTSAFE_STRING_FLAGS));
  1554. pNodeSuite->Release();
  1555. pNodeSuite = NULL;
  1556. SafeSysFreeString(bstrSuite);
  1557. }
  1558. }
  1559. pSuiteList->Release();
  1560. pSuiteList = NULL;
  1561. }
  1562. //
  1563. // if we find a productType node, append its text data
  1564. //
  1565. if (FindNodeValue(pNodePlatform, KEY_PRODUCTTYPE, &bstrType) &&
  1566. NULL != bstrType && SysStringLen(bstrType) > 0)
  1567. {
  1568. iLength += SysStringLen(bstrType) + 1;
  1569. CleanUpIfFalseAndSetHrMsg(iLength >= MAX_PLATFORM_STR_LEN, RET_OVERFLOW);
  1570. CleanUpIfFailedAndSetHrMsg(StringCchCatEx(szPlatformStr,ARRAYSIZE(szPlatformStr),PART_CONNECTOR,NULL,NULL,MISTSAFE_STRING_FLAGS));
  1571. CleanUpIfFailedAndSetHrMsg(StringCchCatEx(szPlatformStr,ARRAYSIZE(szPlatformStr),OLE2T(bstrType),NULL,NULL,MISTSAFE_STRING_FLAGS));
  1572. }
  1573. *pbstrPlatform = SysAllocString(T2OLE(szPlatformStr));
  1574. LOG_XML(_T("Got platform string %s"), szPlatformStr);
  1575. hr = S_OK;
  1576. CleanUp:
  1577. SysFreeString(bstrName);
  1578. SysFreeString(bstrProcessor);
  1579. SysFreeString(bstrSuite);
  1580. SysFreeString(bstrType);
  1581. SafeRelease(pNodeVersion);
  1582. SafeRelease(pNodeSuite);
  1583. SafeRelease(pSuiteList);
  1584. SafeRelease(pElement);
  1585. return hr;
  1586. }
  1587. //----------------------------------------------------------------------
  1588. //
  1589. // public function UtilGetVersionStr()
  1590. // retrieve the data from this <version> in string format
  1591. //
  1592. // Return:
  1593. // HREUSLT - error code
  1594. //
  1595. //----------------------------------------------------------------------
  1596. HRESULT
  1597. UtilGetVersionStr(
  1598. IXMLDOMNode* pVersionNode,
  1599. LPTSTR pszVersion,
  1600. DWORD dwFlag)
  1601. {
  1602. HRESULT hr = E_INVALIDARG;
  1603. LONG iMajor = -1,
  1604. iMinor = -1,
  1605. iBuild = -1,
  1606. iSvcPackMajor = -1,
  1607. iSvcPackMinor = -1;
  1608. LOG_Block("UtilGetVersionStr()");
  1609. BSTR bstrTimestamp = NULL;
  1610. BSTR bstrVersion = NULL;
  1611. TCHAR szNumber[16]; // enough to store a positive integer
  1612. BOOL fLastChunkExists = FALSE;
  1613. USES_IU_CONVERSION;
  1614. if (NULL == pVersionNode || NULL == pszVersion)
  1615. {
  1616. return hr;
  1617. }
  1618. *pszVersion = _T('\0');
  1619. //
  1620. // a version node can contain either text version data (for binaries),
  1621. // or attribute version data (for OS). If both exist, we prefer text data
  1622. //
  1623. if (SUCCEEDED(pVersionNode->get_text(&bstrVersion)) && NULL != bstrVersion &&
  1624. SysStringLen(bstrVersion) > 0)
  1625. {
  1626. lstrcpyn(pszVersion, OLE2T(bstrVersion), MAX_VERSION);
  1627. }
  1628. else
  1629. {
  1630. if (SUCCEEDED(GetAttribute(pVersionNode, KEY_MAJOR, &iMajor)) && iMajor > 0)
  1631. {
  1632. //It's an assumption that the pszVersion will be atleast MAX_VERSION characters wide
  1633. CleanUpIfFailedAndSetHrMsg(StringCchPrintfEx(pszVersion,MAX_VERSION,NULL,NULL,MISTSAFE_STRING_FLAGS, _T("%d"),iMajor));
  1634. if (SUCCEEDED(GetAttribute(pVersionNode, KEY_MINOR, &iMinor)) && iMinor >= 0)
  1635. {
  1636. CleanUpIfFailedAndSetHrMsg(StringCchPrintfEx(szNumber,ARRAYSIZE(szNumber),NULL,NULL,MISTSAFE_STRING_FLAGS, _T(".%d"),iMinor));
  1637. CleanUpIfFailedAndSetHrMsg(StringCchCatEx(pszVersion,MAX_VERSION,szNumber,NULL,NULL,MISTSAFE_STRING_FLAGS));
  1638. if (SUCCEEDED(GetAttribute(pVersionNode, KEY_BUILD, &iBuild)) && iBuild >= 0)
  1639. {
  1640. CleanUpIfFailedAndSetHrMsg(StringCchPrintfEx(szNumber,ARRAYSIZE(szNumber),NULL,NULL,MISTSAFE_STRING_FLAGS, _T(".%d"),iBuild));
  1641. CleanUpIfFailedAndSetHrMsg(StringCchCatEx(pszVersion,MAX_VERSION,szNumber,NULL,NULL,MISTSAFE_STRING_FLAGS));
  1642. }
  1643. }
  1644. fLastChunkExists = TRUE;
  1645. }
  1646. if (0x0 == (dwFlag & SKIP_SERVICEPACK_VER) &&
  1647. SUCCEEDED(GetAttribute(pVersionNode, KEY_SERVICEPACKMAJOR, &iSvcPackMajor)) &&
  1648. iSvcPackMajor > 0)
  1649. {
  1650. if (fLastChunkExists)
  1651. {
  1652. CleanUpIfFailedAndSetHrMsg(StringCchCatEx(pszVersion,MAX_VERSION,_T(","),NULL,NULL,MISTSAFE_STRING_FLAGS));
  1653. }
  1654. CleanUpIfFailedAndSetHrMsg(StringCchPrintfEx(szNumber,ARRAYSIZE(szNumber),NULL,NULL,MISTSAFE_STRING_FLAGS, _T("%d"),iSvcPackMajor));
  1655. CleanUpIfFailedAndSetHrMsg(StringCchCatEx(pszVersion,MAX_VERSION,szNumber,NULL,NULL,MISTSAFE_STRING_FLAGS));
  1656. if (SUCCEEDED(GetAttribute(pVersionNode, KEY_SERVICEPACKMINOR, &iSvcPackMinor)) &&
  1657. iSvcPackMinor >= 0)
  1658. {
  1659. CleanUpIfFailedAndSetHrMsg(StringCchPrintfEx(szNumber,ARRAYSIZE(szNumber),NULL,NULL,MISTSAFE_STRING_FLAGS,_T(".%d"),iSvcPackMinor));
  1660. CleanUpIfFailedAndSetHrMsg(StringCchCatEx(pszVersion,MAX_VERSION,szNumber,NULL,NULL,MISTSAFE_STRING_FLAGS));
  1661. }
  1662. fLastChunkExists = TRUE;
  1663. }
  1664. else
  1665. {
  1666. fLastChunkExists = FALSE;
  1667. }
  1668. if (SUCCEEDED(GetAttribute(pVersionNode, KEY_TIMESTAMP, &bstrTimestamp)) &&
  1669. NULL != bstrTimestamp && SysStringLen(bstrTimestamp) > 0)
  1670. {
  1671. if (fLastChunkExists)
  1672. {
  1673. CleanUpIfFailedAndSetHrMsg(StringCchCatEx(pszVersion,MAX_VERSION,_T(","),NULL,NULL,MISTSAFE_STRING_FLAGS));
  1674. }
  1675. else
  1676. {
  1677. //
  1678. // if we need to append timestamp, and we didn't get service pack
  1679. // data, we want to leave extra separator "," to tell the following
  1680. // part is timestamp and service pack data missing.
  1681. //
  1682. if (*pszVersion != _T('\0'))
  1683. {
  1684. CleanUpIfFailedAndSetHrMsg(StringCchCatEx(pszVersion,MAX_VERSION,_T(",,"),NULL,NULL,MISTSAFE_STRING_FLAGS));
  1685. }
  1686. //
  1687. // if this is the first chunk we found, then no prefix needed
  1688. //
  1689. }
  1690. CleanUpIfFailedAndSetHrMsg(StringCchCatEx(pszVersion,MAX_VERSION,OLE2T(bstrTimestamp),NULL,NULL,MISTSAFE_STRING_FLAGS));
  1691. }
  1692. }
  1693. //
  1694. // if we got something, then this is a valid version node and
  1695. // we can pass back whatever we got. Otherwise we return E_INVALIDARG
  1696. //
  1697. if (*pszVersion != _T('\0'))
  1698. {
  1699. LOG_XML(_T("Got version str %s"), pszVersion);
  1700. hr = S_OK;
  1701. }
  1702. CleanUp:
  1703. SysFreeString(bstrTimestamp);
  1704. SysFreeString(bstrVersion);
  1705. return hr;
  1706. }
  1707. //-----------------------------------------------------------------------
  1708. //
  1709. // function GetFullFilePathFromFilePathNode()
  1710. //
  1711. // retrieve the full qualified file path from a filePath node
  1712. //
  1713. // Input:
  1714. // a filePath XMLDom node
  1715. // a pointer to a buffer to receive path, assumes MAX_PATH long.
  1716. //
  1717. // Return:
  1718. // HRESULT
  1719. // Found path: S_OK
  1720. // Not found path: S_FALSE, lpszFilePath is empty
  1721. // otherwise, error code
  1722. //
  1723. //
  1724. //-----------------------------------------------------------------------
  1725. HRESULT GetFullFilePathFromFilePathNode(
  1726. IXMLDOMNode* pFilePathNode,
  1727. LPTSTR lpszFilePath
  1728. )
  1729. {
  1730. HRESULT hr = S_OK;
  1731. LOG_Block("GetFullFilePathFromFilePathNode");
  1732. USES_IU_CONVERSION;
  1733. IXMLDOMNode* pRegKeyNode = NULL;
  1734. TCHAR szPath[MAX_PATH] = {_T('\0')};
  1735. LPTSTR lpszFileName = NULL;
  1736. LPTSTR lpszKey = NULL;
  1737. LPTSTR lpszValue = NULL;
  1738. LPTSTR lpszPath = NULL;
  1739. BSTR bstrName = NULL;
  1740. BSTR bstrPath = NULL;
  1741. BSTR bstrKey = NULL;
  1742. BSTR bstrValue = NULL;
  1743. BOOL fPathExists = FALSE;
  1744. UINT nReqSize = 0;
  1745. if (NULL == pFilePathNode || NULL == lpszFilePath)
  1746. {
  1747. hr = E_INVALIDARG;
  1748. LOG_ErrorMsg(hr);
  1749. goto CleanUp;
  1750. }
  1751. //
  1752. // init path buffer
  1753. //
  1754. *lpszFilePath = _T('\0');
  1755. //
  1756. // try to get name data, note: S_FALSE won't do, it means everything is
  1757. // fine but this attribute does not exist.
  1758. //
  1759. if (S_OK == (hr = GetAttribute(pFilePathNode, KEY_NAME, &bstrName)))
  1760. {
  1761. //
  1762. // found name attribute
  1763. //
  1764. lpszFileName = OLE2T(bstrName);
  1765. LOG_XML(_T(" file name=%s"), lpszFileName);
  1766. fPathExists = TRUE;
  1767. }
  1768. if (FindNode(pFilePathNode, KEY_REGKEY, &pRegKeyNode) && NULL != pRegKeyNode)
  1769. {
  1770. //
  1771. // found a reg key node
  1772. //
  1773. if (!FindNodeValue(pRegKeyNode, KEY_KEY, &bstrKey))
  1774. {
  1775. //
  1776. // key node is required!
  1777. //
  1778. hr = E_INVALIDARG;
  1779. LOG_ErrorMsg(hr);
  1780. goto CleanUp;
  1781. }
  1782. lpszKey = OLE2T(bstrKey);
  1783. LOG_XML(_T("Found key=%s"), lpszKey);
  1784. //
  1785. // get optional value name
  1786. //
  1787. if (FindNodeValue(pRegKeyNode, KEY_ENTRY, &bstrValue))
  1788. {
  1789. lpszValue = OLE2T(bstrValue);
  1790. LOG_XML(_T("found entry=%s"), lpszValue);
  1791. }
  1792. else
  1793. {
  1794. LOG_XML(_T("found no value, use default"));
  1795. }
  1796. if (GetFilePathFromReg(lpszKey, lpszValue, NULL, NULL, szPath) && _T('\0') != *szPath)
  1797. {
  1798. //
  1799. // various reason can me this call fail, such as
  1800. // reg key wrong, no access to reg key, out of memory, etc
  1801. //
  1802. fPathExists = TRUE;
  1803. }
  1804. }
  1805. if (FindNodeValue(pFilePathNode, KEY_PATH, &bstrPath) && SysStringLen(bstrPath) > 0)
  1806. {
  1807. //
  1808. // found path element
  1809. //
  1810. lpszPath = OLE2T(bstrPath);
  1811. fPathExists = TRUE;
  1812. }
  1813. if (!fPathExists)
  1814. {
  1815. //
  1816. // nothing exist
  1817. //
  1818. lpszFilePath[0] = _T('\0');
  1819. LOG_XML(_T("empty node!"));
  1820. hr = S_FALSE;
  1821. goto CleanUp;
  1822. }
  1823. nReqSize = lstrlen(szPath) + SysStringLen(bstrPath) + SysStringLen(bstrName);
  1824. if (nReqSize >= MAX_PATH ||
  1825. NULL != lpszPath && FAILED(PathCchAppend(szPath,MAX_PATH,lpszPath)) || // append path to reg path
  1826. NULL != lpszFileName && FAILED(PathCchAppend(szPath,MAX_PATH,lpszFileName))) // append name
  1827. {
  1828. LOG_ErrorMsg(ERROR_BUFFER_OVERFLOW);
  1829. hr = HRESULT_FROM_WIN32(ERROR_BUFFER_OVERFLOW);
  1830. goto CleanUp;
  1831. }
  1832. if (FAILED (hr = ExpandFilePath(szPath, lpszFilePath, MAX_PATH)))
  1833. {
  1834. LOG_ErrorMsg(hr);
  1835. goto CleanUp;
  1836. }
  1837. CleanUp:
  1838. SysFreeString(bstrName);
  1839. SysFreeString(bstrPath);
  1840. SysFreeString(bstrKey);
  1841. SysFreeString(bstrValue);
  1842. SafeRelease(pRegKeyNode);
  1843. return hr;
  1844. }
  1845. HRESULT GetBstrFullFilePathFromFilePathNode(
  1846. IXMLDOMNode* pFilePathNode,
  1847. BSTR* pbstrFilePath
  1848. )
  1849. {
  1850. HRESULT hr = S_OK;
  1851. USES_IU_CONVERSION;
  1852. TCHAR szPath[MAX_PATH];
  1853. QuitIfNull(pbstrFilePath);
  1854. *pbstrFilePath = NULL;
  1855. if (SUCCEEDED(hr = GetFullFilePathFromFilePathNode(pFilePathNode, szPath)))
  1856. {
  1857. *pbstrFilePath = SysAllocString(T2OLE(szPath));
  1858. }
  1859. return hr;
  1860. }
  1861. /////////////////////////////////////////////////////////////////////////////
  1862. //
  1863. // Helper function DoesNodeHaveName()
  1864. //
  1865. // find out the the current node has a matching name
  1866. //
  1867. // Input:
  1868. // a node
  1869. //
  1870. // Return:
  1871. // TRUE/FALSE
  1872. //
  1873. /////////////////////////////////////////////////////////////////////////////
  1874. BOOL DoesNodeHaveName(IXMLDOMNode* pNode, BSTR bstrTagName)
  1875. {
  1876. BSTR bstrName;
  1877. BOOL fRet = FALSE;
  1878. IXMLDOMElement* pElement = NULL;
  1879. if (NULL == pNode)
  1880. {
  1881. return fRet;
  1882. }
  1883. if (FAILED(pNode->QueryInterface(IID_IXMLDOMElement, (void**) &pElement)) || NULL == pElement)
  1884. {
  1885. return FALSE;
  1886. }
  1887. if (SUCCEEDED(pElement->get_nodeName(&bstrName)))
  1888. {
  1889. fRet = CompareBSTRsEqual(bstrName, bstrTagName);
  1890. }
  1891. SysFreeString(bstrName);
  1892. SafeReleaseNULL(pElement);
  1893. return fRet;
  1894. }