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