aboutsummaryrefslogtreecommitdiff
path: root/src/dutil/xmlutil.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/dutil/xmlutil.cpp')
-rw-r--r--src/dutil/xmlutil.cpp1317
1 files changed, 1317 insertions, 0 deletions
diff --git a/src/dutil/xmlutil.cpp b/src/dutil/xmlutil.cpp
new file mode 100644
index 00000000..e07c205d
--- /dev/null
+++ b/src/dutil/xmlutil.cpp
@@ -0,0 +1,1317 @@
1// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information.
2
3#include "precomp.h"
4
5// intialization globals
6CLSID vclsidXMLDOM = { 0, 0, 0, { 0, 0, 0, 0, 0, 0, 0, 0} };
7static volatile LONG vcXmlInitialized = 0;
8static BOOL vfMsxml40 = FALSE;
9static BOOL fComInitialized = FALSE;
10BOOL vfMsxml30 = FALSE;
11
12/********************************************************************
13 XmlInitialize - finds an appropriate version of the XML DOM
14
15*********************************************************************/
16extern "C" HRESULT DAPI XmlInitialize(
17 )
18{
19 HRESULT hr = S_OK;
20
21 if (!fComInitialized)
22 {
23 hr = ::CoInitialize(0);
24 if (RPC_E_CHANGED_MODE != hr)
25 {
26 ExitOnFailure(hr, "failed to initialize COM");
27 fComInitialized = TRUE;
28 }
29 }
30
31 LONG cInitialized = ::InterlockedIncrement(&vcXmlInitialized);
32 if (1 == cInitialized)
33 {
34 // NOTE: 4.0 behaves differently than 3.0 so there may be problems doing this
35#if 0
36 hr = ::CLSIDFromProgID(L"Msxml2.DOMDocument.4.0", &vclsidXMLDOM);
37 if (S_OK == hr)
38 {
39 vfMsxml40 = TRUE;
40 Trace(REPORT_VERBOSE, "found Msxml2.DOMDocument.4.0");
41 ExitFunction();
42 }
43#endif
44 hr = ::CLSIDFromProgID(L"Msxml2.DOMDocument", &vclsidXMLDOM);
45 if (FAILED(hr))
46 {
47 // try to fall back to old MSXML
48 hr = ::CLSIDFromProgID(L"MSXML.DOMDocument", &vclsidXMLDOM);
49 }
50 ExitOnFailure(hr, "failed to get CLSID for XML DOM");
51
52 Assert(IsEqualCLSID(vclsidXMLDOM, XmlUtil_CLSID_DOMDocument) ||
53 IsEqualCLSID(vclsidXMLDOM, XmlUtil_CLSID_DOMDocument20) ||
54 IsEqualCLSID(vclsidXMLDOM, XmlUtil_CLSID_DOMDocument26) ||
55 IsEqualCLSID(vclsidXMLDOM, XmlUtil_CLSID_DOMDocument30) ||
56 IsEqualCLSID(vclsidXMLDOM, XmlUtil_CLSID_DOMDocument40) ||
57 IsEqualCLSID(vclsidXMLDOM, XmlUtil_CLSID_DOMDocument50) ||
58 IsEqualCLSID(vclsidXMLDOM, XmlUtil_CLSID_DOMDocument60));
59 }
60
61 hr = S_OK;
62LExit:
63 return hr;
64}
65
66
67/********************************************************************
68 XmUninitialize -
69
70*********************************************************************/
71extern "C" void DAPI XmlUninitialize(
72 )
73{
74 AssertSz(vcXmlInitialized, "XmlUninitialize called when not initialized");
75
76 LONG cInitialized = ::InterlockedDecrement(&vcXmlInitialized);
77
78 if (0 == cInitialized)
79 {
80 memset(&vclsidXMLDOM, 0, sizeof(vclsidXMLDOM));
81
82 if (fComInitialized)
83 {
84 ::CoUninitialize();
85 }
86 }
87}
88
89extern "C" HRESULT DAPI XmlCreateElement(
90 __in IXMLDOMDocument *pixdDocument,
91 __in_z LPCWSTR wzElementName,
92 __out IXMLDOMElement **ppixnElement
93 )
94{
95 if (!ppixnElement || !pixdDocument)
96 {
97 return E_INVALIDARG;
98 }
99
100 HRESULT hr = S_OK;
101 BSTR bstrElementName = ::SysAllocString(wzElementName);
102 ExitOnNull(bstrElementName, hr, E_OUTOFMEMORY, "failed SysAllocString");
103 hr = pixdDocument->createElement(bstrElementName, ppixnElement);
104LExit:
105 ReleaseBSTR(bstrElementName);
106 return hr;
107}
108
109
110/********************************************************************
111 XmlCreateDocument -
112
113*********************************************************************/
114extern "C" HRESULT DAPI XmlCreateDocument(
115 __in_opt LPCWSTR pwzElementName,
116 __out IXMLDOMDocument** ppixdDocument,
117 __out_opt IXMLDOMElement** ppixeRootElement
118 )
119{
120 HRESULT hr = S_OK;
121 BOOL (WINAPI *pfnDisableWow64)(__out PVOID* ) = NULL;
122 BOOLEAN (WINAPI *pfnEnableWow64)(__in BOOLEAN ) = NULL;
123 BOOL (WINAPI *pfnRevertWow64)(__in PVOID ) = NULL;
124 BOOL fWow64Available = FALSE;
125 void *pvWow64State = NULL;
126
127 // RELEASEME
128 IXMLDOMElement* pixeRootElement = NULL;
129 IXMLDOMDocument *pixdDocument = NULL;
130
131 // Test if we have access to the Wow64 API, and store the result in fWow64Available
132 HMODULE hKernel32 = ::GetModuleHandleA("kernel32.dll");
133 ExitOnNullWithLastError(hKernel32, hr, "failed to get handle to kernel32.dll");
134
135 // This will test if we have access to the Wow64 API
136 if (NULL != GetProcAddress(hKernel32, "IsWow64Process"))
137 {
138 pfnDisableWow64 = (BOOL (WINAPI *)(PVOID *))::GetProcAddress(hKernel32, "Wow64DisableWow64FsRedirection");
139 pfnEnableWow64 = (BOOLEAN (WINAPI *)(BOOLEAN))::GetProcAddress(hKernel32, "Wow64EnableWow64FsRedirection");
140 pfnRevertWow64 = (BOOL (WINAPI *)(PVOID))::GetProcAddress(hKernel32, "Wow64RevertWow64FsRedirection");
141
142 fWow64Available = pfnDisableWow64 && pfnEnableWow64 && pfnRevertWow64;
143 }
144
145 // create the top level XML document
146 AssertSz(vcXmlInitialized, "XmlInitialize() was not called");
147
148 // Enable Wow64 Redirection, if possible
149 if (fWow64Available)
150 {
151 // We want to enable Wow64 redirection, but the Wow64 API requires us to disable it first to get its current state (so we can revert it later)
152 pfnDisableWow64(&pvWow64State);
153 // If we fail to enable it, don't bother trying to disable it later on
154 fWow64Available = pfnEnableWow64(TRUE);
155 }
156
157 hr = ::CoCreateInstance(vclsidXMLDOM, NULL, CLSCTX_INPROC_SERVER, XmlUtil_IID_IXMLDOMDocument, (void**)&pixdDocument);
158 ExitOnFailure(hr, "failed to create XML DOM Document");
159 Assert(pixdDocument);
160
161 if (IsEqualCLSID(vclsidXMLDOM, XmlUtil_CLSID_DOMDocument30) || IsEqualCLSID(vclsidXMLDOM, XmlUtil_CLSID_DOMDocument20))
162 {
163 vfMsxml30 = TRUE;
164 }
165
166 if (pwzElementName)
167 {
168 hr = XmlCreateElement(pixdDocument, pwzElementName, &pixeRootElement);
169 ExitOnFailure(hr, "failed XmlCreateElement");
170 hr = pixdDocument->appendChild(pixeRootElement, NULL);
171 ExitOnFailure(hr, "failed appendChild");
172 }
173
174 *ppixdDocument = pixdDocument;
175 pixdDocument = NULL;
176
177 if (ppixeRootElement)
178 {
179 *ppixeRootElement = pixeRootElement;
180 pixeRootElement = NULL;
181 }
182
183LExit:
184 // Re-disable Wow64 Redirection, if appropriate
185 if (fWow64Available && !pfnRevertWow64(pvWow64State))
186 {
187 // If we expected to be able to revert, and couldn't, fail in the only graceful way we can
188 ::ExitProcess(1);
189 }
190
191 ReleaseObject(pixeRootElement);
192 ReleaseObject(pixdDocument);
193 return hr;
194}
195
196
197/********************************************************************
198 XmlLoadDocument -
199
200*********************************************************************/
201extern "C" HRESULT DAPI XmlLoadDocument(
202 __in_z LPCWSTR wzDocument,
203 __out IXMLDOMDocument** ppixdDocument
204 )
205{
206 return XmlLoadDocumentEx(wzDocument, 0, ppixdDocument);
207}
208
209
210/********************************************************************
211 XmlReportParseError -
212
213*********************************************************************/
214static void XmlReportParseError(
215 __in IXMLDOMParseError* pixpe
216 )
217{
218 HRESULT hr = S_OK;
219 long lNumber = 0;
220 BSTR bstr = NULL;
221
222 Trace(REPORT_STANDARD, "Failed to parse XML. IXMLDOMParseError reports:");
223
224 hr = pixpe->get_errorCode(&lNumber);
225 ExitOnFailure(hr, "Failed to query IXMLDOMParseError.errorCode.");
226 Trace(REPORT_STANDARD, "errorCode = 0x%x", lNumber);
227
228 hr = pixpe->get_filepos(&lNumber);
229 ExitOnFailure(hr, "Failed to query IXMLDOMParseError.filepos.");
230 Trace(REPORT_STANDARD, "filepos = %d", lNumber);
231
232 hr = pixpe->get_line(&lNumber);
233 ExitOnFailure(hr, "Failed to query IXMLDOMParseError.line.");
234 Trace(REPORT_STANDARD, "line = %d", lNumber);
235
236 hr = pixpe->get_linepos(&lNumber);
237 ExitOnFailure(hr, "Failed to query IXMLDOMParseError.linepos.");
238 Trace(REPORT_STANDARD, "linepos = %d", lNumber);
239
240 hr = pixpe->get_reason(&bstr);
241 ExitOnFailure(hr, "Failed to query IXMLDOMParseError.reason.");
242 Trace(REPORT_STANDARD, "reason = %ls", bstr);
243 ReleaseNullBSTR(bstr);
244
245 hr = pixpe->get_srcText (&bstr);
246 ExitOnFailure(hr, "Failed to query IXMLDOMParseError.srcText .");
247 Trace(REPORT_STANDARD, "srcText = %ls", bstr);
248 ReleaseNullBSTR(bstr);
249
250LExit:
251 ReleaseBSTR(bstr);
252}
253
254/********************************************************************
255 XmlLoadDocumentEx -
256
257*********************************************************************/
258extern "C" HRESULT DAPI XmlLoadDocumentEx(
259 __in_z LPCWSTR wzDocument,
260 __in DWORD dwAttributes,
261 __out IXMLDOMDocument** ppixdDocument
262 )
263{
264 HRESULT hr = S_OK;
265 VARIANT_BOOL vbSuccess = 0;
266
267 // RELEASEME
268 IXMLDOMDocument* pixd = NULL;
269 IXMLDOMParseError* pixpe = NULL;
270 BSTR bstrLoad = NULL;
271
272 if (!wzDocument || !*wzDocument)
273 {
274 hr = E_UNEXPECTED;
275 ExitOnFailure(hr, "string must be non-null");
276 }
277
278 hr = XmlCreateDocument(NULL, &pixd);
279 if (hr == S_FALSE)
280 {
281 hr = E_FAIL;
282 }
283 ExitOnFailure(hr, "failed XmlCreateDocument");
284
285 if (dwAttributes & XML_LOAD_PRESERVE_WHITESPACE)
286 {
287 hr = pixd->put_preserveWhiteSpace(VARIANT_TRUE);
288 ExitOnFailure(hr, "failed put_preserveWhiteSpace");
289 }
290
291 // Security issue. Avoid triggering anything external.
292 hr = pixd->put_validateOnParse(VARIANT_FALSE);
293 ExitOnFailure(hr, "failed put_validateOnParse");
294 hr = pixd->put_resolveExternals(VARIANT_FALSE);
295 ExitOnFailure(hr, "failed put_resolveExternals");
296
297 bstrLoad = ::SysAllocString(wzDocument);
298 ExitOnNull(bstrLoad, hr, E_OUTOFMEMORY, "failed to allocate bstr for Load in XmlLoadDocumentEx");
299
300 hr = pixd->loadXML(bstrLoad, &vbSuccess);
301 if (S_FALSE == hr)
302 {
303 hr = HRESULT_FROM_WIN32(ERROR_OPEN_FAILED);
304 }
305
306 if (FAILED(hr) && S_OK == pixd->get_parseError(&pixpe))
307 {
308 XmlReportParseError(pixpe);
309 }
310
311 ExitOnFailure(hr, "failed loadXML");
312
313
314 hr = S_OK;
315LExit:
316 if (ppixdDocument)
317 {
318 *ppixdDocument = pixd;
319 pixd = NULL;
320 }
321 ReleaseBSTR(bstrLoad);
322 ReleaseObject(pixd);
323 ReleaseObject(pixpe);
324
325 return hr;
326}
327
328
329/*******************************************************************
330 XmlLoadDocumentFromFile
331
332********************************************************************/
333extern "C" HRESULT DAPI XmlLoadDocumentFromFile(
334 __in_z LPCWSTR wzPath,
335 __out IXMLDOMDocument** ppixdDocument
336 )
337{
338 return XmlLoadDocumentFromFileEx(wzPath, 0, ppixdDocument);
339}
340
341
342/*******************************************************************
343 XmlLoadDocumentFromFileEx
344
345********************************************************************/
346extern "C" HRESULT DAPI XmlLoadDocumentFromFileEx(
347 __in_z LPCWSTR wzPath,
348 __in DWORD dwAttributes,
349 __out IXMLDOMDocument** ppixdDocument
350 )
351{
352 HRESULT hr = S_OK;
353 VARIANT varPath;
354 VARIANT_BOOL vbSuccess = 0;
355
356 IXMLDOMDocument* pixd = NULL;
357 IXMLDOMParseError* pixpe = NULL;
358
359 ::VariantInit(&varPath);
360 varPath.vt = VT_BSTR;
361 varPath.bstrVal = ::SysAllocString(wzPath);
362 ExitOnNull(varPath.bstrVal, hr, E_OUTOFMEMORY, "failed to allocate bstr for Path in XmlLoadDocumentFromFileEx");
363
364 hr = XmlCreateDocument(NULL, &pixd);
365 if (hr == S_FALSE)
366 {
367 hr = E_FAIL;
368 }
369 ExitOnFailure(hr, "failed XmlCreateDocument");
370
371 if (dwAttributes & XML_LOAD_PRESERVE_WHITESPACE)
372 {
373 hr = pixd->put_preserveWhiteSpace(VARIANT_TRUE);
374 ExitOnFailure(hr, "failed put_preserveWhiteSpace");
375 }
376
377 // Avoid triggering anything external.
378 hr = pixd->put_validateOnParse(VARIANT_FALSE);
379 ExitOnFailure(hr, "failed put_validateOnParse");
380 hr = pixd->put_resolveExternals(VARIANT_FALSE);
381 ExitOnFailure(hr, "failed put_resolveExternals");
382
383 pixd->put_async(VARIANT_FALSE);
384 hr = pixd->load(varPath, &vbSuccess);
385 if (S_FALSE == hr)
386 {
387 hr = HRESULT_FROM_WIN32(ERROR_OPEN_FAILED);
388 }
389
390 if (FAILED(hr) && S_OK == pixd->get_parseError(&pixpe))
391 {
392 XmlReportParseError(pixpe);
393 }
394
395 ExitOnFailure(hr, "failed to load XML from: %ls", wzPath);
396
397 if (ppixdDocument)
398 {
399 *ppixdDocument = pixd;
400 pixd = NULL;
401 }
402
403 hr = S_OK;
404LExit:
405 ReleaseVariant(varPath);
406 ReleaseObject(pixd);
407 ReleaseObject(pixpe);
408
409 return hr;
410}
411
412
413/********************************************************************
414 XmlLoadDocumentFromBuffer
415
416*********************************************************************/
417extern "C" HRESULT DAPI XmlLoadDocumentFromBuffer(
418 __in_bcount(cbSource) const BYTE* pbSource,
419 __in DWORD cbSource,
420 __out IXMLDOMDocument** ppixdDocument
421 )
422{
423 HRESULT hr = S_OK;
424 IXMLDOMDocument* pixdDocument = NULL;
425 SAFEARRAY sa = { };
426 VARIANT vtXmlSource;
427 VARIANT_BOOL vbSuccess = 0;
428
429 ::VariantInit(&vtXmlSource);
430
431 // create document
432 hr = XmlCreateDocument(NULL, &pixdDocument);
433 if (hr == S_FALSE)
434 {
435 hr = E_FAIL;
436 }
437 ExitOnFailure(hr, "failed XmlCreateDocument");
438
439 // Security issue. Avoid triggering anything external.
440 hr = pixdDocument->put_validateOnParse(VARIANT_FALSE);
441 ExitOnFailure(hr, "failed put_validateOnParse");
442 hr = pixdDocument->put_resolveExternals(VARIANT_FALSE);
443 ExitOnFailure(hr, "failed put_resolveExternals");
444
445 // load document
446 sa.cDims = 1;
447 sa.fFeatures = FADF_STATIC | FADF_FIXEDSIZE;
448 sa.cbElements = 1;
449 sa.pvData = (PVOID)pbSource;
450 sa.rgsabound[0].cElements = cbSource;
451 vtXmlSource.vt = VT_ARRAY | VT_UI1;
452 vtXmlSource.parray = &sa;
453
454 hr = pixdDocument->load(vtXmlSource, &vbSuccess);
455 if (S_FALSE == hr)
456 {
457 hr = HRESULT_FROM_WIN32(ERROR_OPEN_FAILED);
458 }
459 ExitOnFailure(hr, "failed loadXML");
460
461 // return value
462 *ppixdDocument = pixdDocument;
463 pixdDocument = NULL;
464
465LExit:
466 ReleaseObject(pixdDocument);
467 return hr;
468}
469
470
471/********************************************************************
472 XmlSetAttribute -
473
474*********************************************************************/
475extern "C" HRESULT DAPI XmlSetAttribute(
476 __in IXMLDOMNode* pixnNode,
477 __in_z LPCWSTR pwzAttribute,
478 __in_z LPCWSTR pwzAttributeValue
479 )
480{
481 HRESULT hr = S_OK;
482 VARIANT varAttributeValue;
483 ::VariantInit(&varAttributeValue);
484
485 // RELEASEME
486 IXMLDOMDocument* pixdDocument = NULL;
487 IXMLDOMNamedNodeMap* pixnnmAttributes = NULL;
488 IXMLDOMAttribute* pixaAttribute = NULL;
489 IXMLDOMNode* pixaNode = NULL;
490 BSTR bstrAttributeName = ::SysAllocString(pwzAttribute);
491 ExitOnNull(bstrAttributeName, hr, E_OUTOFMEMORY, "failed to allocate bstr for AttributeName in XmlSetAttribute");
492
493 hr = pixnNode->get_attributes(&pixnnmAttributes);
494 ExitOnFailure(hr, "failed get_attributes in XmlSetAttribute(%ls)", pwzAttribute);
495
496 hr = pixnNode->get_ownerDocument(&pixdDocument);
497 if (hr == S_FALSE)
498 {
499 hr = E_FAIL;
500 }
501 ExitOnFailure(hr, "failed get_ownerDocument in XmlSetAttribute");
502
503 hr = pixdDocument->createAttribute(bstrAttributeName, &pixaAttribute);
504 ExitOnFailure(hr, "failed createAttribute in XmlSetAttribute(%ls)", pwzAttribute);
505
506 varAttributeValue.vt = VT_BSTR;
507 varAttributeValue.bstrVal = ::SysAllocString(pwzAttributeValue);
508 if (!varAttributeValue.bstrVal)
509 {
510 hr = HRESULT_FROM_WIN32(ERROR_OUTOFMEMORY);
511 }
512 ExitOnFailure(hr, "failed SysAllocString in XmlSetAttribute");
513
514 hr = pixaAttribute->put_nodeValue(varAttributeValue);
515 ExitOnFailure(hr, "failed put_nodeValue in XmlSetAttribute(%ls)", pwzAttribute);
516
517 hr = pixnnmAttributes->setNamedItem(pixaAttribute, &pixaNode);
518 ExitOnFailure(hr, "failed setNamedItem in XmlSetAttribute(%ls)", pwzAttribute);
519
520LExit:
521 ReleaseObject(pixdDocument);
522 ReleaseObject(pixnnmAttributes);
523 ReleaseObject(pixaAttribute);
524 ReleaseObject(pixaNode);
525 ReleaseBSTR(varAttributeValue.bstrVal);
526 ReleaseBSTR(bstrAttributeName);
527
528 return hr;
529}
530
531
532/********************************************************************
533 XmlSelectSingleNode -
534
535*********************************************************************/
536extern "C" HRESULT DAPI XmlSelectSingleNode(
537 __in IXMLDOMNode* pixnParent,
538 __in_z LPCWSTR wzXPath,
539 __out IXMLDOMNode **ppixnChild
540 )
541{
542 HRESULT hr = S_OK;
543
544 BSTR bstrXPath = NULL;
545
546 ExitOnNull(pixnParent, hr, E_UNEXPECTED, "pixnParent parameter was null in XmlSelectSingleNode");
547 ExitOnNull(ppixnChild, hr, E_UNEXPECTED, "ppixnChild parameter was null in XmlSelectSingleNode");
548
549 bstrXPath = ::SysAllocString(wzXPath ? wzXPath : L"");
550 ExitOnNull(bstrXPath, hr, E_OUTOFMEMORY, "failed to allocate bstr for XPath expression in XmlSelectSingleNode");
551
552 hr = pixnParent->selectSingleNode(bstrXPath, ppixnChild);
553
554LExit:
555 ReleaseBSTR(bstrXPath);
556
557 return hr;
558}
559
560
561/********************************************************************
562 XmlCreateTextNode -
563
564*********************************************************************/
565extern "C" HRESULT DAPI XmlCreateTextNode(
566 __in IXMLDOMDocument *pixdDocument,
567 __in_z LPCWSTR wzText,
568 __out IXMLDOMText **ppixnTextNode
569 )
570{
571 if (!ppixnTextNode || !pixdDocument)
572 {
573 return E_INVALIDARG;
574 }
575
576 HRESULT hr = S_OK;
577 BSTR bstrText = ::SysAllocString(wzText);
578 ExitOnNull(bstrText, hr, E_OUTOFMEMORY, "failed SysAllocString");
579 hr = pixdDocument->createTextNode(bstrText, ppixnTextNode);
580LExit:
581 ReleaseBSTR(bstrText);
582
583 return hr;
584}
585
586
587/********************************************************************
588 XmlGetText
589
590*********************************************************************/
591extern "C" HRESULT DAPI XmlGetText(
592 __in IXMLDOMNode* pixnNode,
593 __deref_out_z BSTR* pbstrText
594 )
595{
596 return pixnNode->get_text(pbstrText);
597}
598
599
600/********************************************************************
601 XmlGetAttribute
602
603*********************************************************************/
604extern "C" HRESULT DAPI XmlGetAttribute(
605 __in IXMLDOMNode* pixnNode,
606 __in_z LPCWSTR pwzAttribute,
607 __deref_out_z BSTR* pbstrAttributeValue
608 )
609{
610 Assert(pixnNode);
611 HRESULT hr = S_OK;
612
613 // RELEASEME
614 IXMLDOMNamedNodeMap* pixnnmAttributes = NULL;
615 IXMLDOMNode* pixnAttribute = NULL;
616 VARIANT varAttributeValue;
617 BSTR bstrAttribute = SysAllocString(pwzAttribute);
618
619 // INIT
620 ::VariantInit(&varAttributeValue);
621
622 // get attribute value from source
623 hr = pixnNode->get_attributes(&pixnnmAttributes);
624 ExitOnFailure(hr, "failed get_attributes");
625
626 hr = XmlGetNamedItem(pixnnmAttributes, bstrAttribute, &pixnAttribute);
627 if (S_FALSE == hr)
628 {
629 // hr = E_FAIL;
630 ExitFunction();
631 }
632 ExitOnFailure(hr, "failed getNamedItem in XmlGetAttribute(%ls)", pwzAttribute);
633
634 hr = pixnAttribute->get_nodeValue(&varAttributeValue);
635 ExitOnFailure(hr, "failed get_nodeValue in XmlGetAttribute(%ls)", pwzAttribute);
636
637 // steal the BSTR from the VARIANT
638 if (S_OK == hr && pbstrAttributeValue)
639 {
640 *pbstrAttributeValue = varAttributeValue.bstrVal;
641 varAttributeValue.bstrVal = NULL;
642 }
643
644LExit:
645 ReleaseObject(pixnnmAttributes);
646 ReleaseObject(pixnAttribute);
647 ReleaseVariant(varAttributeValue);
648 ReleaseBSTR(bstrAttribute);
649
650 return hr;
651}
652
653
654/********************************************************************
655 XmlGetAttributeEx
656
657*********************************************************************/
658HRESULT DAPI XmlGetAttributeEx(
659 __in IXMLDOMNode* pixnNode,
660 __in_z LPCWSTR wzAttribute,
661 __deref_out_z LPWSTR* psczAttributeValue
662 )
663{
664 Assert(pixnNode);
665 HRESULT hr = S_OK;
666 IXMLDOMNamedNodeMap* pixnnmAttributes = NULL;
667 IXMLDOMNode* pixnAttribute = NULL;
668 VARIANT varAttributeValue;
669 BSTR bstrAttribute = NULL;
670
671 ::VariantInit(&varAttributeValue);
672
673 // get attribute value from source
674 hr = pixnNode->get_attributes(&pixnnmAttributes);
675 ExitOnFailure(hr, "Failed get_attributes.");
676
677 bstrAttribute = ::SysAllocString(wzAttribute);
678 ExitOnNull(bstrAttribute, hr, E_OUTOFMEMORY, "Failed to allocate attribute name BSTR.");
679
680 hr = XmlGetNamedItem(pixnnmAttributes, bstrAttribute, &pixnAttribute);
681 if (S_FALSE == hr)
682 {
683 ExitFunction1(hr = E_NOTFOUND);
684 }
685 ExitOnFailure(hr, "Failed getNamedItem in XmlGetAttribute(%ls)", wzAttribute);
686
687 hr = pixnAttribute->get_nodeValue(&varAttributeValue);
688 if (S_FALSE == hr)
689 {
690 ExitFunction1(hr = E_NOTFOUND);
691 }
692 ExitOnFailure(hr, "Failed get_nodeValue in XmlGetAttribute(%ls)", wzAttribute);
693
694 // copy value
695 hr = StrAllocString(psczAttributeValue, varAttributeValue.bstrVal, 0);
696 ExitOnFailure(hr, "Failed to copy attribute value.");
697
698LExit:
699 ReleaseObject(pixnnmAttributes);
700 ReleaseObject(pixnAttribute);
701 ReleaseVariant(varAttributeValue);
702 ReleaseBSTR(bstrAttribute);
703
704 return hr;
705}
706
707
708/********************************************************************
709 XmlGetYesNoAttribute
710
711*********************************************************************/
712HRESULT DAPI XmlGetYesNoAttribute(
713 __in IXMLDOMNode* pixnNode,
714 __in_z LPCWSTR wzAttribute,
715 __out BOOL* pfYes
716 )
717{
718 HRESULT hr = S_OK;
719 LPWSTR sczValue = NULL;
720
721 hr = XmlGetAttributeEx(pixnNode, wzAttribute, &sczValue);
722 if (E_NOTFOUND != hr)
723 {
724 ExitOnFailure(hr, "Failed to get attribute.");
725
726 *pfYes = CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, 0, sczValue, -1, L"yes", -1);
727 }
728
729LExit:
730 ReleaseStr(sczValue);
731
732 return hr;
733}
734
735
736
737/********************************************************************
738 XmlGetAttributeNumber
739
740*********************************************************************/
741extern "C" HRESULT DAPI XmlGetAttributeNumber(
742 __in IXMLDOMNode* pixnNode,
743 __in_z LPCWSTR pwzAttribute,
744 __out DWORD* pdwValue
745 )
746{
747 HRESULT hr = XmlGetAttributeNumberBase(pixnNode, pwzAttribute, 10, pdwValue);
748 return hr;
749}
750
751
752/********************************************************************
753 XmlGetAttributeNumberBase
754
755*********************************************************************/
756extern "C" HRESULT DAPI XmlGetAttributeNumberBase(
757 __in IXMLDOMNode* pixnNode,
758 __in_z LPCWSTR pwzAttribute,
759 __in int nBase,
760 __out DWORD* pdwValue
761 )
762{
763 HRESULT hr = S_OK;
764 BSTR bstrPointer = NULL;
765
766 hr = XmlGetAttribute(pixnNode, pwzAttribute, &bstrPointer);
767 ExitOnFailure(hr, "Failed to get value from attribute.");
768
769 if (S_OK == hr)
770 {
771 *pdwValue = wcstoul(bstrPointer, NULL, nBase);
772 }
773
774LExit:
775 ReleaseBSTR(bstrPointer);
776 return hr;
777}
778
779
780/********************************************************************
781 XmlGetAttributeLargeNumber
782
783*********************************************************************/
784extern "C" HRESULT DAPI XmlGetAttributeLargeNumber(
785 __in IXMLDOMNode* pixnNode,
786 __in_z LPCWSTR pwzAttribute,
787 __out DWORD64* pdw64Value
788 )
789{
790 HRESULT hr = S_OK;
791 BSTR bstrValue = NULL;
792
793 hr = XmlGetAttribute(pixnNode, pwzAttribute, &bstrValue);
794 ExitOnFailure(hr, "failed XmlGetAttribute");
795
796 if (S_OK == hr)
797 {
798 LONGLONG ll = 0;
799 hr = StrStringToInt64(bstrValue, 0, &ll);
800 ExitOnFailure(hr, "Failed to treat attribute value as number.");
801
802 *pdw64Value = ll;
803 }
804 else
805 {
806 *pdw64Value = 0;
807 }
808
809LExit:
810 ReleaseBSTR(bstrValue);
811 return hr;
812}
813
814
815/********************************************************************
816 XmlGetNamedItem -
817
818*********************************************************************/
819extern "C" HRESULT DAPI XmlGetNamedItem(
820 __in IXMLDOMNamedNodeMap *pixnmAttributes,
821 __in_opt LPCWSTR wzName,
822 __out IXMLDOMNode **ppixnNamedItem
823 )
824{
825 if (!pixnmAttributes || !ppixnNamedItem)
826 {
827 return E_INVALIDARG;
828 }
829
830 HRESULT hr = S_OK;
831 BSTR bstrName = ::SysAllocString(wzName);
832 ExitOnNull(bstrName, hr, E_OUTOFMEMORY, "failed SysAllocString");
833
834 hr = pixnmAttributes->getNamedItem(bstrName, ppixnNamedItem);
835
836LExit:
837 ReleaseBSTR(bstrName);
838 return hr;
839}
840
841
842/********************************************************************
843 XmlSetText -
844
845*********************************************************************/
846extern "C" HRESULT DAPI XmlSetText(
847 __in IXMLDOMNode *pixnNode,
848 __in_z LPCWSTR pwzText
849 )
850{
851 Assert(pixnNode && pwzText);
852 HRESULT hr = S_OK;
853 DOMNodeType dnType;
854
855 // RELEASEME
856 IXMLDOMDocument* pixdDocument = NULL;
857 IXMLDOMNodeList* pixnlNodeList = NULL;
858 IXMLDOMNode* pixnChildNode = NULL;
859 IXMLDOMText* pixtTextNode = NULL;
860 VARIANT varText;
861
862 ::VariantInit(&varText);
863
864 // find the text node
865 hr = pixnNode->get_childNodes(&pixnlNodeList);
866 ExitOnFailure(hr, "failed to get child nodes");
867
868 while (S_OK == (hr = pixnlNodeList->nextNode(&pixnChildNode)))
869 {
870 hr = pixnChildNode->get_nodeType(&dnType);
871 ExitOnFailure(hr, "failed to get node type");
872
873 if (NODE_TEXT == dnType)
874 break;
875 ReleaseNullObject(pixnChildNode);
876 }
877 if (S_FALSE == hr)
878 {
879 hr = S_OK;
880 }
881
882 if (pixnChildNode)
883 {
884 varText.vt = VT_BSTR;
885 varText.bstrVal = ::SysAllocString(pwzText);
886 if (!varText.bstrVal)
887 {
888 hr = HRESULT_FROM_WIN32(ERROR_OUTOFMEMORY);
889 }
890 ExitOnFailure(hr, "failed SysAllocString in XmlSetText");
891
892 hr = pixnChildNode->put_nodeValue(varText);
893 ExitOnFailure(hr, "failed IXMLDOMNode::put_nodeValue");
894 }
895 else
896 {
897 hr = pixnNode->get_ownerDocument(&pixdDocument);
898 if (hr == S_FALSE)
899 {
900 hr = E_FAIL;
901 }
902 ExitOnFailure(hr, "failed get_ownerDocument in XmlSetAttribute");
903
904 hr = XmlCreateTextNode(pixdDocument, pwzText, &pixtTextNode);
905 ExitOnFailure(hr, "failed createTextNode in XmlSetText(%ls)", pwzText);
906
907 hr = pixnNode->appendChild(pixtTextNode, NULL);
908 ExitOnFailure(hr, "failed appendChild in XmlSetText(%ls)", pwzText);
909 }
910
911 hr = *pwzText ? S_OK : S_FALSE;
912
913LExit:
914 ReleaseObject(pixnlNodeList);
915 ReleaseObject(pixnChildNode);
916 ReleaseObject(pixdDocument);
917 ReleaseObject(pixtTextNode);
918 ReleaseVariant(varText);
919 return hr;
920}
921
922
923/********************************************************************
924 XmlSetTextNumber -
925
926*********************************************************************/
927extern "C" HRESULT DAPI XmlSetTextNumber(
928 __in IXMLDOMNode *pixnNode,
929 __in DWORD dwValue
930 )
931{
932 HRESULT hr = S_OK;
933 WCHAR wzValue[12];
934
935 hr = ::StringCchPrintfW(wzValue, countof(wzValue), L"%u", dwValue);
936 ExitOnFailure(hr, "Failed to format numeric value as string.");
937
938 hr = XmlSetText(pixnNode, wzValue);
939
940LExit:
941 return hr;
942}
943
944
945/********************************************************************
946 XmlCreateChild -
947
948*********************************************************************/
949extern "C" HRESULT DAPI XmlCreateChild(
950 __in IXMLDOMNode* pixnParent,
951 __in_z LPCWSTR pwzElementType,
952 __out IXMLDOMNode** ppixnChild
953 )
954{
955 HRESULT hr = S_OK;
956
957 // RELEASEME
958 IXMLDOMDocument* pixdDocument = NULL;
959 IXMLDOMNode* pixnChild = NULL;
960
961 hr = pixnParent->get_ownerDocument(&pixdDocument);
962 if (hr == S_FALSE)
963 {
964 hr = E_FAIL;
965 }
966 ExitOnFailure(hr, "failed get_ownerDocument");
967
968 hr = XmlCreateElement(pixdDocument, pwzElementType, (IXMLDOMElement**) &pixnChild);
969 if (hr == S_FALSE)
970 {
971 hr = E_FAIL;
972 }
973 ExitOnFailure(hr, "failed createElement");
974
975 pixnParent->appendChild(pixnChild,NULL);
976 if (hr == S_FALSE)
977 {
978 hr = E_FAIL;
979 }
980 ExitOnFailure(hr, "failed appendChild");
981
982 if (ppixnChild)
983 {
984 *ppixnChild = pixnChild;
985 pixnChild = NULL;
986 }
987
988LExit:
989 ReleaseObject(pixdDocument);
990 ReleaseObject(pixnChild);
991 return hr;
992}
993
994/********************************************************************
995 XmlRemoveAttribute -
996
997*********************************************************************/
998extern "C" HRESULT DAPI XmlRemoveAttribute(
999 __in IXMLDOMNode* pixnNode,
1000 __in_z LPCWSTR pwzAttribute
1001 )
1002{
1003 HRESULT hr = S_OK;
1004
1005 // RELEASEME
1006 IXMLDOMNamedNodeMap* pixnnmAttributes = NULL;
1007 BSTR bstrAttribute = ::SysAllocString(pwzAttribute);
1008 ExitOnNull(bstrAttribute, hr, E_OUTOFMEMORY, "failed to allocate bstr for attribute in XmlRemoveAttribute");
1009
1010 hr = pixnNode->get_attributes(&pixnnmAttributes);
1011 ExitOnFailure(hr, "failed get_attributes in RemoveXmlAttribute(%ls)", pwzAttribute);
1012
1013 hr = pixnnmAttributes->removeNamedItem(bstrAttribute, NULL);
1014 ExitOnFailure(hr, "failed removeNamedItem in RemoveXmlAttribute(%ls)", pwzAttribute);
1015
1016LExit:
1017 ReleaseObject(pixnnmAttributes);
1018 ReleaseBSTR(bstrAttribute);
1019
1020 return hr;
1021}
1022
1023
1024/********************************************************************
1025 XmlSelectNodes -
1026
1027*********************************************************************/
1028extern "C" HRESULT DAPI XmlSelectNodes(
1029 __in IXMLDOMNode* pixnParent,
1030 __in_z LPCWSTR wzXPath,
1031 __out IXMLDOMNodeList **ppixnlChildren
1032 )
1033{
1034 HRESULT hr = S_OK;
1035
1036 BSTR bstrXPath = NULL;
1037
1038 ExitOnNull(pixnParent, hr, E_UNEXPECTED, "pixnParent parameter was null in XmlSelectNodes");
1039 ExitOnNull(ppixnlChildren, hr, E_UNEXPECTED, "ppixnChild parameter was null in XmlSelectNodes");
1040
1041 bstrXPath = ::SysAllocString(wzXPath ? wzXPath : L"");
1042 ExitOnNull(bstrXPath, hr, E_OUTOFMEMORY, "failed to allocate bstr for XPath expression in XmlSelectNodes");
1043
1044 hr = pixnParent->selectNodes(bstrXPath, ppixnlChildren);
1045
1046LExit:
1047 ReleaseBSTR(bstrXPath);
1048 return hr;
1049}
1050
1051
1052/********************************************************************
1053 XmlNextAttribute - returns the next attribute in a node list
1054
1055 NOTE: pbstrAttribute is optional
1056 returns S_OK if found an element
1057 returns S_FALSE if no element found
1058 returns E_* if something went wrong
1059********************************************************************/
1060extern "C" HRESULT DAPI XmlNextAttribute(
1061 __in IXMLDOMNamedNodeMap* pixnnm,
1062 __out IXMLDOMNode** pixnAttribute,
1063 __deref_opt_out_z_opt BSTR* pbstrAttribute
1064 )
1065{
1066 Assert(pixnnm && pixnAttribute);
1067
1068 HRESULT hr = S_OK;
1069 IXMLDOMNode* pixn = NULL;
1070 DOMNodeType nt;
1071
1072 // null out the return values
1073 *pixnAttribute = NULL;
1074 if (pbstrAttribute)
1075 {
1076 *pbstrAttribute = NULL;
1077 }
1078
1079 hr = pixnnm->nextNode(&pixn);
1080 ExitOnFailure(hr, "Failed to get next attribute.");
1081
1082 if (S_OK == hr)
1083 {
1084 hr = pixn->get_nodeType(&nt);
1085 ExitOnFailure(hr, "failed to get node type");
1086
1087 if (NODE_ATTRIBUTE != nt)
1088 {
1089 hr = E_UNEXPECTED;
1090 ExitOnFailure(hr, "Failed to get expected node type back: attribute");
1091 }
1092
1093 // if the caller asked for the attribute name
1094 if (pbstrAttribute)
1095 {
1096 hr = pixn->get_baseName(pbstrAttribute);
1097 ExitOnFailure(hr, "failed to get attribute name");
1098 }
1099
1100 *pixnAttribute = pixn;
1101 pixn = NULL;
1102 }
1103
1104LExit:
1105 ReleaseObject(pixn);
1106 return hr;
1107}
1108
1109
1110/********************************************************************
1111 XmlNextElement - returns the next element in a node list
1112
1113 NOTE: pbstrElement is optional
1114 returns S_OK if found an element
1115 returns S_FALSE if no element found
1116 returns E_* if something went wrong
1117********************************************************************/
1118extern "C" HRESULT DAPI XmlNextElement(
1119 __in IXMLDOMNodeList* pixnl,
1120 __out IXMLDOMNode** pixnElement,
1121 __deref_opt_out_z_opt BSTR* pbstrElement
1122 )
1123{
1124 Assert(pixnl && pixnElement);
1125
1126 HRESULT hr = S_OK;
1127 IXMLDOMNode* pixn = NULL;
1128 DOMNodeType nt;
1129
1130 // null out the return values
1131 *pixnElement = NULL;
1132 if (pbstrElement)
1133 {
1134 *pbstrElement = NULL;
1135 }
1136
1137 //
1138 // find the next element in the list
1139 //
1140 while (S_OK == (hr = pixnl->nextNode(&pixn)))
1141 {
1142 hr = pixn->get_nodeType(&nt);
1143 ExitOnFailure(hr, "failed to get node type");
1144
1145 if (NODE_ELEMENT == nt)
1146 break;
1147
1148 ReleaseNullObject(pixn);
1149 }
1150 ExitOnFailure(hr, "failed to get next element");
1151
1152 // if we have a node and the caller asked for the element name
1153 if (pixn && pbstrElement)
1154 {
1155 hr = pixn->get_baseName(pbstrElement);
1156 ExitOnFailure(hr, "failed to get element name");
1157 }
1158
1159 *pixnElement = pixn;
1160 pixn = NULL;
1161
1162 hr = *pixnElement ? S_OK : S_FALSE;
1163LExit:
1164 ReleaseObject(pixn);
1165 return hr;
1166}
1167
1168
1169/********************************************************************
1170 XmlRemoveChildren -
1171
1172*********************************************************************/
1173extern "C" HRESULT DAPI XmlRemoveChildren(
1174 __in IXMLDOMNode* pixnSource,
1175 __in_z LPCWSTR pwzXPath
1176 )
1177{
1178 HRESULT hr = S_OK;
1179
1180 // RELEASEME
1181 IXMLDOMNodeList* pixnlNodeList = NULL;
1182 IXMLDOMNode* pixnNode = NULL;
1183 IXMLDOMNode* pixnRemoveChild = NULL;
1184
1185 if (pwzXPath)
1186 {
1187 hr = XmlSelectNodes(pixnSource, pwzXPath, &pixnlNodeList);
1188 ExitOnFailure(hr, "failed XmlSelectNodes");
1189 }
1190 else
1191 {
1192 hr = pixnSource->get_childNodes(&pixnlNodeList);
1193 ExitOnFailure(hr, "failed childNodes");
1194 }
1195 if (S_FALSE == hr)
1196 {
1197 ExitFunction();
1198 }
1199
1200 while (S_OK == (hr = pixnlNodeList->nextNode(&pixnNode)))
1201 {
1202 hr = pixnSource->removeChild(pixnNode, &pixnRemoveChild);
1203 ExitOnFailure(hr, "failed removeChild");
1204
1205 ReleaseNullObject(pixnRemoveChild);
1206 ReleaseNullObject(pixnNode);
1207 }
1208 if (S_FALSE == hr)
1209 {
1210 hr = S_OK;
1211 }
1212
1213LExit:
1214 ReleaseObject(pixnlNodeList);
1215 ReleaseObject(pixnNode);
1216 ReleaseObject(pixnRemoveChild);
1217
1218 return hr;
1219}
1220
1221
1222/********************************************************************
1223 XmlSaveDocument -
1224
1225*********************************************************************/
1226extern "C" HRESULT DAPI XmlSaveDocument(
1227 __in IXMLDOMDocument* pixdDocument,
1228 __inout LPCWSTR wzPath
1229 )
1230{
1231 HRESULT hr = S_OK;
1232
1233 // RELEASEME
1234 VARIANT varsDestPath;
1235
1236 ::VariantInit(&varsDestPath);
1237 varsDestPath.vt = VT_BSTR;
1238 varsDestPath.bstrVal = ::SysAllocString(wzPath);
1239 if (!varsDestPath.bstrVal)
1240 {
1241 hr = HRESULT_FROM_WIN32(ERROR_OUTOFMEMORY);
1242 }
1243 ExitOnFailure(hr, "failed to create BSTR");
1244
1245 hr = pixdDocument->save(varsDestPath);
1246 if (hr == S_FALSE)
1247 {
1248 hr = E_FAIL;
1249 }
1250 ExitOnFailure(hr, "failed save in WriteDocument");
1251
1252LExit:
1253 ReleaseVariant(varsDestPath);
1254 return hr;
1255}
1256
1257
1258/********************************************************************
1259 XmlSaveDocumentToBuffer
1260
1261*********************************************************************/
1262extern "C" HRESULT DAPI XmlSaveDocumentToBuffer(
1263 __in IXMLDOMDocument* pixdDocument,
1264 __deref_out_bcount(*pcbDest) BYTE** ppbDest,
1265 __out DWORD* pcbDest
1266 )
1267{
1268 HRESULT hr = S_OK;
1269 IStream* pStream = NULL;
1270 LARGE_INTEGER li = { };
1271 STATSTG statstg = { };
1272 BYTE* pbDest = NULL;
1273 ULONG cbRead = 0;
1274 VARIANT vtDestination;
1275
1276 ::VariantInit(&vtDestination);
1277
1278 // create stream
1279 hr = ::CreateStreamOnHGlobal(NULL, TRUE, &pStream);
1280 ExitOnFailure(hr, "Failed to create stream.");
1281
1282 // write document to stream
1283 vtDestination.vt = VT_UNKNOWN;
1284 vtDestination.punkVal = (IUnknown*)pStream;
1285 hr = pixdDocument->save(vtDestination);
1286 ExitOnFailure(hr, "Failed to save document.");
1287
1288 // get stream size
1289 hr = pStream->Stat(&statstg, STATFLAG_NONAME);
1290 ExitOnFailure(hr, "Failed to get stream size.");
1291
1292 // allocate buffer
1293 pbDest = static_cast<BYTE*>(MemAlloc((SIZE_T)statstg.cbSize.LowPart, TRUE));
1294 ExitOnNull(pbDest, hr, E_OUTOFMEMORY, "Failed to allocate destination buffer.");
1295
1296 // read data from stream
1297 li.QuadPart = 0;
1298 hr = pStream->Seek(li, STREAM_SEEK_SET, NULL);
1299 ExitOnFailure(hr, "Failed to seek stream.");
1300
1301 hr = pStream->Read(pbDest, statstg.cbSize.LowPart, &cbRead);
1302 if (cbRead < statstg.cbSize.LowPart)
1303 {
1304 hr = E_FAIL;
1305 }
1306 ExitOnFailure(hr, "Failed to read stream content to buffer.");
1307
1308 // return value
1309 *ppbDest = pbDest;
1310 pbDest = NULL;
1311 *pcbDest = statstg.cbSize.LowPart;
1312
1313LExit:
1314 ReleaseObject(pStream);
1315 ReleaseMem(pbDest);
1316 return hr;
1317}