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.

1080 lines
24 KiB

  1. ////////////////////////////////////////////////////////////////////////////////////
  2. //
  3. // File: xml.cpp
  4. //
  5. // History: 16-Nov-00 markder Created.
  6. //
  7. // Desc: This file contains helper functions to manipulate
  8. // the MSXML's document object model (DOM).
  9. //
  10. ////////////////////////////////////////////////////////////////////////////////////
  11. #include "StdAfx.h"
  12. #include "xml.h"
  13. void __stdcall _com_issue_error(long)
  14. {
  15. SDBERROR(_T("Unknown COM error!!"));
  16. }
  17. ////////////////////////////////////////////////////////////////////////////////////
  18. //
  19. // XMLNodeList Implementation
  20. //
  21. // This class is a wrapper for the IXMLDOMNodeList interface. It simplifies
  22. // C++ access by exposing functions for executing XQL queries and iterating
  23. // through the elements in a node list.
  24. //
  25. ////////////////////////////////////////////////////////////////////////////////////
  26. XMLNodeList::XMLNodeList()
  27. {
  28. m_nSize = 0;
  29. }
  30. XMLNodeList::~XMLNodeList()
  31. {
  32. Clear();
  33. }
  34. void XMLNodeList::Clear()
  35. {
  36. m_nSize = 0;
  37. m_csXQL.Empty();
  38. if (m_cpList) {
  39. m_cpList.Release();
  40. }
  41. }
  42. LONG XMLNodeList::GetSize()
  43. {
  44. return m_nSize;
  45. }
  46. BOOL XMLNodeList::Query(IXMLDOMNode* pNode, LPCTSTR szXQL)
  47. {
  48. BOOL bSuccess = FALSE;
  49. BSTR bsXQL = NULL;
  50. CString csXQL(szXQL);
  51. bsXQL = csXQL.AllocSysString();
  52. Clear();
  53. if (FAILED(pNode->selectNodes(bsXQL, &m_cpList))) {
  54. CString csFormat;
  55. csFormat.Format(_T("Error executing XQL \"%s\""), szXQL);
  56. SDBERROR(csFormat);
  57. goto eh;
  58. }
  59. if (FAILED(m_cpList->get_length(&m_nSize))) {
  60. CString csFormat;
  61. csFormat.Format(_T("Error executing XQL \"%s\""), szXQL);
  62. SDBERROR(csFormat);
  63. goto eh;
  64. }
  65. m_csXQL = szXQL;
  66. bSuccess = TRUE;
  67. eh:
  68. if (bsXQL != NULL) {
  69. SysFreeString(bsXQL);
  70. }
  71. if (!bSuccess) {
  72. Clear();
  73. }
  74. return bSuccess;
  75. }
  76. BOOL XMLNodeList::GetChildNodes(IXMLDOMNode* pNode)
  77. {
  78. BOOL bSuccess = FALSE;
  79. Clear();
  80. if (FAILED(pNode->get_childNodes(&m_cpList))) {
  81. SDBERROR(_T("Error retrieving child nodes"));
  82. goto eh;
  83. }
  84. if (FAILED(m_cpList->get_length(&m_nSize))) {
  85. SDBERROR(_T("Error retrieving child nodes"));
  86. goto eh;
  87. }
  88. bSuccess = TRUE;
  89. eh:
  90. if (!bSuccess) {
  91. Clear();
  92. }
  93. return bSuccess;
  94. }
  95. BOOL XMLNodeList::GetItem(LONG nIndex, IXMLDOMNode** ppNode)
  96. {
  97. BOOL bSuccess = FALSE;
  98. if (nIndex < 0 || nIndex >= m_nSize) {
  99. CString csFormat;
  100. csFormat.Format(_T("XMLNodeList index %d out of range for XQL \"%s\""), nIndex, m_csXQL);
  101. SDBERROR(csFormat);
  102. goto eh;
  103. }
  104. if (FAILED(m_cpList->get_item(nIndex, ppNode))) {
  105. CString csFormat;
  106. csFormat.Format(_T("XMLNodeList get_item failed for XQL \"%s\""), m_csXQL);
  107. SDBERROR(csFormat);
  108. goto eh;
  109. }
  110. bSuccess = TRUE;
  111. eh:
  112. return bSuccess;
  113. }
  114. ////////////////////////////////////////////////////////////////////////////////////
  115. //
  116. // Func: OpenXML
  117. //
  118. // Desc: Opens an XML file or stream and returns the root node.
  119. //
  120. BOOL OpenXML(
  121. CString csFileOrStream,
  122. IXMLDOMNode** ppRootNode,
  123. BOOL bStream,
  124. IXMLDOMDocument** ppDoc)
  125. {
  126. long i;
  127. long nErrorLine = 0;
  128. long nErrorLinePos = 0;
  129. long nListCount = 0;
  130. BOOL bSuccess = FALSE;
  131. BSTR bsSrcText = NULL;
  132. BSTR bsErrorReason = NULL;
  133. HRESULT hr = E_FAIL;
  134. VARIANT vFileOrStream;
  135. VARIANT_BOOL vbSuccess = VARIANT_FALSE;
  136. IXMLDOMDocument* pDoc = NULL;
  137. IXMLDOMParseErrorPtr cpXMLParseError;
  138. VariantInit(&vFileOrStream);
  139. VariantClear(&vFileOrStream);
  140. if (ppDoc == NULL) {
  141. ppDoc = &pDoc;
  142. }
  143. if (*ppDoc == NULL) {
  144. if (FAILED(CoCreateInstance(CLSID_DOMDocument,
  145. NULL,
  146. CLSCTX_INPROC_SERVER,
  147. IID_IXMLDOMDocument,
  148. (LPVOID*)ppDoc))) {
  149. SDBERROR(_T("Could not instantiate MSXML object.\n"));
  150. goto eh;
  151. }
  152. }
  153. vFileOrStream.vt = VT_BSTR;
  154. vFileOrStream.bstrVal = csFileOrStream.AllocSysString();
  155. //
  156. // This statement prevents XML parser from replacing white space
  157. // characters with tabs
  158. //
  159. if (bStream) {
  160. hr = (*ppDoc)->loadXML(vFileOrStream.bstrVal, &vbSuccess);
  161. } else {
  162. (*ppDoc)->put_preserveWhiteSpace(VARIANT_TRUE);
  163. (*ppDoc)->put_validateOnParse(g_bStrict ? VARIANT_TRUE : VARIANT_FALSE);
  164. hr = (*ppDoc)->load(vFileOrStream, &vbSuccess);
  165. }
  166. if (FAILED(hr) || vbSuccess == VARIANT_FALSE) {
  167. if (FAILED((*ppDoc)->get_parseError(&cpXMLParseError))) {
  168. SDBERROR(_T("Could not retrieve XMLDOMParseError object"));
  169. goto eh;
  170. }
  171. if (FAILED(cpXMLParseError->get_line(&nErrorLine))) {
  172. SDBERROR(_T("Could not retrieve line number from XMLDOMParseError object"));
  173. goto eh;
  174. }
  175. if (FAILED(cpXMLParseError->get_linepos(&nErrorLinePos))) {
  176. SDBERROR(_T("Could not retrieve line position from XMLDOMParseError object"));
  177. goto eh;
  178. }
  179. if (FAILED(cpXMLParseError->get_srcText(&bsSrcText))) {
  180. SDBERROR(_T("Could not retrieve source text from XMLDOMParseError object"));
  181. goto eh;
  182. }
  183. if (FAILED(cpXMLParseError->get_reason(&bsErrorReason))) {
  184. SDBERROR(_T("Could not retrieve error reason from XMLDOMParseError object"));
  185. goto eh;
  186. }
  187. CString csError;
  188. csError.Format(_T("XML parsing error on line %d:\n\n%ls\n\n%ls\n"),
  189. nErrorLine, bsErrorReason, bsSrcText);
  190. while (nErrorLinePos--) {
  191. csError += " ";
  192. }
  193. csError += _T("^----- Error\n\n");
  194. SDBERROR(csError);
  195. goto eh;
  196. }
  197. if (FAILED((*ppDoc)->QueryInterface(IID_IXMLDOMNode, (LPVOID*)ppRootNode))) {
  198. SDBERROR(_T("Could not retrieve XMLDOMNode object from XMLDOMDocument interface"));
  199. goto eh;
  200. }
  201. bSuccess = TRUE;
  202. eh:
  203. if (pDoc) {
  204. pDoc->Release();
  205. }
  206. if (bsSrcText) {
  207. SysFreeString(bsSrcText);
  208. }
  209. if (bsErrorReason) {
  210. SysFreeString(bsErrorReason);
  211. }
  212. VariantClear(&vFileOrStream);
  213. return bSuccess;
  214. }
  215. ////////////////////////////////////////////////////////////////////////////////////
  216. //
  217. // Func: SaveXMLFile
  218. //
  219. // Desc: Saves an XML file.
  220. //
  221. BOOL SaveXMLFile(
  222. CString csFile,
  223. IXMLDOMNode* pNode)
  224. {
  225. BOOL bSuccess = FALSE;
  226. DWORD dwAttr;
  227. DWORD dwErr;
  228. CString csFormat;
  229. VARIANT vFilename;
  230. HRESULT hr;
  231. IXMLDOMDocumentPtr cpDocument;
  232. VariantInit(&vFilename);
  233. //
  234. // Check file attributes
  235. //
  236. dwAttr = GetFileAttributes(csFile);
  237. if ((DWORD)-1 == dwAttr) {
  238. dwErr = GetLastError();
  239. if (ERROR_FILE_NOT_FOUND != dwErr) {
  240. csFormat.Format(_T("Error accessing XML file: %s (0x%lx)\n"), dwErr);
  241. SDBERROR(csFormat);
  242. goto eh;
  243. }
  244. } else if (dwAttr & FILE_ATTRIBUTE_READONLY) {
  245. csFormat.Format(_T("File \"%s\" appears to be read-only and cannot be updated\n"),
  246. csFile);
  247. SDBERROR(csFormat);
  248. goto eh;
  249. }
  250. if (FAILED(pNode->get_ownerDocument(&cpDocument))) {
  251. SDBERROR(_T("Could not retrieve ownerDocument property of node."));
  252. goto eh;
  253. }
  254. vFilename.vt = VT_BSTR;
  255. vFilename.bstrVal = csFile.AllocSysString();
  256. hr = cpDocument->save(vFilename);
  257. if (FAILED(hr)) {
  258. csFormat.Format(_T("Could not update XML file: %s (0x%lx)\n"), csFile, (DWORD)hr);
  259. SDBERROR(csFormat);
  260. goto eh;
  261. }
  262. bSuccess = TRUE;
  263. eh:
  264. VariantClear(&vFilename);
  265. return bSuccess;
  266. }
  267. CString ReplaceAmp(
  268. LPCTSTR lpszXML)
  269. {
  270. LPTSTR pchStart = (LPTSTR)lpszXML;
  271. LPTSTR pchEnd;
  272. LPTSTR pchHRef;
  273. LPTSTR pchTag;
  274. TCHAR ch;
  275. CString csXML = ""; // << this is what we return
  276. CString csHRef;
  277. do {
  278. pchHRef = _tcsstr(pchStart, _T("href"));
  279. if (NULL == pchHRef) {
  280. pchHRef = _tcsstr(pchStart, _T("HREF"));
  281. }
  282. if (NULL != pchHRef) {
  283. //
  284. // Find the closing bracket
  285. //
  286. pchEnd = _tcschr(pchHRef, _T('>'));
  287. if (NULL == pchEnd) {
  288. csXML += pchStart;
  289. pchHRef = NULL;
  290. } else {
  291. //
  292. // Now see where this thing starts
  293. //
  294. ch = *pchHRef;
  295. *pchHRef = _T('\0');
  296. //
  297. // Search back to the first '<'
  298. //
  299. pchTag = _tcsrchr(pchStart, _T('<'));
  300. *pchHRef = ch;
  301. if (NULL == pchTag) {
  302. pchTag = pchStart;
  303. }
  304. //
  305. // Now we have < >
  306. //
  307. csHRef = CString(pchTag, (int)(pchEnd - pchTag + 1));
  308. csHRef.Replace(_T("%26"), _T("&"));
  309. csHRef.Replace(_T("&amp;"), _T("&"));
  310. csXML += CString(pchStart, (int)(pchTag-pchStart)) + csHRef;
  311. pchStart = pchEnd + 1;
  312. }
  313. } else {
  314. csXML += pchStart;
  315. }
  316. } while (NULL != pchHRef);
  317. return csXML;
  318. }
  319. ////////////////////////////////////////////////////////////////////////////////////
  320. //
  321. // Func: GetInnerXML
  322. //
  323. // Desc: Returns the XML between the begin/end tag of pNode.
  324. //
  325. CString GetInnerXML(
  326. IXMLDOMNode* pNode)
  327. {
  328. USES_CONVERSION;
  329. long nIndex = 0;
  330. long nListLength = 0;
  331. IXMLDOMNode* pNodeChild = NULL;
  332. IXMLDOMNodeList* pNodeList = NULL;
  333. DOMNodeType NodeType;
  334. CString csNodeXML;
  335. CString csHRef;
  336. CString csFixedHRef;
  337. CString strXML;
  338. strXML.Empty();
  339. if (FAILED(pNode->get_childNodes(&pNodeList)) || pNodeList == NULL) {
  340. SDBERROR(_T("get_childNodes failed while retrieving innerXML"));
  341. goto eh;
  342. }
  343. if (FAILED(pNodeList->get_length(&nListLength))) {
  344. SDBERROR(_T("get_length failed while retrieving innerXML"));
  345. goto eh;
  346. }
  347. while (nIndex < nListLength) {
  348. if (FAILED(pNodeList->get_item(nIndex, &pNodeChild))) {
  349. SDBERROR(_T("get_item failed while retrieving innerXML"));
  350. goto eh;
  351. }
  352. csNodeXML = GetXML(pNodeChild);
  353. strXML += csNodeXML;
  354. pNodeChild->Release();
  355. pNodeChild = NULL;
  356. ++nIndex;
  357. }
  358. ReplaceStringNoCase(strXML, _T(" xmlns=\"x-schema:schema.xml\""), _T(""));
  359. eh:
  360. if (NULL != pNodeList) {
  361. pNodeList->Release();
  362. }
  363. if (NULL != pNodeChild) {
  364. pNodeChild->Release();
  365. }
  366. return strXML;
  367. }
  368. ////////////////////////////////////////////////////////////////////////////////////
  369. //
  370. // Func: GetAttribute
  371. //
  372. // Desc: Returns the text value of the attribute specified by lpszAttribute on node
  373. // pNode. If the the attribute doesn't exist, the function returns FALSE.
  374. //
  375. BOOL GetAttribute(
  376. LPCTSTR lpszAttribute,
  377. IXMLDOMNodePtr pNode,
  378. CString* pcsValue,
  379. BOOL bXML)
  380. {
  381. USES_CONVERSION;
  382. BOOL bSuccess = FALSE;
  383. BSTR bsQuery = NULL;
  384. CString csQuery;
  385. IXMLDOMNodePtr cpAttrNode;
  386. csQuery = _T("@");
  387. csQuery += lpszAttribute;
  388. bsQuery = csQuery.AllocSysString();
  389. //
  390. // g_csError will not be set in this function. It is up
  391. // to the caller to handle a FALSE return from this function
  392. // and report appropriately.
  393. //
  394. if (FAILED(pNode->selectSingleNode(bsQuery, &cpAttrNode))) {
  395. goto eh;
  396. }
  397. if (cpAttrNode == NULL) {
  398. goto eh;
  399. }
  400. if (bXML) {
  401. *pcsValue = GetXML(cpAttrNode);
  402. } else {
  403. *pcsValue = GetText(cpAttrNode);
  404. }
  405. bSuccess = TRUE;
  406. eh:
  407. if (bsQuery != NULL) {
  408. SysFreeString(bsQuery);
  409. }
  410. return bSuccess;
  411. }
  412. ////////////////////////////////////////////////////////////////////////////////////
  413. //
  414. // Func: RemoveAttribute
  415. //
  416. // Desc: Removes the specified attribute from the element.
  417. //
  418. BOOL RemoveAttribute(
  419. CString csName,
  420. IXMLDOMNodePtr pNode)
  421. {
  422. USES_CONVERSION;
  423. BOOL bSuccess = FALSE;
  424. BSTR bsName = NULL;
  425. IXMLDOMNamedNodeMap* pNodeMap = NULL;
  426. IXMLDOMNode* pAttrNode = NULL;
  427. //
  428. // g_csError will not be set in this function. It is up
  429. // to the caller to handle a FALSE return from this function
  430. // and report appropriately.
  431. //
  432. if (FAILED(pNode->get_attributes(&pNodeMap)) || pNodeMap == NULL) {
  433. goto eh;
  434. }
  435. bsName = csName.AllocSysString();
  436. if (FAILED(pNodeMap->removeNamedItem(bsName, &pAttrNode))) {
  437. goto eh;
  438. }
  439. bSuccess = TRUE;
  440. eh:
  441. if (pNodeMap != NULL) {
  442. pNodeMap->Release();
  443. }
  444. if (pAttrNode != NULL) {
  445. pAttrNode->Release();
  446. }
  447. if (bsName != NULL) {
  448. SysFreeString(bsName);
  449. }
  450. return bSuccess;
  451. }
  452. ////////////////////////////////////////////////////////////////////////////////////
  453. //
  454. // Func: GetChild
  455. //
  456. // Desc: Returns the child node corresponding to the specified tag name.
  457. //
  458. BOOL GetChild(
  459. LPCTSTR lpszTag,
  460. IXMLDOMNode* pParentNode,
  461. IXMLDOMNode** ppChildNode)
  462. {
  463. BOOL bSuccess = FALSE;
  464. XMLNodeList XQL;
  465. if (!XQL.Query(pParentNode, lpszTag)) {
  466. goto eh;
  467. }
  468. if (XQL.GetSize() == 0) {
  469. goto eh;
  470. }
  471. if (XQL.GetSize() > 1) {
  472. goto eh;
  473. }
  474. if (!XQL.GetItem(0, ppChildNode)) {
  475. goto eh;
  476. }
  477. bSuccess = TRUE;
  478. eh:
  479. return bSuccess;
  480. }
  481. ////////////////////////////////////////////////////////////////////////////////////
  482. //
  483. // Func: GetText
  484. //
  485. // Desc: Returns the value of the text property on node pNode.
  486. //
  487. CString GetText(
  488. IXMLDOMNode* pNode)
  489. {
  490. CString csText;
  491. BSTR bsText = NULL;
  492. HRESULT hr;
  493. hr = pNode->get_text(&bsText);
  494. if (SUCCEEDED(hr)) {
  495. csText = bsText;
  496. if (bsText) {
  497. SysFreeString(bsText);
  498. }
  499. }
  500. //
  501. // If get_text fails, then csText is blank.
  502. //
  503. return csText;
  504. }
  505. ////////////////////////////////////////////////////////////////////////////////////
  506. //
  507. // Func: GetText
  508. //
  509. // Desc: Returns the value of the node pNode, in string form
  510. //
  511. CString GetNodeValue(
  512. IXMLDOMNode* pNode)
  513. {
  514. CString csVal;
  515. VARIANT var;
  516. VariantInit(&var);
  517. // BUGBUG: what if some of these calls fail!
  518. if (S_OK == pNode->get_nodeValue(&var)) {
  519. if (VT_BSTR == var.vt) {
  520. csVal = var.bstrVal;
  521. if (NULL != var.bstrVal) {
  522. SysFreeString(var.bstrVal);
  523. }
  524. }
  525. }
  526. return csVal;
  527. }
  528. ////////////////////////////////////////////////////////////////////////////////////
  529. //
  530. // Func: GetText
  531. //
  532. // Desc: Retrieves the value of the text property on node pNode.
  533. // excludes any comment text
  534. // Returns FALSE in case of an error
  535. //
  536. BOOL GetNodeText(
  537. IXMLDOMNode* pNode,
  538. CString& csNodeText
  539. )
  540. {
  541. USES_CONVERSION;
  542. BOOL bSuccess = FALSE;
  543. long nIndex = 0;
  544. long nListLength = 0;
  545. IXMLDOMNode* pNodeText = NULL;
  546. IXMLDOMNodeList* pNodeList = NULL;
  547. DOMNodeType NodeType;
  548. CString csText;
  549. csNodeText.Empty();
  550. if (FAILED(pNode->get_childNodes(&pNodeList)) || pNodeList == NULL) {
  551. // BUGBUG: display some error
  552. goto eh;
  553. }
  554. if (FAILED(pNodeList->get_length(&nListLength))) {
  555. // BUGBUG: display some error
  556. goto eh;
  557. }
  558. while (nIndex < nListLength) {
  559. if (FAILED(pNodeList->get_item(nIndex, &pNodeText))) {
  560. // BUGBUG: display some error
  561. goto eh; // can't get the item
  562. }
  563. if (FAILED(pNodeText->get_nodeType(&NodeType))) {
  564. // BUGBUG: display some error
  565. goto eh; // can't get node type
  566. }
  567. if (NODE_TEXT == NodeType) {
  568. //
  569. // now this node is a body text
  570. //
  571. csText = GetNodeValue(pNodeText);
  572. csText.TrimLeft();
  573. csText.TrimRight();
  574. if (!csText.IsEmpty()) {
  575. csNodeText += CString(_T(' ')) + csText;
  576. }
  577. }
  578. pNodeText->Release();
  579. pNodeText = NULL;
  580. ++nIndex;
  581. }
  582. //
  583. // we have gathered all the text from this node
  584. //
  585. bSuccess = !csNodeText.IsEmpty();
  586. eh:
  587. if (NULL != pNodeList) {
  588. pNodeList->Release();
  589. }
  590. if (NULL != pNodeText) {
  591. pNodeText->Release();
  592. }
  593. return bSuccess;
  594. }
  595. ////////////////////////////////////////////////////////////////////////////////////
  596. //
  597. // Func: GetNodeName
  598. //
  599. // Desc: Returns the nodeName value from the specified node.
  600. //
  601. CString GetNodeName(
  602. IXMLDOMNode* pNode)
  603. {
  604. CString csName;
  605. BSTR bsName = NULL;
  606. if (SUCCEEDED(pNode->get_nodeName(&bsName))) {
  607. csName = bsName;
  608. }
  609. if (bsName)
  610. SysFreeString(bsName);
  611. //
  612. // If get_nodeName fails, then csName is blank.
  613. //
  614. return csName;
  615. }
  616. CString GetParentNodeName(
  617. IXMLDOMNode* pNode)
  618. {
  619. CString csName;
  620. IXMLDOMNodePtr cpParent;
  621. if (FAILED(pNode->get_parentNode(&cpParent))) {
  622. return CString();
  623. }
  624. return GetNodeName(cpParent);
  625. }
  626. ////////////////////////////////////////////////////////////////////////////////////
  627. //
  628. // Func: GetXML
  629. //
  630. // Desc: Returns the value of the xml property on node pNode.
  631. //
  632. CString GetXML(
  633. IXMLDOMNode* pNode)
  634. {
  635. CString csXML;
  636. BSTR bsXML = NULL;
  637. HRESULT hr;
  638. hr = pNode->get_xml(&bsXML);
  639. if (SUCCEEDED(hr)) {
  640. csXML = bsXML;
  641. if (bsXML) {
  642. SysFreeString(bsXML);
  643. }
  644. }
  645. //
  646. // If get_xml fails, then csXML is blank.
  647. //
  648. return csXML;
  649. }
  650. ////////////////////////////////////////////////////////////////////////////////////
  651. //
  652. // Func: MapStringToLangID
  653. //
  654. // Desc: Returns a LANGID corresponding to the passed in string.
  655. //
  656. LANGID MapStringToLangID(
  657. CString& csLang)
  658. {
  659. typedef struct _LANG_MAP {
  660. LPTSTR szLang;
  661. LANGID LangID;
  662. } LANG_MAP, *PLANG_MAP;
  663. static LANG_MAP s_LangMap[] = {
  664. { _T("usa"), MAKELANGID(LANG_ENGLISH,SUBLANG_ENGLISH_US) },
  665. { _T(""), NULL }
  666. };
  667. long i;
  668. BOOL bSuccess = FALSE;
  669. LANGID LangID = MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US);
  670. if (csLang.Left(2) == _T("0x") ||
  671. csLang.Left(2) == _T("0X")) {
  672. _stscanf(csLang, _T("0x%x"), &LangID);
  673. return LangID;
  674. }
  675. i = 0;
  676. while (TRUE) {
  677. if (s_LangMap[i].szLang[0] == _T('\0')) {
  678. //
  679. // End of map.
  680. //
  681. break;
  682. }
  683. if (0 == _tcsicmp(csLang, s_LangMap[i].szLang)) {
  684. //
  685. // Found string.
  686. //
  687. LangID = s_LangMap[i].LangID;
  688. bSuccess = TRUE;
  689. }
  690. if (bSuccess) {
  691. break;
  692. }
  693. i++;
  694. }
  695. if (!bSuccess) {
  696. //
  697. // Couldn't map it. Give a useful error; list all recognized values.
  698. //
  699. CString csError;
  700. CString csFormat;
  701. i = 0;
  702. csError = _T("LANG attribute on DATABASE is not one of recognized values:\n\n");
  703. while (TRUE) {
  704. if (s_LangMap[i].szLang[0] == _T('\0')) {
  705. break;
  706. }
  707. csFormat.Format(_T(" %s\n"), s_LangMap[i].szLang);
  708. csError += csFormat;
  709. i++;
  710. }
  711. SDBERROR(csError);
  712. }
  713. return LangID;
  714. }
  715. ////////////////////////////////////////////////////////////////////////////////////
  716. //
  717. // Func: AddAttribute
  718. //
  719. // Desc: Adds an attribute to the specified XML node.
  720. //
  721. BOOL AddAttribute(
  722. IXMLDOMNode* pNode,
  723. CString csAttribute,
  724. CString csValue)
  725. {
  726. USES_CONVERSION;
  727. BOOL bSuccess = FALSE;
  728. BSTR bsAttribute = NULL;
  729. VARIANT vType;
  730. VARIANT vValue;
  731. IXMLDOMDocumentPtr cpDocument;
  732. IXMLDOMNamedNodeMapPtr cpNodeMap;
  733. IXMLDOMNodePtr cpAttrNode;
  734. IXMLDOMNodePtr cpNamedAttr;
  735. VariantInit(&vType);
  736. VariantInit(&vValue);
  737. vValue.bstrVal = csValue.AllocSysString();
  738. if (vValue.bstrVal == NULL) {
  739. SDBERROR(_T("CString::AllocSysString failed"));
  740. goto eh;
  741. }
  742. vValue.vt = VT_BSTR;
  743. vType.vt = VT_I4;
  744. vType.lVal = NODE_ATTRIBUTE;
  745. bsAttribute = csAttribute.AllocSysString();
  746. if (bsAttribute == NULL) {
  747. SDBERROR(_T("CString::AllocSysString failed"));
  748. goto eh;
  749. }
  750. if (FAILED(pNode->get_ownerDocument(&cpDocument))) {
  751. SDBERROR(_T("createNode failed while adding attribute"));
  752. goto eh;
  753. }
  754. if (FAILED(cpDocument->createNode(vType, bsAttribute, NULL, &cpAttrNode))) {
  755. SDBERROR(_T("createNode failed while adding attribute"));
  756. goto eh;
  757. }
  758. if (FAILED(cpAttrNode->put_nodeValue(vValue))) {
  759. SDBERROR(_T("put_nodeValue failed while adding attribute"));
  760. goto eh;
  761. }
  762. if (FAILED(pNode->get_attributes(&cpNodeMap))) {
  763. SDBERROR(_T("get_attributes failed while adding adding attribute"));
  764. goto eh;
  765. }
  766. if (FAILED(cpNodeMap->setNamedItem(cpAttrNode, &cpNamedAttr))) {
  767. SDBERROR(_T("setNamedItem failed while adding adding attribute"));
  768. goto eh;
  769. }
  770. bSuccess = TRUE;
  771. eh:
  772. VariantClear(&vType);
  773. VariantClear(&vValue);
  774. if (bsAttribute != NULL) {
  775. SysFreeString(bsAttribute);
  776. }
  777. return bSuccess;
  778. }
  779. ////////////////////////////////////////////////////////////////////////////////////
  780. //
  781. // Func: GenerateIDAttribute
  782. //
  783. // Desc: Adds an ID attribute to the specified XML node. The ID is in the
  784. // traditional Windows GUID format.
  785. //
  786. BOOL GenerateIDAttribute(
  787. IXMLDOMNode* pNode,
  788. CString* pcsGuid,
  789. GUID* pGuid)
  790. {
  791. BOOL bSuccess = FALSE;
  792. BSTR bsGUID = NULL;
  793. GUID id;
  794. //
  795. // Generate guid
  796. //
  797. if (FAILED(CoCreateGuid(&id))) {
  798. SDBERROR(_T("CoCreateGuid failed"));
  799. goto eh;
  800. }
  801. if (NULL != pGuid) {
  802. *pGuid = id;
  803. }
  804. bsGUID = SysAllocStringLen(NULL, 64);
  805. if (bsGUID == NULL) {
  806. SDBERROR(_T("SysAllocStringLen failed"));
  807. goto eh;
  808. }
  809. StringFromGUID2(id, bsGUID, 64);
  810. if (!AddAttribute( pNode, _T("ID"), CString(bsGUID) )) {
  811. SDBERROR_PROPOGATE();
  812. goto eh;
  813. }
  814. *pcsGuid = bsGUID;
  815. bSuccess = TRUE;
  816. eh:
  817. if (bsGUID) {
  818. SysFreeString(bsGUID);
  819. }
  820. return bSuccess;
  821. }
  822. BOOL ReplaceXMLNode(IXMLDOMNode* pNode, IXMLDOMDocument* pDoc, BSTR bsText)
  823. {
  824. BOOL bSuccess = FALSE;
  825. IXMLDOMNodePtr cpNewTextNode;
  826. IXMLDOMNodePtr cpParentNode;
  827. IXMLDOMNodePtr cpOldNode;
  828. VARIANT vType;
  829. VariantInit(&vType);
  830. vType.vt = VT_I4;
  831. vType.lVal = NODE_TEXT;
  832. if (FAILED(pDoc->createNode(vType, NULL, NULL, &cpNewTextNode))) {
  833. SDBERROR(_T("createNode failed while adding attribute"));
  834. goto eh;
  835. }
  836. if (FAILED(cpNewTextNode->put_text(bsText))) {
  837. SDBERROR(_T("Could not set text property of object."));
  838. goto eh;
  839. }
  840. if (FAILED(pNode->get_parentNode(&cpParentNode))) {
  841. SDBERROR(_T("Could not retrieve parent node of object."));
  842. goto eh;
  843. }
  844. if (FAILED(cpParentNode->replaceChild(cpNewTextNode, pNode, &cpOldNode))) {
  845. SDBERROR(_T("Could not replace node with text node."));
  846. goto eh;
  847. }
  848. bSuccess = TRUE;
  849. eh:
  850. VariantClear(&vType);
  851. return bSuccess;
  852. }