d3dx9/tests: Cleanup test_createtext() a bit.
[wine.git] / dlls / msxml3 / domdoc.c
blobddd756582ba384630bfe825095d8cd618df387ed
1 /*
2 * DOM Document implementation
4 * Copyright 2005 Mike McCormack
5 * Copyright 2010-2011 Adam Martinson for CodeWeavers
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
22 #define COBJMACROS
24 #include "config.h"
26 #include <stdarg.h>
27 #include <assert.h>
28 #ifdef HAVE_LIBXML2
29 # include <libxml/parser.h>
30 # include <libxml/xmlerror.h>
31 # include <libxml/xpathInternals.h>
32 # include <libxml/xmlsave.h>
33 # include <libxml/SAX2.h>
34 # include <libxml/parserInternals.h>
35 #endif
37 #include "windef.h"
38 #include "winbase.h"
39 #include "winuser.h"
40 #include "winnls.h"
41 #include "ole2.h"
42 #include "olectl.h"
43 #include "msxml6.h"
44 #include "wininet.h"
45 #include "winreg.h"
46 #include "shlwapi.h"
47 #include "ocidl.h"
48 #include "objsafe.h"
50 #include "wine/debug.h"
52 #include "msxml_private.h"
54 #ifdef HAVE_LIBXML2
56 WINE_DEFAULT_DEBUG_CHANNEL(msxml);
58 /* not defined in older versions */
59 #define XML_SAVE_FORMAT 1
60 #define XML_SAVE_NO_DECL 2
61 #define XML_SAVE_NO_EMPTY 4
62 #define XML_SAVE_NO_XHTML 8
63 #define XML_SAVE_XHTML 16
64 #define XML_SAVE_AS_XML 32
65 #define XML_SAVE_AS_HTML 64
67 static const WCHAR PropertySelectionLanguageW[] = {'S','e','l','e','c','t','i','o','n','L','a','n','g','u','a','g','e',0};
68 static const WCHAR PropertySelectionNamespacesW[] = {'S','e','l','e','c','t','i','o','n','N','a','m','e','s','p','a','c','e','s',0};
69 static const WCHAR PropertyProhibitDTDW[] = {'P','r','o','h','i','b','i','t','D','T','D',0};
70 static const WCHAR PropertyNewParserW[] = {'N','e','w','P','a','r','s','e','r',0};
71 static const WCHAR PropValueXPathW[] = {'X','P','a','t','h',0};
72 static const WCHAR PropValueXSLPatternW[] = {'X','S','L','P','a','t','t','e','r','n',0};
73 static const WCHAR PropertyResolveExternalsW[] = {'R','e','s','o','l','v','e','E','x','t','e','r','n','a','l','s',0};
74 static const WCHAR PropertyAllowXsltScriptW[] = {'A','l','l','o','w','X','s','l','t','S','c','r','i','p','t',0};
75 static const WCHAR PropertyAllowDocumentFunctionW[] = {'A','l','l','o','w','D','o','c','u','m','e','n','t','F','u','n','c','t','i','o','n',0};
77 /* Anything that passes the test_get_ownerDocument()
78 * tests can go here (data shared between all instances).
79 * We need to preserve this when reloading a document,
80 * and also need access to it from the libxml backend. */
81 typedef struct {
82 MSXML_VERSION version;
83 VARIANT_BOOL preserving;
84 IXMLDOMSchemaCollection2* schemaCache;
85 struct list selectNsList;
86 xmlChar const* selectNsStr;
87 LONG selectNsStr_len;
88 BOOL XPath;
89 IUri *uri;
90 } domdoc_properties;
92 typedef struct ConnectionPoint ConnectionPoint;
93 typedef struct domdoc domdoc;
95 struct ConnectionPoint
97 IConnectionPoint IConnectionPoint_iface;
98 const IID *iid;
100 ConnectionPoint *next;
101 IConnectionPointContainer *container;
102 domdoc *doc;
104 union
106 IUnknown *unk;
107 IDispatch *disp;
108 IPropertyNotifySink *propnotif;
109 } *sinks;
110 DWORD sinks_size;
113 typedef enum {
114 EVENTID_READYSTATECHANGE = 0,
115 EVENTID_DATAAVAILABLE,
116 EVENTID_TRANSFORMNODE,
117 EVENTID_LAST
118 } eventid_t;
120 struct domdoc
122 xmlnode node;
123 IXMLDOMDocument3 IXMLDOMDocument3_iface;
124 IPersistStreamInit IPersistStreamInit_iface;
125 IObjectWithSite IObjectWithSite_iface;
126 IObjectSafety IObjectSafety_iface;
127 IConnectionPointContainer IConnectionPointContainer_iface;
128 LONG ref;
129 VARIANT_BOOL async;
130 VARIANT_BOOL validating;
131 VARIANT_BOOL resolving;
132 domdoc_properties* properties;
133 HRESULT error;
135 /* IObjectWithSite */
136 IUnknown *site;
138 /* IObjectSafety */
139 DWORD safeopt;
141 /* connection list */
142 ConnectionPoint *cp_list;
143 ConnectionPoint cp_domdocevents;
144 ConnectionPoint cp_propnotif;
145 ConnectionPoint cp_dispatch;
147 /* events */
148 IDispatch *events[EVENTID_LAST];
150 IXMLDOMSchemaCollection2 *namespaces;
153 static HRESULT set_doc_event(domdoc *doc, eventid_t eid, const VARIANT *v)
155 IDispatch *disp;
157 switch (V_VT(v))
159 case VT_UNKNOWN:
160 if (V_UNKNOWN(v))
161 IUnknown_QueryInterface(V_UNKNOWN(v), &IID_IDispatch, (void**)&disp);
162 else
163 disp = NULL;
164 break;
165 case VT_DISPATCH:
166 disp = V_DISPATCH(v);
167 if (disp) IDispatch_AddRef(disp);
168 break;
169 default:
170 return DISP_E_TYPEMISMATCH;
173 if (doc->events[eid]) IDispatch_Release(doc->events[eid]);
174 doc->events[eid] = disp;
176 return S_OK;
179 static inline ConnectionPoint *impl_from_IConnectionPoint(IConnectionPoint *iface)
181 return CONTAINING_RECORD(iface, ConnectionPoint, IConnectionPoint_iface);
185 In native windows, the whole lifetime management of XMLDOMNodes is
186 managed automatically using reference counts. Wine emulates that by
187 maintaining a reference count to the document that is increased for
188 each IXMLDOMNode pointer passed out for this document. If all these
189 pointers are gone, the document is unreachable and gets freed, that
190 is, all nodes in the tree of the document get freed.
192 You are able to create nodes that are associated to a document (in
193 fact, in msxml's XMLDOM model, all nodes are associated to a document),
194 but not in the tree of that document, for example using the createFoo
195 functions from IXMLDOMDocument. These nodes do not get cleaned up
196 by libxml, so we have to do it ourselves.
198 To catch these nodes, a list of "orphan nodes" is introduced.
199 It contains pointers to all roots of node trees that are
200 associated with the document without being part of the document
201 tree. All nodes with parent==NULL (except for the document root nodes)
202 should be in the orphan node list of their document. All orphan nodes
203 get freed together with the document itself.
206 typedef struct _xmldoc_priv {
207 LONG refs;
208 struct list orphans;
209 domdoc_properties* properties;
210 } xmldoc_priv;
212 typedef struct _orphan_entry {
213 struct list entry;
214 xmlNode * node;
215 } orphan_entry;
217 typedef struct _select_ns_entry {
218 struct list entry;
219 xmlChar const* prefix;
220 xmlChar prefix_end;
221 xmlChar const* href;
222 xmlChar href_end;
223 } select_ns_entry;
225 static inline xmldoc_priv * priv_from_xmlDocPtr(const xmlDocPtr doc)
227 return doc->_private;
230 static inline domdoc_properties * properties_from_xmlDocPtr(xmlDocPtr doc)
232 return priv_from_xmlDocPtr(doc)->properties;
235 BOOL is_xpathmode(const xmlDocPtr doc)
237 return properties_from_xmlDocPtr(doc)->XPath;
240 void set_xpathmode(xmlDocPtr doc, BOOL xpath)
242 properties_from_xmlDocPtr(doc)->XPath = xpath;
245 int registerNamespaces(xmlXPathContextPtr ctxt)
247 int n = 0;
248 const select_ns_entry* ns = NULL;
249 const struct list* pNsList = &properties_from_xmlDocPtr(ctxt->doc)->selectNsList;
251 TRACE("(%p)\n", ctxt);
253 LIST_FOR_EACH_ENTRY( ns, pNsList, select_ns_entry, entry )
255 xmlXPathRegisterNs(ctxt, ns->prefix, ns->href);
256 ++n;
259 return n;
262 static inline void clear_selectNsList(struct list* pNsList)
264 select_ns_entry *ns, *ns2;
265 LIST_FOR_EACH_ENTRY_SAFE( ns, ns2, pNsList, select_ns_entry, entry )
267 heap_free( ns );
269 list_init(pNsList);
272 static xmldoc_priv * create_priv(void)
274 xmldoc_priv *priv;
275 priv = heap_alloc( sizeof (*priv) );
277 if (priv)
279 priv->refs = 0;
280 list_init( &priv->orphans );
281 priv->properties = NULL;
284 return priv;
287 static domdoc_properties *create_properties(MSXML_VERSION version)
289 domdoc_properties *properties = heap_alloc(sizeof(domdoc_properties));
291 list_init(&properties->selectNsList);
292 properties->preserving = VARIANT_FALSE;
293 properties->schemaCache = NULL;
294 properties->selectNsStr = heap_alloc_zero(sizeof(xmlChar));
295 properties->selectNsStr_len = 0;
297 /* properties that are dependent on object versions */
298 properties->version = version;
299 properties->XPath = (version == MSXML4 || version == MSXML6);
301 /* document uri */
302 properties->uri = NULL;
304 return properties;
307 static domdoc_properties* copy_properties(domdoc_properties const* properties)
309 domdoc_properties* pcopy = heap_alloc(sizeof(domdoc_properties));
310 select_ns_entry const* ns = NULL;
311 select_ns_entry* new_ns = NULL;
312 int len = (properties->selectNsStr_len+1)*sizeof(xmlChar);
313 ptrdiff_t offset;
315 if (pcopy)
317 pcopy->version = properties->version;
318 pcopy->preserving = properties->preserving;
319 pcopy->schemaCache = properties->schemaCache;
320 if (pcopy->schemaCache)
321 IXMLDOMSchemaCollection2_AddRef(pcopy->schemaCache);
322 pcopy->XPath = properties->XPath;
323 pcopy->selectNsStr_len = properties->selectNsStr_len;
324 list_init( &pcopy->selectNsList );
325 pcopy->selectNsStr = heap_alloc(len);
326 memcpy((xmlChar*)pcopy->selectNsStr, properties->selectNsStr, len);
327 offset = pcopy->selectNsStr - properties->selectNsStr;
329 LIST_FOR_EACH_ENTRY( ns, (&properties->selectNsList), select_ns_entry, entry )
331 new_ns = heap_alloc(sizeof(select_ns_entry));
332 memcpy(new_ns, ns, sizeof(select_ns_entry));
333 new_ns->href += offset;
334 new_ns->prefix += offset;
335 list_add_tail(&pcopy->selectNsList, &new_ns->entry);
338 pcopy->uri = properties->uri;
339 if (pcopy->uri)
340 IUri_AddRef(pcopy->uri);
343 return pcopy;
346 static void free_properties(domdoc_properties* properties)
348 if (properties)
350 if (properties->schemaCache)
351 IXMLDOMSchemaCollection2_Release(properties->schemaCache);
352 clear_selectNsList(&properties->selectNsList);
353 heap_free((xmlChar*)properties->selectNsStr);
354 if (properties->uri)
355 IUri_Release(properties->uri);
356 heap_free(properties);
360 static void release_namespaces(domdoc *This)
362 if (This->namespaces)
364 IXMLDOMSchemaCollection2_Release(This->namespaces);
365 This->namespaces = NULL;
369 /* links a "<?xml" node as a first child */
370 void xmldoc_link_xmldecl(xmlDocPtr doc, xmlNodePtr node)
372 assert(doc != NULL);
373 if (doc->standalone != -1) xmlAddPrevSibling( doc->children, node );
376 /* unlinks a first "<?xml" child if it was created */
377 xmlNodePtr xmldoc_unlink_xmldecl(xmlDocPtr doc)
379 static const xmlChar xmlA[] = "xml";
380 xmlNodePtr node, first_child;
382 assert(doc != NULL);
384 /* xml declaration node could be created automatically after parsing or added
385 to a tree later */
386 first_child = doc->children;
387 if (first_child && first_child->type == XML_PI_NODE && xmlStrEqual(first_child->name, xmlA))
389 node = first_child;
390 xmlUnlinkNode( node );
392 else
393 node = NULL;
395 return node;
398 BOOL is_preserving_whitespace(xmlNodePtr node)
400 domdoc_properties* properties = NULL;
401 /* during parsing the xmlDoc._private stuff is not there */
402 if (priv_from_xmlDocPtr(node->doc))
403 properties = properties_from_xmlDocPtr(node->doc);
404 return ((properties && properties->preserving == VARIANT_TRUE) ||
405 xmlNodeGetSpacePreserve(node) == 1);
408 static inline BOOL strn_isspace(xmlChar const* str, int len)
410 for (; str && len > 0 && *str; ++str, --len)
411 if (!isspace(*str))
412 break;
414 return len == 0;
417 static void sax_characters(void *ctx, const xmlChar *ch, int len)
419 xmlParserCtxtPtr ctxt;
420 const domdoc *This;
422 ctxt = (xmlParserCtxtPtr) ctx;
423 This = (const domdoc*) ctxt->_private;
425 if (ctxt->node)
427 xmlChar cur = *(ctxt->input->cur);
429 /* Characters are reported with multiple calls, for example each charref is reported with a separate
430 call and then parser appends it to a single text node or creates a new node if not created.
431 It's not possible to tell if it's ignorable data or not just looking at data itself cause it could be
432 space chars that separate charrefs or similar case. We only need to skip leading and trailing spaces,
433 or whole node if it has nothing but space chars, so to detect leading space node->last is checked that
434 contains text node pointer if already created, trailing spaces are detected directly looking at parser input
435 for next '<' opening bracket - similar logic is used by libxml2 itself. Basically 'cur' == '<' means the last
436 chunk of char data, in case it's not the last chunk we check for previously added node type and if it's not
437 a text node it's safe to ignore.
439 Note that during domdoc_loadXML() the xmlDocPtr->_private data is not available. */
441 if (!This->properties->preserving &&
442 !is_preserving_whitespace(ctxt->node) &&
443 strn_isspace(ch, len) &&
444 (!ctxt->node->last ||
445 ((ctxt->node->last && (cur == '<' || ctxt->node->last->type != XML_TEXT_NODE))
448 /* Keep information about ignorable whitespace text node in previous or parent node */
449 if (ctxt->node->last)
450 *(DWORD*)&ctxt->node->last->_private |= NODE_PRIV_TRAILING_IGNORABLE_WS;
451 else if (ctxt->node->type != XML_DOCUMENT_NODE)
452 *(DWORD*)&ctxt->node->_private |= NODE_PRIV_CHILD_IGNORABLE_WS;
453 return;
457 xmlSAX2Characters(ctxt, ch, len);
460 static void LIBXML2_LOG_CALLBACK sax_error(void* ctx, char const* msg, ...)
462 va_list ap;
463 va_start(ap, msg);
464 LIBXML2_CALLBACK_ERR(doparse, msg, ap);
465 va_end(ap);
468 static void LIBXML2_LOG_CALLBACK sax_warning(void* ctx, char const* msg, ...)
470 va_list ap;
471 va_start(ap, msg);
472 LIBXML2_CALLBACK_WARN(doparse, msg, ap);
473 va_end(ap);
476 static void sax_serror(void* ctx, xmlErrorPtr err)
478 LIBXML2_CALLBACK_SERROR(doparse, err);
481 static xmlDocPtr doparse(domdoc* This, char const* ptr, int len, xmlCharEncoding encoding)
483 xmlDocPtr doc = NULL;
484 xmlParserCtxtPtr pctx;
485 static xmlSAXHandler sax_handler = {
486 xmlSAX2InternalSubset, /* internalSubset */
487 xmlSAX2IsStandalone, /* isStandalone */
488 xmlSAX2HasInternalSubset, /* hasInternalSubset */
489 xmlSAX2HasExternalSubset, /* hasExternalSubset */
490 xmlSAX2ResolveEntity, /* resolveEntity */
491 xmlSAX2GetEntity, /* getEntity */
492 xmlSAX2EntityDecl, /* entityDecl */
493 xmlSAX2NotationDecl, /* notationDecl */
494 xmlSAX2AttributeDecl, /* attributeDecl */
495 xmlSAX2ElementDecl, /* elementDecl */
496 xmlSAX2UnparsedEntityDecl, /* unparsedEntityDecl */
497 xmlSAX2SetDocumentLocator, /* setDocumentLocator */
498 xmlSAX2StartDocument, /* startDocument */
499 xmlSAX2EndDocument, /* endDocument */
500 xmlSAX2StartElement, /* startElement */
501 xmlSAX2EndElement, /* endElement */
502 xmlSAX2Reference, /* reference */
503 sax_characters, /* characters */
504 sax_characters, /* ignorableWhitespace */
505 xmlSAX2ProcessingInstruction, /* processingInstruction */
506 xmlSAX2Comment, /* comment */
507 sax_warning, /* warning */
508 sax_error, /* error */
509 sax_error, /* fatalError */
510 xmlSAX2GetParameterEntity, /* getParameterEntity */
511 xmlSAX2CDataBlock, /* cdataBlock */
512 xmlSAX2ExternalSubset, /* externalSubset */
513 0, /* initialized */
514 NULL, /* _private */
515 xmlSAX2StartElementNs, /* startElementNs */
516 xmlSAX2EndElementNs, /* endElementNs */
517 sax_serror /* serror */
520 pctx = xmlCreateMemoryParserCtxt(ptr, len);
521 if (!pctx)
523 ERR("Failed to create parser context\n");
524 return NULL;
527 if (pctx->sax) xmlFree(pctx->sax);
528 pctx->sax = &sax_handler;
529 pctx->_private = This;
530 pctx->recovery = 0;
532 if (encoding != XML_CHAR_ENCODING_NONE)
533 xmlSwitchEncoding(pctx, encoding);
535 xmlParseDocument(pctx);
537 if (pctx->wellFormed)
539 doc = pctx->myDoc;
541 else
543 xmlFreeDoc(pctx->myDoc);
544 pctx->myDoc = NULL;
546 pctx->sax = NULL;
547 xmlFreeParserCtxt(pctx);
549 /* TODO: put this in one of the SAX callbacks */
550 /* create first child as a <?xml...?> */
551 if (doc && doc->standalone != -1)
553 xmlNodePtr node;
554 char buff[30];
555 xmlChar *xmlbuff = (xmlChar*)buff;
557 node = xmlNewDocPI( doc, (xmlChar*)"xml", NULL );
559 /* version attribute can't be omitted */
560 sprintf(buff, "version=\"%s\"", doc->version ? (char*)doc->version : "1.0");
561 xmlNodeAddContent( node, xmlbuff );
563 if (doc->encoding)
565 sprintf(buff, " encoding=\"%s\"", doc->encoding);
566 xmlNodeAddContent( node, xmlbuff );
569 if (doc->standalone != -2)
571 sprintf(buff, " standalone=\"%s\"", doc->standalone == 0 ? "no" : "yes");
572 xmlNodeAddContent( node, xmlbuff );
575 xmldoc_link_xmldecl( doc, node );
578 return doc;
581 void xmldoc_init(xmlDocPtr doc, MSXML_VERSION version)
583 doc->_private = create_priv();
584 priv_from_xmlDocPtr(doc)->properties = create_properties(version);
587 LONG xmldoc_add_refs(xmlDocPtr doc, LONG refs)
589 LONG ref = InterlockedExchangeAdd(&priv_from_xmlDocPtr(doc)->refs, refs) + refs;
590 TRACE("(%p)->(%d)\n", doc, ref);
591 return ref;
594 LONG xmldoc_add_ref(xmlDocPtr doc)
596 return xmldoc_add_refs(doc, 1);
599 LONG xmldoc_release_refs(xmlDocPtr doc, LONG refs)
601 xmldoc_priv *priv = priv_from_xmlDocPtr(doc);
602 LONG ref = InterlockedExchangeAdd(&priv->refs, -refs) - refs;
603 TRACE("(%p)->(%d)\n", doc, ref);
605 if (ref < 0)
606 WARN("negative refcount, expect troubles\n");
608 if (ref == 0)
610 orphan_entry *orphan, *orphan2;
611 TRACE("freeing docptr %p\n", doc);
613 LIST_FOR_EACH_ENTRY_SAFE( orphan, orphan2, &priv->orphans, orphan_entry, entry )
615 xmlFreeNode( orphan->node );
616 heap_free( orphan );
618 free_properties(priv->properties);
619 heap_free(doc->_private);
621 xmlFreeDoc(doc);
624 return ref;
627 LONG xmldoc_release(xmlDocPtr doc)
629 return xmldoc_release_refs(doc, 1);
632 HRESULT xmldoc_add_orphan(xmlDocPtr doc, xmlNodePtr node)
634 xmldoc_priv *priv = priv_from_xmlDocPtr(doc);
635 orphan_entry *entry;
637 entry = heap_alloc( sizeof (*entry) );
638 if(!entry)
639 return E_OUTOFMEMORY;
641 entry->node = node;
642 list_add_head( &priv->orphans, &entry->entry );
643 return S_OK;
646 HRESULT xmldoc_remove_orphan(xmlDocPtr doc, xmlNodePtr node)
648 xmldoc_priv *priv = priv_from_xmlDocPtr(doc);
649 orphan_entry *entry, *entry2;
651 LIST_FOR_EACH_ENTRY_SAFE( entry, entry2, &priv->orphans, orphan_entry, entry )
653 if( entry->node == node )
655 list_remove( &entry->entry );
656 heap_free( entry );
657 return S_OK;
661 return S_FALSE;
664 static inline xmlDocPtr get_doc( domdoc *This )
666 return This->node.node->doc;
669 static HRESULT attach_xmldoc(domdoc *This, xmlDocPtr xml )
671 release_namespaces(This);
673 if(This->node.node)
675 priv_from_xmlDocPtr(get_doc(This))->properties = NULL;
676 if (xmldoc_release(get_doc(This)) != 0)
677 priv_from_xmlDocPtr(get_doc(This))->properties =
678 copy_properties(This->properties);
681 This->node.node = (xmlNodePtr) xml;
683 if(This->node.node)
685 xmldoc_add_ref(get_doc(This));
686 priv_from_xmlDocPtr(get_doc(This))->properties = This->properties;
689 return S_OK;
692 static inline domdoc *impl_from_IXMLDOMDocument3( IXMLDOMDocument3 *iface )
694 return CONTAINING_RECORD(iface, domdoc, IXMLDOMDocument3_iface);
697 static inline domdoc *impl_from_IPersistStreamInit(IPersistStreamInit *iface)
699 return CONTAINING_RECORD(iface, domdoc, IPersistStreamInit_iface);
702 static inline domdoc *impl_from_IObjectWithSite(IObjectWithSite *iface)
704 return CONTAINING_RECORD(iface, domdoc, IObjectWithSite_iface);
707 static inline domdoc *impl_from_IObjectSafety(IObjectSafety *iface)
709 return CONTAINING_RECORD(iface, domdoc, IObjectSafety_iface);
712 static inline domdoc *impl_from_IConnectionPointContainer(IConnectionPointContainer *iface)
714 return CONTAINING_RECORD(iface, domdoc, IConnectionPointContainer_iface);
717 /************************************************************************
718 * domdoc implementation of IPersistStream.
720 static HRESULT WINAPI PersistStreamInit_QueryInterface(
721 IPersistStreamInit *iface, REFIID riid, void **ppvObj)
723 domdoc* This = impl_from_IPersistStreamInit(iface);
724 return IXMLDOMDocument3_QueryInterface(&This->IXMLDOMDocument3_iface, riid, ppvObj);
727 static ULONG WINAPI PersistStreamInit_AddRef(
728 IPersistStreamInit *iface)
730 domdoc* This = impl_from_IPersistStreamInit(iface);
731 return IXMLDOMDocument3_AddRef(&This->IXMLDOMDocument3_iface);
734 static ULONG WINAPI PersistStreamInit_Release(
735 IPersistStreamInit *iface)
737 domdoc* This = impl_from_IPersistStreamInit(iface);
738 return IXMLDOMDocument3_Release(&This->IXMLDOMDocument3_iface);
741 static HRESULT WINAPI PersistStreamInit_GetClassID(
742 IPersistStreamInit *iface, CLSID *classid)
744 domdoc* This = impl_from_IPersistStreamInit(iface);
745 TRACE("(%p)->(%p)\n", This, classid);
747 if(!classid)
748 return E_POINTER;
750 *classid = *DOMDocument_version(This->properties->version);
752 return S_OK;
755 static HRESULT WINAPI PersistStreamInit_IsDirty(
756 IPersistStreamInit *iface)
758 domdoc *This = impl_from_IPersistStreamInit(iface);
759 FIXME("(%p): stub!\n", This);
760 return S_FALSE;
763 static HRESULT domdoc_load_from_stream(domdoc *doc, ISequentialStream *stream)
765 DWORD read, written, len;
766 xmlDocPtr xmldoc = NULL;
767 IStream *hstream;
768 HGLOBAL hglobal;
769 BYTE buf[4096];
770 HRESULT hr;
771 char *ptr;
773 hstream = NULL;
774 hr = CreateStreamOnHGlobal(NULL, TRUE, &hstream);
775 if (FAILED(hr))
776 return hr;
780 ISequentialStream_Read(stream, buf, sizeof(buf), &read);
781 hr = IStream_Write(hstream, buf, read, &written);
782 } while(SUCCEEDED(hr) && written != 0 && read != 0);
784 if (FAILED(hr))
786 ERR("failed to copy stream 0x%08x\n", hr);
787 IStream_Release(hstream);
788 return hr;
791 hr = GetHGlobalFromStream(hstream, &hglobal);
792 if (FAILED(hr))
793 return hr;
795 len = GlobalSize(hglobal);
796 ptr = GlobalLock(hglobal);
797 if (len)
798 xmldoc = doparse(doc, ptr, len, XML_CHAR_ENCODING_NONE);
799 GlobalUnlock(hglobal);
801 if (!xmldoc)
803 ERR("Failed to parse xml\n");
804 return E_FAIL;
807 xmldoc->_private = create_priv();
809 return attach_xmldoc(doc, xmldoc);
812 static HRESULT WINAPI PersistStreamInit_Load(IPersistStreamInit *iface, IStream *stream)
814 domdoc *This = impl_from_IPersistStreamInit(iface);
816 TRACE("(%p)->(%p)\n", This, stream);
818 if (!stream)
819 return E_INVALIDARG;
821 return domdoc_load_from_stream(This, (ISequentialStream*)stream);
824 static HRESULT WINAPI PersistStreamInit_Save(
825 IPersistStreamInit *iface, IStream *stream, BOOL clr_dirty)
827 domdoc *This = impl_from_IPersistStreamInit(iface);
828 BSTR xmlString;
829 HRESULT hr;
831 TRACE("(%p)->(%p %d)\n", This, stream, clr_dirty);
833 hr = IXMLDOMDocument3_get_xml(&This->IXMLDOMDocument3_iface, &xmlString);
834 if(hr == S_OK)
836 DWORD len = SysStringLen(xmlString) * sizeof(WCHAR);
838 hr = IStream_Write( stream, xmlString, len, NULL );
839 SysFreeString(xmlString);
842 TRACE("ret 0x%08x\n", hr);
844 return hr;
847 static HRESULT WINAPI PersistStreamInit_GetSizeMax(
848 IPersistStreamInit *iface, ULARGE_INTEGER *pcbSize)
850 domdoc *This = impl_from_IPersistStreamInit(iface);
851 TRACE("(%p)->(%p)\n", This, pcbSize);
852 return E_NOTIMPL;
855 static HRESULT WINAPI PersistStreamInit_InitNew(
856 IPersistStreamInit *iface)
858 domdoc *This = impl_from_IPersistStreamInit(iface);
859 TRACE("(%p)\n", This);
860 return S_OK;
863 static const IPersistStreamInitVtbl xmldoc_IPersistStreamInit_VTable =
865 PersistStreamInit_QueryInterface,
866 PersistStreamInit_AddRef,
867 PersistStreamInit_Release,
868 PersistStreamInit_GetClassID,
869 PersistStreamInit_IsDirty,
870 PersistStreamInit_Load,
871 PersistStreamInit_Save,
872 PersistStreamInit_GetSizeMax,
873 PersistStreamInit_InitNew
876 /* IXMLDOMDocument3 interface */
878 static const tid_t domdoc_se_tids[] = {
879 IXMLDOMNode_tid,
880 IXMLDOMDocument_tid,
881 IXMLDOMDocument2_tid,
882 IXMLDOMDocument3_tid,
883 NULL_tid
886 static HRESULT WINAPI domdoc_QueryInterface( IXMLDOMDocument3 *iface, REFIID riid, void** ppvObject )
888 domdoc *This = impl_from_IXMLDOMDocument3( iface );
890 TRACE("(%p)->(%s %p)\n", This, debugstr_guid( riid ), ppvObject );
892 *ppvObject = NULL;
894 if ( IsEqualGUID( riid, &IID_IUnknown ) ||
895 IsEqualGUID( riid, &IID_IDispatch ) ||
896 IsEqualGUID( riid, &IID_IXMLDOMNode ) ||
897 IsEqualGUID( riid, &IID_IXMLDOMDocument ) ||
898 IsEqualGUID( riid, &IID_IXMLDOMDocument2 )||
899 IsEqualGUID( riid, &IID_IXMLDOMDocument3 ))
901 *ppvObject = iface;
903 else if (IsEqualGUID(&IID_IPersistStream, riid) ||
904 IsEqualGUID(&IID_IPersistStreamInit, riid))
906 *ppvObject = &This->IPersistStreamInit_iface;
908 else if (IsEqualGUID(&IID_IObjectWithSite, riid))
910 *ppvObject = &This->IObjectWithSite_iface;
912 else if (IsEqualGUID(&IID_IObjectSafety, riid))
914 *ppvObject = &This->IObjectSafety_iface;
916 else if( IsEqualGUID( riid, &IID_ISupportErrorInfo ))
918 return node_create_supporterrorinfo(domdoc_se_tids, ppvObject);
920 else if(node_query_interface(&This->node, riid, ppvObject))
922 return *ppvObject ? S_OK : E_NOINTERFACE;
924 else if (IsEqualGUID( riid, &IID_IConnectionPointContainer ))
926 *ppvObject = &This->IConnectionPointContainer_iface;
928 else
930 TRACE("interface %s not implemented\n", debugstr_guid(riid));
931 return E_NOINTERFACE;
934 IUnknown_AddRef((IUnknown*)*ppvObject);
936 return S_OK;
939 static ULONG WINAPI domdoc_AddRef( IXMLDOMDocument3 *iface )
941 domdoc *This = impl_from_IXMLDOMDocument3( iface );
942 ULONG ref = InterlockedIncrement( &This->ref );
943 TRACE("(%p)->(%d)\n", This, ref );
944 return ref;
947 static ULONG WINAPI domdoc_Release( IXMLDOMDocument3 *iface )
949 domdoc *This = impl_from_IXMLDOMDocument3( iface );
950 LONG ref = InterlockedDecrement( &This->ref );
952 TRACE("(%p)->(%d)\n", This, ref );
954 if ( ref == 0 )
956 int eid;
958 if (This->site)
959 IUnknown_Release( This->site );
960 destroy_xmlnode(&This->node);
962 for (eid = 0; eid < EVENTID_LAST; eid++)
963 if (This->events[eid]) IDispatch_Release(This->events[eid]);
965 release_namespaces(This);
966 heap_free(This);
969 return ref;
972 static HRESULT WINAPI domdoc_GetTypeInfoCount( IXMLDOMDocument3 *iface, UINT* pctinfo )
974 domdoc *This = impl_from_IXMLDOMDocument3( iface );
975 return IDispatchEx_GetTypeInfoCount(&This->node.dispex.IDispatchEx_iface, pctinfo);
978 static HRESULT WINAPI domdoc_GetTypeInfo(
979 IXMLDOMDocument3 *iface,
980 UINT iTInfo, LCID lcid, ITypeInfo** ppTInfo )
982 domdoc *This = impl_from_IXMLDOMDocument3( iface );
983 return IDispatchEx_GetTypeInfo(&This->node.dispex.IDispatchEx_iface, iTInfo, lcid, ppTInfo);
986 static HRESULT WINAPI domdoc_GetIDsOfNames(
987 IXMLDOMDocument3 *iface,
988 REFIID riid,
989 LPOLESTR* rgszNames,
990 UINT cNames,
991 LCID lcid,
992 DISPID* rgDispId)
994 domdoc *This = impl_from_IXMLDOMDocument3( iface );
995 return IDispatchEx_GetIDsOfNames(&This->node.dispex.IDispatchEx_iface,
996 riid, rgszNames, cNames, lcid, rgDispId);
999 static HRESULT WINAPI domdoc_Invoke(
1000 IXMLDOMDocument3 *iface,
1001 DISPID dispIdMember,
1002 REFIID riid,
1003 LCID lcid,
1004 WORD wFlags,
1005 DISPPARAMS* pDispParams,
1006 VARIANT* pVarResult,
1007 EXCEPINFO* pExcepInfo,
1008 UINT* puArgErr)
1010 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1011 return IDispatchEx_Invoke(&This->node.dispex.IDispatchEx_iface,
1012 dispIdMember, riid, lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
1015 static HRESULT WINAPI domdoc_get_nodeName(
1016 IXMLDOMDocument3 *iface,
1017 BSTR* name )
1019 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1021 static const WCHAR documentW[] = {'#','d','o','c','u','m','e','n','t',0};
1023 TRACE("(%p)->(%p)\n", This, name);
1025 return return_bstr(documentW, name);
1029 static HRESULT WINAPI domdoc_get_nodeValue(
1030 IXMLDOMDocument3 *iface,
1031 VARIANT* value )
1033 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1035 TRACE("(%p)->(%p)\n", This, value);
1037 if(!value)
1038 return E_INVALIDARG;
1040 V_VT(value) = VT_NULL;
1041 V_BSTR(value) = NULL; /* tests show that we should do this */
1042 return S_FALSE;
1046 static HRESULT WINAPI domdoc_put_nodeValue(
1047 IXMLDOMDocument3 *iface,
1048 VARIANT value)
1050 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1051 TRACE("(%p)->(%s)\n", This, debugstr_variant(&value));
1052 return E_FAIL;
1056 static HRESULT WINAPI domdoc_get_nodeType(
1057 IXMLDOMDocument3 *iface,
1058 DOMNodeType* type )
1060 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1062 TRACE("(%p)->(%p)\n", This, type);
1064 *type = NODE_DOCUMENT;
1065 return S_OK;
1069 static HRESULT WINAPI domdoc_get_parentNode(
1070 IXMLDOMDocument3 *iface,
1071 IXMLDOMNode** parent )
1073 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1075 TRACE("(%p)->(%p)\n", This, parent);
1077 return node_get_parent(&This->node, parent);
1081 static HRESULT WINAPI domdoc_get_childNodes(
1082 IXMLDOMDocument3 *iface,
1083 IXMLDOMNodeList** childList )
1085 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1087 TRACE("(%p)->(%p)\n", This, childList);
1089 return node_get_child_nodes(&This->node, childList);
1093 static HRESULT WINAPI domdoc_get_firstChild(
1094 IXMLDOMDocument3 *iface,
1095 IXMLDOMNode** firstChild )
1097 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1099 TRACE("(%p)->(%p)\n", This, firstChild);
1101 return node_get_first_child(&This->node, firstChild);
1105 static HRESULT WINAPI domdoc_get_lastChild(
1106 IXMLDOMDocument3 *iface,
1107 IXMLDOMNode** lastChild )
1109 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1111 TRACE("(%p)->(%p)\n", This, lastChild);
1113 return node_get_last_child(&This->node, lastChild);
1117 static HRESULT WINAPI domdoc_get_previousSibling(
1118 IXMLDOMDocument3 *iface,
1119 IXMLDOMNode** previousSibling )
1121 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1123 TRACE("(%p)->(%p)\n", This, previousSibling);
1125 return return_null_node(previousSibling);
1129 static HRESULT WINAPI domdoc_get_nextSibling(
1130 IXMLDOMDocument3 *iface,
1131 IXMLDOMNode** nextSibling )
1133 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1135 TRACE("(%p)->(%p)\n", This, nextSibling);
1137 return return_null_node(nextSibling);
1141 static HRESULT WINAPI domdoc_get_attributes(
1142 IXMLDOMDocument3 *iface,
1143 IXMLDOMNamedNodeMap** attributeMap )
1145 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1147 TRACE("(%p)->(%p)\n", This, attributeMap);
1149 return return_null_ptr((void**)attributeMap);
1153 static HRESULT WINAPI domdoc_insertBefore(
1154 IXMLDOMDocument3 *iface,
1155 IXMLDOMNode* newChild,
1156 VARIANT refChild,
1157 IXMLDOMNode** outNewChild )
1159 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1160 DOMNodeType type;
1161 HRESULT hr;
1163 TRACE("(%p)->(%p %s %p)\n", This, newChild, debugstr_variant(&refChild), outNewChild);
1165 hr = IXMLDOMNode_get_nodeType(newChild, &type);
1166 if (hr != S_OK) return hr;
1168 TRACE("new node type %d\n", type);
1169 switch (type)
1171 case NODE_ATTRIBUTE:
1172 case NODE_DOCUMENT:
1173 case NODE_CDATA_SECTION:
1174 if (outNewChild) *outNewChild = NULL;
1175 return E_FAIL;
1176 default:
1177 return node_insert_before(&This->node, newChild, &refChild, outNewChild);
1181 static HRESULT WINAPI domdoc_replaceChild(
1182 IXMLDOMDocument3 *iface,
1183 IXMLDOMNode* newChild,
1184 IXMLDOMNode* oldChild,
1185 IXMLDOMNode** outOldChild)
1187 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1189 TRACE("(%p)->(%p %p %p)\n", This, newChild, oldChild, outOldChild);
1191 return node_replace_child(&This->node, newChild, oldChild, outOldChild);
1195 static HRESULT WINAPI domdoc_removeChild(
1196 IXMLDOMDocument3 *iface,
1197 IXMLDOMNode *child,
1198 IXMLDOMNode **oldChild)
1200 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1201 TRACE("(%p)->(%p %p)\n", This, child, oldChild);
1202 return node_remove_child(&This->node, child, oldChild);
1206 static HRESULT WINAPI domdoc_appendChild(
1207 IXMLDOMDocument3 *iface,
1208 IXMLDOMNode *child,
1209 IXMLDOMNode **outChild)
1211 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1212 TRACE("(%p)->(%p %p)\n", This, child, outChild);
1213 return node_append_child(&This->node, child, outChild);
1217 static HRESULT WINAPI domdoc_hasChildNodes(
1218 IXMLDOMDocument3 *iface,
1219 VARIANT_BOOL *ret)
1221 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1222 TRACE("(%p)->(%p)\n", This, ret);
1223 return node_has_childnodes(&This->node, ret);
1227 static HRESULT WINAPI domdoc_get_ownerDocument(
1228 IXMLDOMDocument3 *iface,
1229 IXMLDOMDocument **doc)
1231 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1232 TRACE("(%p)->(%p)\n", This, doc);
1233 return node_get_owner_doc(&This->node, doc);
1237 static HRESULT WINAPI domdoc_cloneNode(
1238 IXMLDOMDocument3 *iface,
1239 VARIANT_BOOL deep,
1240 IXMLDOMNode** outNode)
1242 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1243 xmlNodePtr clone;
1245 TRACE("(%p)->(%d %p)\n", This, deep, outNode);
1247 if (!outNode)
1248 return E_INVALIDARG;
1250 *outNode = NULL;
1252 clone = xmlCopyNode((xmlNodePtr)get_doc(This), deep ? 1 : 2);
1253 if (!clone)
1254 return E_FAIL;
1256 clone->doc->_private = create_priv();
1257 xmldoc_add_orphan(clone->doc, clone);
1258 xmldoc_add_ref(clone->doc);
1260 priv_from_xmlDocPtr(clone->doc)->properties = copy_properties(This->properties);
1261 if (!(*outNode = (IXMLDOMNode*)create_domdoc(clone)))
1263 xmldoc_release(clone->doc);
1264 return E_FAIL;
1267 return S_OK;
1271 static HRESULT WINAPI domdoc_get_nodeTypeString(
1272 IXMLDOMDocument3 *iface,
1273 BSTR *p)
1275 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1276 static const WCHAR documentW[] = {'d','o','c','u','m','e','n','t',0};
1278 TRACE("(%p)->(%p)\n", This, p);
1280 return return_bstr(documentW, p);
1284 static HRESULT WINAPI domdoc_get_text(
1285 IXMLDOMDocument3 *iface,
1286 BSTR *p)
1288 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1289 TRACE("(%p)->(%p)\n", This, p);
1290 return node_get_text(&This->node, p);
1294 static HRESULT WINAPI domdoc_put_text(
1295 IXMLDOMDocument3 *iface,
1296 BSTR text )
1298 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1299 TRACE("(%p)->(%s)\n", This, debugstr_w(text));
1300 return E_FAIL;
1304 static HRESULT WINAPI domdoc_get_specified(
1305 IXMLDOMDocument3 *iface,
1306 VARIANT_BOOL* isSpecified )
1308 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1309 FIXME("(%p)->(%p) stub!\n", This, isSpecified);
1310 *isSpecified = VARIANT_TRUE;
1311 return S_OK;
1315 static HRESULT WINAPI domdoc_get_definition(
1316 IXMLDOMDocument3 *iface,
1317 IXMLDOMNode** definitionNode )
1319 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1320 FIXME("(%p)->(%p)\n", This, definitionNode);
1321 return E_NOTIMPL;
1325 static HRESULT WINAPI domdoc_get_nodeTypedValue(
1326 IXMLDOMDocument3 *iface,
1327 VARIANT* v )
1329 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1330 TRACE("(%p)->(%p)\n", This, v);
1331 return return_null_var(v);
1334 static HRESULT WINAPI domdoc_put_nodeTypedValue(
1335 IXMLDOMDocument3 *iface,
1336 VARIANT typedValue )
1338 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1339 FIXME("(%p)->(%s)\n", This, debugstr_variant(&typedValue));
1340 return E_NOTIMPL;
1344 static HRESULT WINAPI domdoc_get_dataType(
1345 IXMLDOMDocument3 *iface,
1346 VARIANT* typename )
1348 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1349 TRACE("(%p)->(%p)\n", This, typename);
1350 return return_null_var( typename );
1354 static HRESULT WINAPI domdoc_put_dataType(
1355 IXMLDOMDocument3 *iface,
1356 BSTR dataTypeName )
1358 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1360 FIXME("(%p)->(%s)\n", This, debugstr_w(dataTypeName));
1362 if(!dataTypeName)
1363 return E_INVALIDARG;
1365 return E_FAIL;
1368 static int XMLCALL domdoc_get_xml_writecallback(void *ctx, const char *data, int len)
1370 return xmlBufferAdd((xmlBufferPtr)ctx, (xmlChar*)data, len) == 0 ? len : 0;
1373 static HRESULT WINAPI domdoc_get_xml(
1374 IXMLDOMDocument3 *iface,
1375 BSTR* p)
1377 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1378 xmlSaveCtxtPtr ctxt;
1379 xmlBufferPtr buf;
1380 int options;
1381 long ret;
1383 TRACE("(%p)->(%p)\n", This, p);
1385 if(!p)
1386 return E_INVALIDARG;
1388 *p = NULL;
1390 buf = xmlBufferCreate();
1391 if(!buf)
1392 return E_OUTOFMEMORY;
1394 options = XML_SAVE_FORMAT | XML_SAVE_NO_DECL;
1395 ctxt = xmlSaveToIO(domdoc_get_xml_writecallback, NULL, buf, "UTF-8", options);
1397 if(!ctxt)
1399 xmlBufferFree(buf);
1400 return E_OUTOFMEMORY;
1403 ret = xmlSaveDoc(ctxt, get_doc(This));
1404 /* flushes on close */
1405 xmlSaveClose(ctxt);
1407 TRACE("%ld, len=%d\n", ret, xmlBufferLength(buf));
1408 if(ret != -1 && xmlBufferLength(buf) > 0)
1410 BSTR content;
1412 content = bstr_from_xmlChar(xmlBufferContent(buf));
1413 content = EnsureCorrectEOL(content);
1415 *p = content;
1417 else
1419 *p = SysAllocStringLen(NULL, 0);
1422 xmlBufferFree(buf);
1424 return *p ? S_OK : E_OUTOFMEMORY;
1428 static HRESULT WINAPI domdoc_transformNode(
1429 IXMLDOMDocument3 *iface,
1430 IXMLDOMNode *node,
1431 BSTR *p)
1433 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1434 TRACE("(%p)->(%p %p)\n", This, node, p);
1435 return node_transform_node(&This->node, node, p);
1439 static HRESULT WINAPI domdoc_selectNodes(
1440 IXMLDOMDocument3 *iface,
1441 BSTR p,
1442 IXMLDOMNodeList **outList)
1444 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1445 TRACE("(%p)->(%s %p)\n", This, debugstr_w(p), outList);
1446 return node_select_nodes(&This->node, p, outList);
1450 static HRESULT WINAPI domdoc_selectSingleNode(
1451 IXMLDOMDocument3 *iface,
1452 BSTR p,
1453 IXMLDOMNode **outNode)
1455 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1456 TRACE("(%p)->(%s %p)\n", This, debugstr_w(p), outNode);
1457 return node_select_singlenode(&This->node, p, outNode);
1461 static HRESULT WINAPI domdoc_get_parsed(
1462 IXMLDOMDocument3 *iface,
1463 VARIANT_BOOL* isParsed )
1465 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1466 FIXME("(%p)->(%p) stub!\n", This, isParsed);
1467 *isParsed = VARIANT_TRUE;
1468 return S_OK;
1471 static HRESULT WINAPI domdoc_get_namespaceURI(
1472 IXMLDOMDocument3 *iface,
1473 BSTR* namespaceURI )
1475 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1476 TRACE("(%p)->(%p)\n", This, namespaceURI);
1477 return return_null_bstr( namespaceURI );
1480 static HRESULT WINAPI domdoc_get_prefix(
1481 IXMLDOMDocument3 *iface,
1482 BSTR* prefix )
1484 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1485 TRACE("(%p)->(%p)\n", This, prefix);
1486 return return_null_bstr( prefix );
1490 static HRESULT WINAPI domdoc_get_baseName(
1491 IXMLDOMDocument3 *iface,
1492 BSTR* name )
1494 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1495 TRACE("(%p)->(%p)\n", This, name);
1496 return return_null_bstr( name );
1500 static HRESULT WINAPI domdoc_transformNodeToObject(
1501 IXMLDOMDocument3 *iface,
1502 IXMLDOMNode* stylesheet,
1503 VARIANT output)
1505 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1507 TRACE("(%p)->(%p %s)\n", This, stylesheet, debugstr_variant(&output));
1509 switch (V_VT(&output))
1511 case VT_UNKNOWN:
1512 case VT_DISPATCH:
1514 IXMLDOMDocument *doc;
1515 HRESULT hr;
1517 if (!V_UNKNOWN(&output))
1518 return E_INVALIDARG;
1520 /* FIXME: we're not supposed to query for document interface, should use IStream
1521 which we don't support currently. */
1522 if (IUnknown_QueryInterface(V_UNKNOWN(&output), &IID_IXMLDOMDocument, (void **)&doc) == S_OK)
1524 VARIANT_BOOL b;
1525 BSTR str;
1527 if (FAILED(hr = node_transform_node(&This->node, stylesheet, &str)))
1528 return hr;
1530 hr = IXMLDOMDocument_loadXML(doc, str, &b);
1531 SysFreeString(str);
1532 return hr;
1534 else
1536 FIXME("Unsupported destination type.\n");
1537 return E_INVALIDARG;
1540 default:
1541 FIXME("Output type %d not handled.\n", V_VT(&output));
1542 return E_NOTIMPL;
1545 return E_NOTIMPL;
1549 static HRESULT WINAPI domdoc_get_doctype(
1550 IXMLDOMDocument3 *iface,
1551 IXMLDOMDocumentType** doctype )
1553 domdoc *This = impl_from_IXMLDOMDocument3(iface);
1554 IXMLDOMNode *node;
1555 xmlDtdPtr dtd;
1556 HRESULT hr;
1558 TRACE("(%p)->(%p)\n", This, doctype);
1560 if (!doctype) return E_INVALIDARG;
1562 *doctype = NULL;
1564 dtd = xmlGetIntSubset(get_doc(This));
1565 if (!dtd) return S_FALSE;
1567 node = create_node((xmlNodePtr)dtd);
1568 if (!node) return S_FALSE;
1570 hr = IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMDocumentType, (void**)doctype);
1571 IXMLDOMNode_Release(node);
1573 return hr;
1577 static HRESULT WINAPI domdoc_get_implementation(
1578 IXMLDOMDocument3 *iface,
1579 IXMLDOMImplementation** impl )
1581 domdoc *This = impl_from_IXMLDOMDocument3(iface);
1583 TRACE("(%p)->(%p)\n", This, impl);
1585 if(!impl)
1586 return E_INVALIDARG;
1588 *impl = (IXMLDOMImplementation*)create_doc_Implementation();
1590 return S_OK;
1593 static HRESULT WINAPI domdoc_get_documentElement(
1594 IXMLDOMDocument3 *iface,
1595 IXMLDOMElement** DOMElement )
1597 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1598 IXMLDOMNode *element_node;
1599 xmlNodePtr root;
1600 HRESULT hr;
1602 TRACE("(%p)->(%p)\n", This, DOMElement);
1604 if(!DOMElement)
1605 return E_INVALIDARG;
1607 *DOMElement = NULL;
1609 root = xmlDocGetRootElement( get_doc(This) );
1610 if ( !root )
1611 return S_FALSE;
1613 element_node = create_node( root );
1614 if(!element_node) return S_FALSE;
1616 hr = IXMLDOMNode_QueryInterface(element_node, &IID_IXMLDOMElement, (void**)DOMElement);
1617 IXMLDOMNode_Release(element_node);
1619 return hr;
1623 static HRESULT WINAPI domdoc_put_documentElement(
1624 IXMLDOMDocument3 *iface,
1625 IXMLDOMElement* DOMElement )
1627 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1628 IXMLDOMNode *elementNode;
1629 xmlNodePtr oldRoot;
1630 xmlDocPtr old_doc;
1631 xmlnode *xmlNode;
1632 int refcount = 0;
1633 HRESULT hr;
1635 TRACE("(%p)->(%p)\n", This, DOMElement);
1637 hr = IXMLDOMElement_QueryInterface( DOMElement, &IID_IXMLDOMNode, (void**)&elementNode );
1638 if(FAILED(hr))
1639 return hr;
1641 xmlNode = get_node_obj( elementNode );
1642 if(!xmlNode) return E_FAIL;
1644 if(!xmlNode->node->parent)
1645 if(xmldoc_remove_orphan(xmlNode->node->doc, xmlNode->node) != S_OK)
1646 WARN("%p is not an orphan of %p\n", xmlNode->node->doc, xmlNode->node);
1648 old_doc = xmlNode->node->doc;
1649 if (old_doc != get_doc(This))
1650 refcount = xmlnode_get_inst_cnt(xmlNode);
1652 /* old root is still orphaned by its document, update refcount from new root */
1653 if (refcount) xmldoc_add_refs(get_doc(This), refcount);
1654 oldRoot = xmlDocSetRootElement( get_doc(This), xmlNode->node);
1655 if (refcount) xmldoc_release_refs(old_doc, refcount);
1656 IXMLDOMNode_Release( elementNode );
1658 if(oldRoot)
1659 xmldoc_add_orphan(oldRoot->doc, oldRoot);
1661 return S_OK;
1665 static HRESULT WINAPI domdoc_createElement(
1666 IXMLDOMDocument3 *iface,
1667 BSTR tagname,
1668 IXMLDOMElement** element )
1670 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1671 IXMLDOMNode *node;
1672 VARIANT type;
1673 HRESULT hr;
1675 TRACE("(%p)->(%s %p)\n", This, debugstr_w(tagname), element);
1677 if (!element || !tagname) return E_INVALIDARG;
1679 V_VT(&type) = VT_I1;
1680 V_I1(&type) = NODE_ELEMENT;
1682 hr = IXMLDOMDocument3_createNode(iface, type, tagname, NULL, &node);
1683 if (hr == S_OK)
1685 IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMElement, (void**)element);
1686 IXMLDOMNode_Release(node);
1689 return hr;
1693 static HRESULT WINAPI domdoc_createDocumentFragment(
1694 IXMLDOMDocument3 *iface,
1695 IXMLDOMDocumentFragment** frag )
1697 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1698 IXMLDOMNode *node;
1699 VARIANT type;
1700 HRESULT hr;
1702 TRACE("(%p)->(%p)\n", This, frag);
1704 if (!frag) return E_INVALIDARG;
1706 *frag = NULL;
1708 V_VT(&type) = VT_I1;
1709 V_I1(&type) = NODE_DOCUMENT_FRAGMENT;
1711 hr = IXMLDOMDocument3_createNode(iface, type, NULL, NULL, &node);
1712 if (hr == S_OK)
1714 IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMDocumentFragment, (void**)frag);
1715 IXMLDOMNode_Release(node);
1718 return hr;
1722 static HRESULT WINAPI domdoc_createTextNode(
1723 IXMLDOMDocument3 *iface,
1724 BSTR data,
1725 IXMLDOMText** text )
1727 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1728 IXMLDOMNode *node;
1729 VARIANT type;
1730 HRESULT hr;
1732 TRACE("(%p)->(%s %p)\n", This, debugstr_w(data), text);
1734 if (!text) return E_INVALIDARG;
1736 *text = NULL;
1738 V_VT(&type) = VT_I1;
1739 V_I1(&type) = NODE_TEXT;
1741 hr = IXMLDOMDocument3_createNode(iface, type, NULL, NULL, &node);
1742 if (hr == S_OK)
1744 IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMText, (void**)text);
1745 IXMLDOMNode_Release(node);
1746 hr = IXMLDOMText_put_data(*text, data);
1749 return hr;
1753 static HRESULT WINAPI domdoc_createComment(
1754 IXMLDOMDocument3 *iface,
1755 BSTR data,
1756 IXMLDOMComment** comment )
1758 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1759 VARIANT type;
1760 HRESULT hr;
1761 IXMLDOMNode *node;
1763 TRACE("(%p)->(%s %p)\n", This, debugstr_w(data), comment);
1765 if (!comment) return E_INVALIDARG;
1767 *comment = NULL;
1769 V_VT(&type) = VT_I1;
1770 V_I1(&type) = NODE_COMMENT;
1772 hr = IXMLDOMDocument3_createNode(iface, type, NULL, NULL, &node);
1773 if (hr == S_OK)
1775 IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMComment, (void**)comment);
1776 IXMLDOMNode_Release(node);
1777 hr = IXMLDOMComment_put_data(*comment, data);
1780 return hr;
1784 static HRESULT WINAPI domdoc_createCDATASection(
1785 IXMLDOMDocument3 *iface,
1786 BSTR data,
1787 IXMLDOMCDATASection** cdata )
1789 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1790 IXMLDOMNode *node;
1791 VARIANT type;
1792 HRESULT hr;
1794 TRACE("(%p)->(%s %p)\n", This, debugstr_w(data), cdata);
1796 if (!cdata) return E_INVALIDARG;
1798 *cdata = NULL;
1800 V_VT(&type) = VT_I1;
1801 V_I1(&type) = NODE_CDATA_SECTION;
1803 hr = IXMLDOMDocument3_createNode(iface, type, NULL, NULL, &node);
1804 if (hr == S_OK)
1806 IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMCDATASection, (void**)cdata);
1807 IXMLDOMNode_Release(node);
1808 hr = IXMLDOMCDATASection_put_data(*cdata, data);
1811 return hr;
1815 static HRESULT WINAPI domdoc_createProcessingInstruction(
1816 IXMLDOMDocument3 *iface,
1817 BSTR target,
1818 BSTR data,
1819 IXMLDOMProcessingInstruction** pi )
1821 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1822 IXMLDOMNode *node;
1823 VARIANT type;
1824 HRESULT hr;
1826 TRACE("(%p)->(%s %s %p)\n", This, debugstr_w(target), debugstr_w(data), pi);
1828 if (!pi) return E_INVALIDARG;
1830 *pi = NULL;
1832 V_VT(&type) = VT_I1;
1833 V_I1(&type) = NODE_PROCESSING_INSTRUCTION;
1835 hr = IXMLDOMDocument3_createNode(iface, type, target, NULL, &node);
1836 if (hr == S_OK)
1838 xmlnode *node_obj;
1840 /* this is to bypass check in ::put_data() that blocks "<?xml" PIs */
1841 node_obj = get_node_obj(node);
1842 hr = node_set_content(node_obj, data);
1844 IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMProcessingInstruction, (void**)pi);
1845 IXMLDOMNode_Release(node);
1848 return hr;
1852 static HRESULT WINAPI domdoc_createAttribute(
1853 IXMLDOMDocument3 *iface,
1854 BSTR name,
1855 IXMLDOMAttribute** attribute )
1857 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1858 IXMLDOMNode *node;
1859 VARIANT type;
1860 HRESULT hr;
1862 TRACE("(%p)->(%s %p)\n", This, debugstr_w(name), attribute);
1864 if (!attribute || !name) return E_INVALIDARG;
1866 V_VT(&type) = VT_I1;
1867 V_I1(&type) = NODE_ATTRIBUTE;
1869 hr = IXMLDOMDocument3_createNode(iface, type, name, NULL, &node);
1870 if (hr == S_OK)
1872 IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMAttribute, (void**)attribute);
1873 IXMLDOMNode_Release(node);
1876 return hr;
1880 static HRESULT WINAPI domdoc_createEntityReference(
1881 IXMLDOMDocument3 *iface,
1882 BSTR name,
1883 IXMLDOMEntityReference** entityref )
1885 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1886 IXMLDOMNode *node;
1887 VARIANT type;
1888 HRESULT hr;
1890 TRACE("(%p)->(%s %p)\n", This, debugstr_w(name), entityref);
1892 if (!entityref) return E_INVALIDARG;
1894 *entityref = NULL;
1896 V_VT(&type) = VT_I1;
1897 V_I1(&type) = NODE_ENTITY_REFERENCE;
1899 hr = IXMLDOMDocument3_createNode(iface, type, name, NULL, &node);
1900 if (hr == S_OK)
1902 IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMEntityReference, (void**)entityref);
1903 IXMLDOMNode_Release(node);
1906 return hr;
1909 xmlChar* tagName_to_XPath(const BSTR tagName)
1911 xmlChar *query, *tmp;
1912 static const xmlChar everything[] = "/descendant::node()";
1913 static const xmlChar mod_pre[] = "*[local-name()='";
1914 static const xmlChar mod_post[] = "']";
1915 static const xmlChar prefix[] = "descendant::";
1916 const WCHAR *tokBegin, *tokEnd;
1917 int len;
1919 /* Special case - empty tagname - means select all nodes,
1920 except document itself. */
1921 if (!*tagName)
1922 return xmlStrdup(everything);
1924 query = xmlStrdup(prefix);
1926 tokBegin = tagName;
1927 while (tokBegin && *tokBegin)
1929 switch (*tokBegin)
1931 case '/':
1932 query = xmlStrcat(query, BAD_CAST "/");
1933 ++tokBegin;
1934 break;
1935 case '*':
1936 query = xmlStrcat(query, BAD_CAST "*");
1937 ++tokBegin;
1938 break;
1939 default:
1940 query = xmlStrcat(query, mod_pre);
1941 tokEnd = tokBegin;
1942 while (*tokEnd && *tokEnd != '/')
1943 ++tokEnd;
1944 len = WideCharToMultiByte(CP_UTF8, 0, tokBegin, tokEnd-tokBegin, NULL, 0, NULL, NULL);
1945 tmp = xmlMalloc(len);
1946 WideCharToMultiByte(CP_UTF8, 0, tokBegin, tokEnd-tokBegin, (char*)tmp, len, NULL, NULL);
1947 query = xmlStrncat(query, tmp, len);
1948 xmlFree(tmp);
1949 tokBegin = tokEnd;
1950 query = xmlStrcat(query, mod_post);
1954 return query;
1957 static HRESULT WINAPI domdoc_getElementsByTagName(
1958 IXMLDOMDocument3 *iface,
1959 BSTR tagName,
1960 IXMLDOMNodeList** resultList )
1962 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1963 xmlChar *query;
1964 HRESULT hr;
1965 BOOL XPath;
1967 TRACE("(%p)->(%s, %p)\n", This, debugstr_w(tagName), resultList);
1969 if (!tagName || !resultList) return E_INVALIDARG;
1971 XPath = This->properties->XPath;
1972 This->properties->XPath = TRUE;
1973 query = tagName_to_XPath(tagName);
1974 hr = create_selection((xmlNodePtr)get_doc(This), query, resultList);
1975 xmlFree(query);
1976 This->properties->XPath = XPath;
1978 return hr;
1981 static HRESULT get_node_type(VARIANT Type, DOMNodeType * type)
1983 VARIANT tmp;
1984 HRESULT hr;
1986 VariantInit(&tmp);
1987 hr = VariantChangeType(&tmp, &Type, 0, VT_I4);
1988 if(FAILED(hr))
1989 return E_INVALIDARG;
1991 *type = V_I4(&tmp);
1993 return S_OK;
1996 static HRESULT WINAPI domdoc_createNode(
1997 IXMLDOMDocument3 *iface,
1998 VARIANT Type,
1999 BSTR name,
2000 BSTR namespaceURI,
2001 IXMLDOMNode** node )
2003 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2004 DOMNodeType node_type;
2005 xmlNodePtr xmlnode;
2006 xmlChar *xml_name, *href;
2007 HRESULT hr;
2009 TRACE("(%p)->(%s %s %s %p)\n", This, debugstr_variant(&Type), debugstr_w(name), debugstr_w(namespaceURI), node);
2011 if(!node) return E_INVALIDARG;
2013 hr = get_node_type(Type, &node_type);
2014 if(FAILED(hr)) return hr;
2016 TRACE("node_type %d\n", node_type);
2018 /* exit earlier for types that need name */
2019 switch(node_type)
2021 case NODE_ELEMENT:
2022 case NODE_ATTRIBUTE:
2023 case NODE_ENTITY_REFERENCE:
2024 case NODE_PROCESSING_INSTRUCTION:
2025 if (!name || *name == 0) return E_FAIL;
2026 break;
2027 default:
2028 break;
2031 xml_name = xmlchar_from_wchar(name);
2032 /* prevent empty href from being allocated */
2033 href = namespaceURI ? xmlchar_from_wchar(namespaceURI) : NULL;
2035 switch(node_type)
2037 case NODE_ELEMENT:
2039 xmlChar *local, *prefix;
2041 local = xmlSplitQName2(xml_name, &prefix);
2043 xmlnode = xmlNewDocNode(get_doc(This), NULL, local ? local : xml_name, NULL);
2045 /* allow creating the default namespace xmlns= */
2046 if (local || (href && *href))
2048 xmlNsPtr ns = xmlNewNs(xmlnode, href, prefix);
2049 xmlSetNs(xmlnode, ns);
2052 xmlFree(local);
2053 xmlFree(prefix);
2055 break;
2057 case NODE_ATTRIBUTE:
2059 xmlChar *local, *prefix;
2061 local = xmlSplitQName2(xml_name, &prefix);
2063 xmlnode = (xmlNodePtr)xmlNewDocProp(get_doc(This), local ? local : xml_name, NULL);
2065 if (local || (href && *href))
2067 /* we need a floating namespace here, it can't be created linked to attribute from
2068 a start */
2069 xmlNsPtr ns = xmlNewNs(NULL, href, prefix);
2070 xmlSetNs(xmlnode, ns);
2073 xmlFree(local);
2074 xmlFree(prefix);
2076 break;
2078 case NODE_TEXT:
2079 xmlnode = (xmlNodePtr)xmlNewDocText(get_doc(This), NULL);
2080 break;
2081 case NODE_CDATA_SECTION:
2082 xmlnode = xmlNewCDataBlock(get_doc(This), NULL, 0);
2083 break;
2084 case NODE_ENTITY_REFERENCE:
2085 xmlnode = xmlNewReference(get_doc(This), xml_name);
2086 break;
2087 case NODE_PROCESSING_INSTRUCTION:
2088 #ifdef HAVE_XMLNEWDOCPI
2089 xmlnode = xmlNewDocPI(get_doc(This), xml_name, NULL);
2090 #else
2091 FIXME("xmlNewDocPI() not supported, use libxml2 2.6.15 or greater\n");
2092 xmlnode = NULL;
2093 #endif
2094 break;
2095 case NODE_COMMENT:
2096 xmlnode = xmlNewDocComment(get_doc(This), NULL);
2097 break;
2098 case NODE_DOCUMENT_FRAGMENT:
2099 xmlnode = xmlNewDocFragment(get_doc(This));
2100 break;
2101 /* unsupported types */
2102 case NODE_DOCUMENT:
2103 case NODE_DOCUMENT_TYPE:
2104 case NODE_ENTITY:
2105 case NODE_NOTATION:
2106 heap_free(xml_name);
2107 return E_INVALIDARG;
2108 default:
2109 FIXME("unhandled node type %d\n", node_type);
2110 xmlnode = NULL;
2111 break;
2114 *node = create_node(xmlnode);
2115 heap_free(xml_name);
2116 heap_free(href);
2118 if(*node)
2120 TRACE("created node (%d, %p, %p)\n", node_type, *node, xmlnode);
2121 xmldoc_add_orphan(xmlnode->doc, xmlnode);
2122 return S_OK;
2125 return E_FAIL;
2128 static HRESULT WINAPI domdoc_nodeFromID(
2129 IXMLDOMDocument3 *iface,
2130 BSTR idString,
2131 IXMLDOMNode** node )
2133 domdoc *This = impl_from_IXMLDOMDocument3(iface);
2134 FIXME("(%p)->(%s %p)\n", This, debugstr_w(idString), node);
2135 return E_NOTIMPL;
2138 static HRESULT domdoc_onDataAvailable(void *obj, char *ptr, DWORD len)
2140 domdoc *This = obj;
2141 xmlDocPtr xmldoc;
2143 xmldoc = doparse(This, ptr, len, XML_CHAR_ENCODING_NONE);
2144 if(xmldoc) {
2145 xmldoc->_private = create_priv();
2146 return attach_xmldoc(This, xmldoc);
2149 return E_FAIL;
2152 static HRESULT domdoc_load_moniker(domdoc *This, IMoniker *mon)
2154 bsc_t *bsc;
2155 HRESULT hr;
2157 hr = bind_url(mon, domdoc_onDataAvailable, This, &bsc);
2158 if(FAILED(hr))
2159 return hr;
2161 return detach_bsc(bsc);
2164 static HRESULT WINAPI domdoc_load(
2165 IXMLDOMDocument3 *iface,
2166 VARIANT source,
2167 VARIANT_BOOL* isSuccessful )
2169 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2170 LPWSTR filename = NULL;
2171 HRESULT hr = S_FALSE;
2172 xmlDocPtr xmldoc;
2174 TRACE("(%p)->(%s)\n", This, debugstr_variant(&source));
2176 if (!isSuccessful)
2177 return E_POINTER;
2178 *isSuccessful = VARIANT_FALSE;
2180 assert( &This->node );
2182 switch( V_VT(&source) )
2184 case VT_BSTR:
2185 filename = V_BSTR(&source);
2186 break;
2187 case VT_BSTR|VT_BYREF:
2188 if (!V_BSTRREF(&source)) return E_INVALIDARG;
2189 filename = *V_BSTRREF(&source);
2190 break;
2191 case VT_ARRAY|VT_UI1:
2193 SAFEARRAY *psa = V_ARRAY(&source);
2194 char *str;
2195 LONG len;
2196 UINT dim = SafeArrayGetDim(psa);
2198 switch (dim)
2200 case 0:
2201 ERR("SAFEARRAY == NULL\n");
2202 hr = This->error = E_INVALIDARG;
2203 break;
2204 case 1:
2205 /* Only takes UTF-8 strings.
2206 * NOT NULL-terminated. */
2207 hr = SafeArrayAccessData(psa, (void**)&str);
2208 if (FAILED(hr))
2210 This->error = hr;
2211 WARN("failed to access array data, 0x%08x\n", hr);
2212 break;
2214 SafeArrayGetUBound(psa, 1, &len);
2216 if ((xmldoc = doparse(This, str, ++len, XML_CHAR_ENCODING_UTF8)))
2218 hr = This->error = S_OK;
2219 *isSuccessful = VARIANT_TRUE;
2220 TRACE("parsed document %p\n", xmldoc);
2222 else
2224 This->error = E_FAIL;
2225 TRACE("failed to parse document\n");
2228 SafeArrayUnaccessData(psa);
2230 if(xmldoc)
2232 xmldoc->_private = create_priv();
2233 return attach_xmldoc(This, xmldoc);
2235 break;
2236 default:
2237 FIXME("unhandled SAFEARRAY dim: %d\n", dim);
2238 hr = This->error = E_NOTIMPL;
2241 break;
2242 case VT_UNKNOWN:
2244 ISequentialStream *stream = NULL;
2245 IXMLDOMDocument3 *newdoc = NULL;
2247 if (!V_UNKNOWN(&source)) return E_INVALIDARG;
2249 hr = IUnknown_QueryInterface(V_UNKNOWN(&source), &IID_IXMLDOMDocument3, (void**)&newdoc);
2250 if(hr == S_OK)
2252 if(newdoc)
2254 domdoc *newDoc = impl_from_IXMLDOMDocument3( newdoc );
2256 xmldoc = xmlCopyDoc(get_doc(newDoc), 1);
2257 xmldoc->_private = create_priv();
2258 hr = attach_xmldoc(This, xmldoc);
2260 if(SUCCEEDED(hr))
2261 *isSuccessful = VARIANT_TRUE;
2263 return hr;
2267 hr = IUnknown_QueryInterface(V_UNKNOWN(&source), &IID_IStream, (void**)&stream);
2268 if (FAILED(hr))
2269 hr = IUnknown_QueryInterface(V_UNKNOWN(&source), &IID_ISequentialStream, (void**)&stream);
2271 if (hr == S_OK)
2273 hr = domdoc_load_from_stream(This, stream);
2274 if (hr == S_OK)
2275 *isSuccessful = VARIANT_TRUE;
2276 ISequentialStream_Release(stream);
2277 return hr;
2280 FIXME("unsupported IUnknown type (0x%08x) (%p)\n", hr, V_UNKNOWN(&source)->lpVtbl);
2281 break;
2283 default:
2284 FIXME("VT type not supported (%d)\n", V_VT(&source));
2287 if ( filename )
2289 IMoniker *mon;
2290 IUri *uri;
2292 if (This->properties->uri)
2294 IUri_Release(This->properties->uri);
2295 This->properties->uri = NULL;
2298 hr = create_uri(filename, &uri);
2299 if (SUCCEEDED(hr))
2300 hr = CreateURLMonikerEx2(NULL, uri, &mon, 0);
2301 if ( SUCCEEDED(hr) )
2303 hr = domdoc_load_moniker( This, mon );
2304 IMoniker_Release(mon);
2307 if ( FAILED(hr) )
2308 This->error = E_FAIL;
2309 else
2311 get_doc(This)->name = (char *)xmlchar_from_wcharn(filename, -1, TRUE);
2312 This->properties->uri = uri;
2313 hr = This->error = S_OK;
2314 *isSuccessful = VARIANT_TRUE;
2318 if(!filename || FAILED(hr)) {
2319 xmldoc = xmlNewDoc(NULL);
2320 xmldoc->_private = create_priv();
2321 hr = attach_xmldoc(This, xmldoc);
2322 if(SUCCEEDED(hr))
2323 hr = S_FALSE;
2326 TRACE("ret (%d)\n", hr);
2328 return hr;
2332 static HRESULT WINAPI domdoc_get_readyState(
2333 IXMLDOMDocument3 *iface,
2334 LONG *value )
2336 domdoc *This = impl_from_IXMLDOMDocument3(iface);
2337 FIXME("stub! (%p)->(%p)\n", This, value);
2339 if (!value)
2340 return E_INVALIDARG;
2342 *value = READYSTATE_COMPLETE;
2343 return S_OK;
2347 static HRESULT WINAPI domdoc_get_parseError(
2348 IXMLDOMDocument3 *iface,
2349 IXMLDOMParseError** errorObj )
2351 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2352 static const WCHAR err[] = {'e','r','r','o','r',0};
2353 BSTR error_string = NULL;
2355 FIXME("(%p)->(%p): creating a dummy parseError\n", iface, errorObj);
2357 if(This->error)
2358 error_string = SysAllocString(err);
2360 *errorObj = create_parseError(This->error, NULL, error_string, NULL, 0, 0, 0);
2361 if(!*errorObj) return E_OUTOFMEMORY;
2362 return S_OK;
2366 static HRESULT WINAPI domdoc_get_url(
2367 IXMLDOMDocument3 *iface,
2368 BSTR* url )
2370 domdoc *This = impl_from_IXMLDOMDocument3(iface);
2372 TRACE("(%p)->(%p)\n", This, url);
2374 if (!url)
2375 return E_INVALIDARG;
2377 if (!This->properties->uri)
2378 return return_null_bstr(url);
2380 return IUri_GetPropertyBSTR(This->properties->uri, Uri_PROPERTY_DISPLAY_URI, url, 0);
2384 static HRESULT WINAPI domdoc_get_async(
2385 IXMLDOMDocument3 *iface,
2386 VARIANT_BOOL* isAsync )
2388 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2390 TRACE("(%p)->(%p: %d)\n", This, isAsync, This->async);
2391 *isAsync = This->async;
2392 return S_OK;
2396 static HRESULT WINAPI domdoc_put_async(
2397 IXMLDOMDocument3 *iface,
2398 VARIANT_BOOL isAsync )
2400 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2402 TRACE("(%p)->(%d)\n", This, isAsync);
2403 This->async = isAsync;
2404 return S_OK;
2408 static HRESULT WINAPI domdoc_abort(
2409 IXMLDOMDocument3 *iface )
2411 domdoc *This = impl_from_IXMLDOMDocument3(iface);
2412 FIXME("%p\n", This);
2413 return E_NOTIMPL;
2416 /* don't rely on data to be in BSTR format, treat it as WCHAR string */
2417 static HRESULT WINAPI domdoc_loadXML(
2418 IXMLDOMDocument3 *iface,
2419 BSTR data,
2420 VARIANT_BOOL* isSuccessful )
2422 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2423 xmlDocPtr xmldoc = NULL;
2424 HRESULT hr = S_FALSE, hr2;
2426 TRACE("(%p)->(%s %p)\n", This, debugstr_w(data), isSuccessful );
2428 assert ( &This->node );
2430 if ( isSuccessful )
2432 *isSuccessful = VARIANT_FALSE;
2434 if (data)
2436 WCHAR *ptr = data;
2438 /* skip leading spaces if needed */
2439 if (This->properties->version == MSXML_DEFAULT || This->properties->version == MSXML26)
2440 while (*ptr && isspaceW(*ptr)) ptr++;
2442 xmldoc = doparse(This, (char*)ptr, strlenW(ptr)*sizeof(WCHAR), XML_CHAR_ENCODING_UTF16LE);
2443 if ( !xmldoc )
2445 This->error = E_FAIL;
2446 TRACE("failed to parse document\n");
2448 else
2450 hr = This->error = S_OK;
2451 *isSuccessful = VARIANT_TRUE;
2452 TRACE("parsed document %p\n", xmldoc);
2457 if(!xmldoc)
2458 xmldoc = xmlNewDoc(NULL);
2459 xmldoc->_private = create_priv();
2460 hr2 = attach_xmldoc(This, xmldoc);
2461 if( FAILED(hr2) )
2462 hr = hr2;
2464 return hr;
2467 static int XMLCALL domdoc_save_writecallback(void *ctx, const char *buffer, int len)
2469 DWORD written = -1;
2471 if(!WriteFile(ctx, buffer, len, &written, NULL))
2473 WARN("write error\n");
2474 return -1;
2476 else
2477 return written;
2480 static int XMLCALL domdoc_save_closecallback(void *ctx)
2482 return CloseHandle(ctx) ? 0 : -1;
2485 static int XMLCALL domdoc_stream_save_writecallback(void *ctx, const char *buffer, int len)
2487 ULONG written = 0;
2488 HRESULT hr;
2490 hr = IStream_Write((IStream*)ctx, buffer, len, &written);
2491 TRACE("0x%08x %p %d %u\n", hr, buffer, len, written);
2492 if (hr != S_OK)
2494 WARN("stream write error: 0x%08x\n", hr);
2495 return -1;
2497 else
2498 return len;
2501 static int XMLCALL domdoc_stream_save_closecallback(void *ctx)
2503 IStream_Release((IStream*)ctx);
2504 return 0;
2507 static HRESULT WINAPI domdoc_save(
2508 IXMLDOMDocument3 *iface,
2509 VARIANT destination )
2511 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2512 xmlSaveCtxtPtr ctx = NULL;
2513 xmlNodePtr xmldecl;
2514 HRESULT ret = S_OK;
2516 TRACE("(%p)->(%s)\n", This, debugstr_variant(&destination));
2518 switch (V_VT(&destination))
2520 case VT_UNKNOWN:
2522 IUnknown *pUnk = V_UNKNOWN(&destination);
2523 IXMLDOMDocument3 *document;
2524 IStream *stream;
2526 ret = IUnknown_QueryInterface(pUnk, &IID_IXMLDOMDocument3, (void**)&document);
2527 if(ret == S_OK)
2529 VARIANT_BOOL success;
2530 BSTR xml;
2532 ret = IXMLDOMDocument3_get_xml(iface, &xml);
2533 if(ret == S_OK)
2535 ret = IXMLDOMDocument3_loadXML(document, xml, &success);
2536 SysFreeString(xml);
2539 IXMLDOMDocument3_Release(document);
2540 return ret;
2543 ret = IUnknown_QueryInterface(pUnk, &IID_IStream, (void**)&stream);
2544 if(ret == S_OK)
2546 int options = get_doc(This)->standalone == -1 ? XML_SAVE_NO_DECL : 0;
2547 ctx = xmlSaveToIO(domdoc_stream_save_writecallback,
2548 domdoc_stream_save_closecallback, stream, NULL, options);
2550 if(!ctx)
2552 IStream_Release(stream);
2553 return E_FAIL;
2557 break;
2559 case VT_BSTR:
2560 case VT_BSTR | VT_BYREF:
2562 int options = get_doc(This)->standalone == -1 ? XML_SAVE_NO_DECL : 0;
2564 /* save with file path */
2565 HANDLE handle = CreateFileW( (V_VT(&destination) & VT_BYREF)? *V_BSTRREF(&destination) : V_BSTR(&destination),
2566 GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL );
2567 if( handle == INVALID_HANDLE_VALUE )
2569 WARN("failed to create file\n");
2570 return E_FAIL;
2573 /* disable top XML declaration */
2574 ctx = xmlSaveToIO(domdoc_save_writecallback, domdoc_save_closecallback,
2575 handle, NULL, options);
2576 if (!ctx)
2578 CloseHandle(handle);
2579 return E_FAIL;
2582 break;
2584 default:
2585 FIXME("Unhandled VARIANT: %s\n", debugstr_variant(&destination));
2586 return S_FALSE;
2589 xmldecl = xmldoc_unlink_xmldecl(get_doc(This));
2590 if (xmlSaveDoc(ctx, get_doc(This)) == -1) ret = S_FALSE;
2591 xmldoc_link_xmldecl(get_doc(This), xmldecl);
2593 /* will release resources through close callback */
2594 xmlSaveClose(ctx);
2596 return ret;
2599 static HRESULT WINAPI domdoc_get_validateOnParse(
2600 IXMLDOMDocument3 *iface,
2601 VARIANT_BOOL* isValidating )
2603 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2604 TRACE("(%p)->(%p: %d)\n", This, isValidating, This->validating);
2605 *isValidating = This->validating;
2606 return S_OK;
2610 static HRESULT WINAPI domdoc_put_validateOnParse(
2611 IXMLDOMDocument3 *iface,
2612 VARIANT_BOOL isValidating )
2614 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2615 TRACE("(%p)->(%d)\n", This, isValidating);
2616 This->validating = isValidating;
2617 return S_OK;
2621 static HRESULT WINAPI domdoc_get_resolveExternals(
2622 IXMLDOMDocument3 *iface,
2623 VARIANT_BOOL* isResolving )
2625 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2626 TRACE("(%p)->(%p: %d)\n", This, isResolving, This->resolving);
2627 *isResolving = This->resolving;
2628 return S_OK;
2632 static HRESULT WINAPI domdoc_put_resolveExternals(
2633 IXMLDOMDocument3 *iface,
2634 VARIANT_BOOL isResolving )
2636 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2637 TRACE("(%p)->(%d)\n", This, isResolving);
2638 This->resolving = isResolving;
2639 return S_OK;
2643 static HRESULT WINAPI domdoc_get_preserveWhiteSpace(
2644 IXMLDOMDocument3 *iface,
2645 VARIANT_BOOL* isPreserving )
2647 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2648 TRACE("(%p)->(%p: %d)\n", This, isPreserving, This->properties->preserving);
2649 *isPreserving = This->properties->preserving;
2650 return S_OK;
2654 static HRESULT WINAPI domdoc_put_preserveWhiteSpace(
2655 IXMLDOMDocument3 *iface,
2656 VARIANT_BOOL isPreserving )
2658 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2659 TRACE("(%p)->(%d)\n", This, isPreserving);
2660 This->properties->preserving = isPreserving;
2661 return S_OK;
2665 static HRESULT WINAPI domdoc_put_onreadystatechange(
2666 IXMLDOMDocument3 *iface,
2667 VARIANT event )
2669 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2671 TRACE("(%p)->(%s)\n", This, debugstr_variant(&event));
2672 return set_doc_event(This, EVENTID_READYSTATECHANGE, &event);
2676 static HRESULT WINAPI domdoc_put_onDataAvailable(IXMLDOMDocument3 *iface, VARIANT sink)
2678 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2679 FIXME("(%p)->(%s): stub\n", This, debugstr_variant(&sink));
2680 return E_NOTIMPL;
2683 static HRESULT WINAPI domdoc_put_onTransformNode(IXMLDOMDocument3 *iface, VARIANT sink )
2685 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2686 FIXME("(%p)->(%s): stub\n", This, debugstr_variant(&sink));
2687 return E_NOTIMPL;
2690 static HRESULT WINAPI domdoc_get_namespaces(
2691 IXMLDOMDocument3* iface,
2692 IXMLDOMSchemaCollection** collection )
2694 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2695 HRESULT hr;
2697 FIXME("(%p)->(%p): semi-stub\n", This, collection);
2699 if (!collection) return E_POINTER;
2701 if (!This->namespaces)
2703 hr = SchemaCache_create(This->properties->version, (void**)&This->namespaces);
2704 if (hr != S_OK) return hr;
2706 hr = cache_from_doc_ns(This->namespaces, &This->node);
2707 if (hr != S_OK)
2708 release_namespaces(This);
2711 if (This->namespaces)
2712 return IXMLDOMSchemaCollection2_QueryInterface(This->namespaces,
2713 &IID_IXMLDOMSchemaCollection, (void**)collection);
2715 return hr;
2718 static HRESULT WINAPI domdoc_get_schemas(
2719 IXMLDOMDocument3* iface,
2720 VARIANT* schema )
2722 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2723 IXMLDOMSchemaCollection2* cur_schema = This->properties->schemaCache;
2724 HRESULT hr = S_FALSE;
2726 TRACE("(%p)->(%p)\n", This, schema);
2728 V_VT(schema) = VT_NULL;
2729 /* just to reset pointer part, cause that's what application is expected to use */
2730 V_DISPATCH(schema) = NULL;
2732 if(cur_schema)
2734 hr = IXMLDOMSchemaCollection2_QueryInterface(cur_schema, &IID_IDispatch, (void**)&V_DISPATCH(schema));
2735 if(SUCCEEDED(hr))
2736 V_VT(schema) = VT_DISPATCH;
2738 return hr;
2741 static HRESULT WINAPI domdoc_putref_schemas(
2742 IXMLDOMDocument3* iface,
2743 VARIANT schema)
2745 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2746 HRESULT hr = E_FAIL;
2747 IXMLDOMSchemaCollection2* new_schema = NULL;
2749 FIXME("(%p)->(%s): semi-stub\n", This, debugstr_variant(&schema));
2750 switch(V_VT(&schema))
2752 case VT_UNKNOWN:
2753 if (V_UNKNOWN(&schema))
2755 hr = IUnknown_QueryInterface(V_UNKNOWN(&schema), &IID_IXMLDOMSchemaCollection, (void**)&new_schema);
2756 break;
2758 /* fallthrough */
2759 case VT_DISPATCH:
2760 if (V_DISPATCH(&schema))
2762 hr = IDispatch_QueryInterface(V_DISPATCH(&schema), &IID_IXMLDOMSchemaCollection, (void**)&new_schema);
2763 break;
2765 /* fallthrough */
2766 case VT_NULL:
2767 case VT_EMPTY:
2768 hr = S_OK;
2769 break;
2771 default:
2772 WARN("Can't get schema from vt %x\n", V_VT(&schema));
2775 if(SUCCEEDED(hr))
2777 IXMLDOMSchemaCollection2* old_schema = InterlockedExchangePointer((void**)&This->properties->schemaCache, new_schema);
2778 if(old_schema) IXMLDOMSchemaCollection2_Release(old_schema);
2781 return hr;
2784 static inline BOOL is_wellformed(xmlDocPtr doc)
2786 #ifdef HAVE_XMLDOC_PROPERTIES
2787 return doc->properties & XML_DOC_WELLFORMED;
2788 #else
2789 /* Not a full check, but catches the worst violations */
2790 xmlNodePtr child;
2791 int root = 0;
2793 for (child = doc->children; child != NULL; child = child->next)
2795 switch (child->type)
2797 case XML_ELEMENT_NODE:
2798 if (++root > 1)
2799 return FALSE;
2800 break;
2801 case XML_TEXT_NODE:
2802 case XML_CDATA_SECTION_NODE:
2803 return FALSE;
2804 break;
2805 default:
2806 break;
2810 return root == 1;
2811 #endif
2814 static void LIBXML2_LOG_CALLBACK validate_error(void* ctx, char const* msg, ...)
2816 va_list ap;
2817 va_start(ap, msg);
2818 LIBXML2_CALLBACK_ERR(domdoc_validateNode, msg, ap);
2819 va_end(ap);
2822 static void LIBXML2_LOG_CALLBACK validate_warning(void* ctx, char const* msg, ...)
2824 va_list ap;
2825 va_start(ap, msg);
2826 LIBXML2_CALLBACK_WARN(domdoc_validateNode, msg, ap);
2827 va_end(ap);
2830 static HRESULT WINAPI domdoc_validateNode(
2831 IXMLDOMDocument3* iface,
2832 IXMLDOMNode* node,
2833 IXMLDOMParseError** err)
2835 domdoc* This = impl_from_IXMLDOMDocument3(iface);
2836 LONG state, err_code = 0;
2837 HRESULT hr = S_OK;
2838 int validated = 0;
2840 TRACE("(%p)->(%p, %p)\n", This, node, err);
2841 IXMLDOMDocument3_get_readyState(iface, &state);
2842 if (state != READYSTATE_COMPLETE)
2844 if (err)
2845 *err = create_parseError(err_code, NULL, NULL, NULL, 0, 0, 0);
2846 return E_PENDING;
2849 if (!node)
2851 if (err)
2852 *err = create_parseError(err_code, NULL, NULL, NULL, 0, 0, 0);
2853 return E_POINTER;
2856 if (!get_node_obj(node)->node || get_node_obj(node)->node->doc != get_doc(This))
2858 if (err)
2859 *err = create_parseError(err_code, NULL, NULL, NULL, 0, 0, 0);
2860 return E_FAIL;
2863 if (!is_wellformed(get_doc(This)))
2865 ERR("doc not well-formed\n");
2866 if (err)
2867 *err = create_parseError(E_XML_NOTWF, NULL, NULL, NULL, 0, 0, 0);
2868 return S_FALSE;
2871 /* DTD validation */
2872 if (get_doc(This)->intSubset || get_doc(This)->extSubset)
2874 xmlValidCtxtPtr vctx = xmlNewValidCtxt();
2875 vctx->error = validate_error;
2876 vctx->warning = validate_warning;
2877 ++validated;
2879 if (!((node == (IXMLDOMNode*)iface)?
2880 xmlValidateDocument(vctx, get_doc(This)) :
2881 xmlValidateElement(vctx, get_doc(This), get_node_obj(node)->node)))
2883 /* TODO: get a real error code here */
2884 TRACE("DTD validation failed\n");
2885 err_code = E_XML_INVALID;
2886 hr = S_FALSE;
2888 xmlFreeValidCtxt(vctx);
2891 /* Schema validation */
2892 if (hr == S_OK && This->properties->schemaCache != NULL)
2895 hr = SchemaCache_validate_tree(This->properties->schemaCache, get_node_obj(node)->node);
2896 if (SUCCEEDED(hr))
2898 ++validated;
2899 /* TODO: get a real error code here */
2900 if (hr == S_OK)
2902 TRACE("schema validation succeeded\n");
2904 else
2906 ERR("schema validation failed\n");
2907 err_code = E_XML_INVALID;
2910 else
2912 /* not really OK, just didn't find a schema for the ns */
2913 hr = S_OK;
2917 if (!validated)
2919 ERR("no DTD or schema found\n");
2920 err_code = E_XML_NODTD;
2921 hr = S_FALSE;
2924 if (err)
2925 *err = create_parseError(err_code, NULL, NULL, NULL, 0, 0, 0);
2927 return hr;
2930 static HRESULT WINAPI domdoc_validate(
2931 IXMLDOMDocument3* iface,
2932 IXMLDOMParseError** err)
2934 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2935 TRACE("(%p)->(%p)\n", This, err);
2936 return IXMLDOMDocument3_validateNode(iface, (IXMLDOMNode*)iface, err);
2939 static HRESULT WINAPI domdoc_setProperty(
2940 IXMLDOMDocument3* iface,
2941 BSTR p,
2942 VARIANT value)
2944 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2946 TRACE("(%p)->(%s %s)\n", This, debugstr_w(p), debugstr_variant(&value));
2948 if (lstrcmpiW(p, PropertySelectionLanguageW) == 0)
2950 VARIANT varStr;
2951 HRESULT hr;
2952 BSTR bstr;
2954 V_VT(&varStr) = VT_EMPTY;
2955 if (V_VT(&value) != VT_BSTR)
2957 if (FAILED(hr = VariantChangeType(&varStr, &value, 0, VT_BSTR)))
2958 return hr;
2959 bstr = V_BSTR(&varStr);
2961 else
2962 bstr = V_BSTR(&value);
2964 hr = S_OK;
2965 if (lstrcmpiW(bstr, PropValueXPathW) == 0)
2966 This->properties->XPath = TRUE;
2967 else if (lstrcmpiW(bstr, PropValueXSLPatternW) == 0)
2968 This->properties->XPath = FALSE;
2969 else
2970 hr = E_FAIL;
2972 VariantClear(&varStr);
2973 return hr;
2975 else if (lstrcmpiW(p, PropertySelectionNamespacesW) == 0)
2977 xmlChar *nsStr = (xmlChar*)This->properties->selectNsStr;
2978 struct list *pNsList;
2979 VARIANT varStr;
2980 HRESULT hr;
2981 BSTR bstr;
2983 V_VT(&varStr) = VT_EMPTY;
2984 if (V_VT(&value) != VT_BSTR)
2986 if (FAILED(hr = VariantChangeType(&varStr, &value, 0, VT_BSTR)))
2987 return hr;
2988 bstr = V_BSTR(&varStr);
2990 else
2991 bstr = V_BSTR(&value);
2993 hr = S_OK;
2995 pNsList = &(This->properties->selectNsList);
2996 clear_selectNsList(pNsList);
2997 heap_free(nsStr);
2998 nsStr = xmlchar_from_wchar(bstr);
3000 TRACE("property value: \"%s\"\n", debugstr_w(bstr));
3002 This->properties->selectNsStr = nsStr;
3003 This->properties->selectNsStr_len = xmlStrlen(nsStr);
3004 if (bstr && *bstr)
3006 xmlChar *pTokBegin, *pTokEnd, *pTokInner;
3007 select_ns_entry* ns_entry = NULL;
3008 xmlXPathContextPtr ctx;
3010 ctx = xmlXPathNewContext(This->node.node->doc);
3011 pTokBegin = nsStr;
3013 /* skip leading spaces */
3014 while (*pTokBegin == ' ' || *pTokBegin == '\n' ||
3015 *pTokBegin == '\t' || *pTokBegin == '\r')
3016 ++pTokBegin;
3018 for (; *pTokBegin; pTokBegin = pTokEnd)
3020 if (ns_entry)
3021 memset(ns_entry, 0, sizeof(select_ns_entry));
3022 else
3023 ns_entry = heap_alloc_zero(sizeof(select_ns_entry));
3025 while (*pTokBegin == ' ')
3026 ++pTokBegin;
3027 pTokEnd = pTokBegin;
3028 while (*pTokEnd != ' ' && *pTokEnd != 0)
3029 ++pTokEnd;
3031 /* so it failed to advance which means we've got some trailing spaces */
3032 if (pTokEnd == pTokBegin) break;
3034 if (xmlStrncmp(pTokBegin, (xmlChar const*)"xmlns", 5) != 0)
3036 hr = E_FAIL;
3037 WARN("Syntax error in xmlns string: %s\n\tat token: %s\n",
3038 debugstr_w(bstr), debugstr_an((const char*)pTokBegin, pTokEnd-pTokBegin));
3039 continue;
3042 pTokBegin += 5;
3043 if (*pTokBegin == '=')
3045 /*valid for XSLPattern?*/
3046 FIXME("Setting default xmlns not supported - skipping.\n");
3047 continue;
3049 else if (*pTokBegin == ':')
3051 ns_entry->prefix = ++pTokBegin;
3052 for (pTokInner = pTokBegin; pTokInner != pTokEnd && *pTokInner != '='; ++pTokInner)
3055 if (pTokInner == pTokEnd)
3057 hr = E_FAIL;
3058 WARN("Syntax error in xmlns string: %s\n\tat token: %s\n",
3059 debugstr_w(bstr), debugstr_an((const char*)pTokBegin, pTokEnd-pTokBegin));
3060 continue;
3063 ns_entry->prefix_end = *pTokInner;
3064 *pTokInner = 0;
3065 ++pTokInner;
3067 if (pTokEnd-pTokInner > 1 &&
3068 ((*pTokInner == '\'' && *(pTokEnd-1) == '\'') ||
3069 (*pTokInner == '"' && *(pTokEnd-1) == '"')))
3071 ns_entry->href = ++pTokInner;
3072 ns_entry->href_end = *(pTokEnd-1);
3073 *(pTokEnd-1) = 0;
3074 list_add_tail(pNsList, &ns_entry->entry);
3075 /*let libxml figure out if they're valid from here ;)*/
3076 if (xmlXPathRegisterNs(ctx, ns_entry->prefix, ns_entry->href) != 0)
3078 hr = E_FAIL;
3080 ns_entry = NULL;
3081 continue;
3083 else
3085 WARN("Syntax error in xmlns string: %s\n\tat token: %s\n",
3086 debugstr_w(bstr), debugstr_an((const char*)pTokInner, pTokEnd-pTokInner));
3087 list_add_tail(pNsList, &ns_entry->entry);
3089 ns_entry = NULL;
3090 hr = E_FAIL;
3091 continue;
3094 else
3096 hr = E_FAIL;
3097 continue;
3100 heap_free(ns_entry);
3101 xmlXPathFreeContext(ctx);
3104 VariantClear(&varStr);
3105 return hr;
3107 else if (lstrcmpiW(p, PropertyProhibitDTDW) == 0 ||
3108 lstrcmpiW(p, PropertyNewParserW) == 0 ||
3109 lstrcmpiW(p, PropertyResolveExternalsW) == 0 ||
3110 lstrcmpiW(p, PropertyAllowXsltScriptW) == 0 ||
3111 lstrcmpiW(p, PropertyAllowDocumentFunctionW) == 0)
3113 /* Ignore */
3114 FIXME("Ignoring property %s, value %s\n", debugstr_w(p), debugstr_variant(&value));
3115 return S_OK;
3118 FIXME("Unknown property %s\n", debugstr_w(p));
3119 return E_FAIL;
3122 static HRESULT WINAPI domdoc_getProperty(
3123 IXMLDOMDocument3* iface,
3124 BSTR p,
3125 VARIANT* var)
3127 domdoc *This = impl_from_IXMLDOMDocument3( iface );
3129 TRACE("(%p)->(%s)\n", This, debugstr_w(p));
3131 if (!var)
3132 return E_INVALIDARG;
3134 if (lstrcmpiW(p, PropertySelectionLanguageW) == 0)
3136 V_VT(var) = VT_BSTR;
3137 V_BSTR(var) = This->properties->XPath ?
3138 SysAllocString(PropValueXPathW) :
3139 SysAllocString(PropValueXSLPatternW);
3140 return V_BSTR(var) ? S_OK : E_OUTOFMEMORY;
3142 else if (lstrcmpiW(p, PropertySelectionNamespacesW) == 0)
3144 int lenA, lenW;
3145 BSTR rebuiltStr, cur;
3146 const xmlChar *nsStr;
3147 struct list *pNsList;
3148 select_ns_entry* pNsEntry;
3150 V_VT(var) = VT_BSTR;
3151 nsStr = This->properties->selectNsStr;
3152 pNsList = &This->properties->selectNsList;
3153 lenA = This->properties->selectNsStr_len;
3154 lenW = MultiByteToWideChar(CP_UTF8, 0, (LPCSTR)nsStr, lenA+1, NULL, 0);
3155 rebuiltStr = heap_alloc(lenW*sizeof(WCHAR));
3156 MultiByteToWideChar(CP_UTF8, 0, (LPCSTR)nsStr, lenA+1, rebuiltStr, lenW);
3157 cur = rebuiltStr;
3158 /* this is fine because all of the chars that end tokens are ASCII*/
3159 LIST_FOR_EACH_ENTRY(pNsEntry, pNsList, select_ns_entry, entry)
3161 while (*cur != 0) ++cur;
3162 if (pNsEntry->prefix_end)
3164 *cur = pNsEntry->prefix_end;
3165 while (*cur != 0) ++cur;
3168 if (pNsEntry->href_end)
3170 *cur = pNsEntry->href_end;
3173 V_BSTR(var) = SysAllocString(rebuiltStr);
3174 heap_free(rebuiltStr);
3175 return S_OK;
3178 FIXME("Unknown property %s\n", debugstr_w(p));
3179 return E_FAIL;
3182 static HRESULT WINAPI domdoc_importNode(
3183 IXMLDOMDocument3* iface,
3184 IXMLDOMNode* node,
3185 VARIANT_BOOL deep,
3186 IXMLDOMNode** clone)
3188 domdoc *This = impl_from_IXMLDOMDocument3( iface );
3189 FIXME("(%p)->(%p %d %p): stub\n", This, node, deep, clone);
3190 return E_NOTIMPL;
3193 static const struct IXMLDOMDocument3Vtbl XMLDOMDocument3Vtbl =
3195 domdoc_QueryInterface,
3196 domdoc_AddRef,
3197 domdoc_Release,
3198 domdoc_GetTypeInfoCount,
3199 domdoc_GetTypeInfo,
3200 domdoc_GetIDsOfNames,
3201 domdoc_Invoke,
3202 domdoc_get_nodeName,
3203 domdoc_get_nodeValue,
3204 domdoc_put_nodeValue,
3205 domdoc_get_nodeType,
3206 domdoc_get_parentNode,
3207 domdoc_get_childNodes,
3208 domdoc_get_firstChild,
3209 domdoc_get_lastChild,
3210 domdoc_get_previousSibling,
3211 domdoc_get_nextSibling,
3212 domdoc_get_attributes,
3213 domdoc_insertBefore,
3214 domdoc_replaceChild,
3215 domdoc_removeChild,
3216 domdoc_appendChild,
3217 domdoc_hasChildNodes,
3218 domdoc_get_ownerDocument,
3219 domdoc_cloneNode,
3220 domdoc_get_nodeTypeString,
3221 domdoc_get_text,
3222 domdoc_put_text,
3223 domdoc_get_specified,
3224 domdoc_get_definition,
3225 domdoc_get_nodeTypedValue,
3226 domdoc_put_nodeTypedValue,
3227 domdoc_get_dataType,
3228 domdoc_put_dataType,
3229 domdoc_get_xml,
3230 domdoc_transformNode,
3231 domdoc_selectNodes,
3232 domdoc_selectSingleNode,
3233 domdoc_get_parsed,
3234 domdoc_get_namespaceURI,
3235 domdoc_get_prefix,
3236 domdoc_get_baseName,
3237 domdoc_transformNodeToObject,
3238 domdoc_get_doctype,
3239 domdoc_get_implementation,
3240 domdoc_get_documentElement,
3241 domdoc_put_documentElement,
3242 domdoc_createElement,
3243 domdoc_createDocumentFragment,
3244 domdoc_createTextNode,
3245 domdoc_createComment,
3246 domdoc_createCDATASection,
3247 domdoc_createProcessingInstruction,
3248 domdoc_createAttribute,
3249 domdoc_createEntityReference,
3250 domdoc_getElementsByTagName,
3251 domdoc_createNode,
3252 domdoc_nodeFromID,
3253 domdoc_load,
3254 domdoc_get_readyState,
3255 domdoc_get_parseError,
3256 domdoc_get_url,
3257 domdoc_get_async,
3258 domdoc_put_async,
3259 domdoc_abort,
3260 domdoc_loadXML,
3261 domdoc_save,
3262 domdoc_get_validateOnParse,
3263 domdoc_put_validateOnParse,
3264 domdoc_get_resolveExternals,
3265 domdoc_put_resolveExternals,
3266 domdoc_get_preserveWhiteSpace,
3267 domdoc_put_preserveWhiteSpace,
3268 domdoc_put_onreadystatechange,
3269 domdoc_put_onDataAvailable,
3270 domdoc_put_onTransformNode,
3271 domdoc_get_namespaces,
3272 domdoc_get_schemas,
3273 domdoc_putref_schemas,
3274 domdoc_validate,
3275 domdoc_setProperty,
3276 domdoc_getProperty,
3277 domdoc_validateNode,
3278 domdoc_importNode
3281 /* IConnectionPointContainer */
3282 static HRESULT WINAPI ConnectionPointContainer_QueryInterface(IConnectionPointContainer *iface,
3283 REFIID riid, void **ppv)
3285 domdoc *This = impl_from_IConnectionPointContainer(iface);
3286 return IXMLDOMDocument3_QueryInterface(&This->IXMLDOMDocument3_iface, riid, ppv);
3289 static ULONG WINAPI ConnectionPointContainer_AddRef(IConnectionPointContainer *iface)
3291 domdoc *This = impl_from_IConnectionPointContainer(iface);
3292 return IXMLDOMDocument3_AddRef(&This->IXMLDOMDocument3_iface);
3295 static ULONG WINAPI ConnectionPointContainer_Release(IConnectionPointContainer *iface)
3297 domdoc *This = impl_from_IConnectionPointContainer(iface);
3298 return IXMLDOMDocument3_Release(&This->IXMLDOMDocument3_iface);
3301 static HRESULT WINAPI ConnectionPointContainer_EnumConnectionPoints(IConnectionPointContainer *iface,
3302 IEnumConnectionPoints **ppEnum)
3304 domdoc *This = impl_from_IConnectionPointContainer(iface);
3305 FIXME("(%p)->(%p): stub\n", This, ppEnum);
3306 return E_NOTIMPL;
3309 static HRESULT WINAPI ConnectionPointContainer_FindConnectionPoint(IConnectionPointContainer *iface,
3310 REFIID riid, IConnectionPoint **cp)
3312 domdoc *This = impl_from_IConnectionPointContainer(iface);
3313 ConnectionPoint *iter;
3315 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), cp);
3317 *cp = NULL;
3319 for(iter = This->cp_list; iter; iter = iter->next)
3321 if (IsEqualGUID(iter->iid, riid))
3322 *cp = &iter->IConnectionPoint_iface;
3325 if (*cp)
3327 IConnectionPoint_AddRef(*cp);
3328 return S_OK;
3331 FIXME("unsupported riid %s\n", debugstr_guid(riid));
3332 return CONNECT_E_NOCONNECTION;
3336 static const struct IConnectionPointContainerVtbl ConnectionPointContainerVtbl =
3338 ConnectionPointContainer_QueryInterface,
3339 ConnectionPointContainer_AddRef,
3340 ConnectionPointContainer_Release,
3341 ConnectionPointContainer_EnumConnectionPoints,
3342 ConnectionPointContainer_FindConnectionPoint
3345 /* IConnectionPoint */
3346 static HRESULT WINAPI ConnectionPoint_QueryInterface(IConnectionPoint *iface,
3347 REFIID riid, void **ppv)
3349 ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3351 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv );
3353 *ppv = NULL;
3355 if (IsEqualGUID(&IID_IUnknown, riid) ||
3356 IsEqualGUID(&IID_IConnectionPoint, riid))
3358 *ppv = iface;
3361 if (*ppv)
3363 IConnectionPoint_AddRef(iface);
3364 return S_OK;
3367 WARN("Unsupported interface %s\n", debugstr_guid(riid));
3368 return E_NOINTERFACE;
3371 static ULONG WINAPI ConnectionPoint_AddRef(IConnectionPoint *iface)
3373 ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3374 return IConnectionPointContainer_AddRef(This->container);
3377 static ULONG WINAPI ConnectionPoint_Release(IConnectionPoint *iface)
3379 ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3380 return IConnectionPointContainer_Release(This->container);
3383 static HRESULT WINAPI ConnectionPoint_GetConnectionInterface(IConnectionPoint *iface, IID *iid)
3385 ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3387 TRACE("(%p)->(%p)\n", This, iid);
3389 if (!iid) return E_POINTER;
3391 *iid = *This->iid;
3392 return S_OK;
3395 static HRESULT WINAPI ConnectionPoint_GetConnectionPointContainer(IConnectionPoint *iface,
3396 IConnectionPointContainer **container)
3398 ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3400 TRACE("(%p)->(%p)\n", This, container);
3402 if (!container) return E_POINTER;
3404 *container = This->container;
3405 IConnectionPointContainer_AddRef(*container);
3406 return S_OK;
3409 static HRESULT WINAPI ConnectionPoint_Advise(IConnectionPoint *iface, IUnknown *unk_sink,
3410 DWORD *cookie)
3412 ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3413 IUnknown *sink;
3414 HRESULT hr;
3415 DWORD i;
3417 TRACE("(%p)->(%p %p)\n", This, unk_sink, cookie);
3419 hr = IUnknown_QueryInterface(unk_sink, This->iid, (void**)&sink);
3420 if(FAILED(hr) && !IsEqualGUID(&IID_IPropertyNotifySink, This->iid))
3421 hr = IUnknown_QueryInterface(unk_sink, &IID_IDispatch, (void**)&sink);
3422 if(FAILED(hr))
3423 return CONNECT_E_CANNOTCONNECT;
3425 if(This->sinks)
3427 for (i = 0; i < This->sinks_size; i++)
3428 if (!This->sinks[i].unk)
3429 break;
3431 if (i == This->sinks_size)
3432 This->sinks = heap_realloc(This->sinks,(++This->sinks_size)*sizeof(*This->sinks));
3434 else
3436 This->sinks = heap_alloc(sizeof(*This->sinks));
3437 This->sinks_size = 1;
3438 i = 0;
3441 This->sinks[i].unk = sink;
3442 if (cookie)
3443 *cookie = i+1;
3445 return S_OK;
3448 static HRESULT WINAPI ConnectionPoint_Unadvise(IConnectionPoint *iface, DWORD cookie)
3450 ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3452 TRACE("(%p)->(%d)\n", This, cookie);
3454 if (cookie == 0 || cookie > This->sinks_size || !This->sinks[cookie-1].unk)
3455 return CONNECT_E_NOCONNECTION;
3457 IUnknown_Release(This->sinks[cookie-1].unk);
3458 This->sinks[cookie-1].unk = NULL;
3460 return S_OK;
3463 static HRESULT WINAPI ConnectionPoint_EnumConnections(IConnectionPoint *iface,
3464 IEnumConnections **ppEnum)
3466 ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3467 FIXME("(%p)->(%p): stub\n", This, ppEnum);
3468 return E_NOTIMPL;
3471 static const IConnectionPointVtbl ConnectionPointVtbl =
3473 ConnectionPoint_QueryInterface,
3474 ConnectionPoint_AddRef,
3475 ConnectionPoint_Release,
3476 ConnectionPoint_GetConnectionInterface,
3477 ConnectionPoint_GetConnectionPointContainer,
3478 ConnectionPoint_Advise,
3479 ConnectionPoint_Unadvise,
3480 ConnectionPoint_EnumConnections
3483 static void ConnectionPoint_Init(ConnectionPoint *cp, struct domdoc *doc, REFIID riid)
3485 cp->IConnectionPoint_iface.lpVtbl = &ConnectionPointVtbl;
3486 cp->doc = doc;
3487 cp->iid = riid;
3488 cp->sinks = NULL;
3489 cp->sinks_size = 0;
3491 cp->next = doc->cp_list;
3492 doc->cp_list = cp;
3494 cp->container = &doc->IConnectionPointContainer_iface;
3497 /* domdoc implementation of IObjectWithSite */
3498 static HRESULT WINAPI
3499 domdoc_ObjectWithSite_QueryInterface( IObjectWithSite* iface, REFIID riid, void** ppvObject )
3501 domdoc *This = impl_from_IObjectWithSite(iface);
3502 return IXMLDOMDocument3_QueryInterface(&This->IXMLDOMDocument3_iface, riid, ppvObject);
3505 static ULONG WINAPI domdoc_ObjectWithSite_AddRef( IObjectWithSite* iface )
3507 domdoc *This = impl_from_IObjectWithSite(iface);
3508 return IXMLDOMDocument3_AddRef(&This->IXMLDOMDocument3_iface);
3511 static ULONG WINAPI domdoc_ObjectWithSite_Release( IObjectWithSite* iface )
3513 domdoc *This = impl_from_IObjectWithSite(iface);
3514 return IXMLDOMDocument3_Release(&This->IXMLDOMDocument3_iface);
3517 static HRESULT WINAPI domdoc_ObjectWithSite_GetSite( IObjectWithSite *iface, REFIID iid, void **ppvSite )
3519 domdoc *This = impl_from_IObjectWithSite(iface);
3521 TRACE("(%p)->(%s %p)\n", This, debugstr_guid( iid ), ppvSite );
3523 if ( !This->site )
3524 return E_FAIL;
3526 return IUnknown_QueryInterface( This->site, iid, ppvSite );
3529 static HRESULT WINAPI domdoc_ObjectWithSite_SetSite( IObjectWithSite *iface, IUnknown *punk )
3531 domdoc *This = impl_from_IObjectWithSite(iface);
3533 TRACE("(%p)->(%p)\n", iface, punk);
3535 if(!punk)
3537 if(This->site)
3539 IUnknown_Release( This->site );
3540 This->site = NULL;
3543 return S_OK;
3546 IUnknown_AddRef( punk );
3548 if(This->site)
3549 IUnknown_Release( This->site );
3551 This->site = punk;
3553 return S_OK;
3556 static const IObjectWithSiteVtbl domdocObjectSite =
3558 domdoc_ObjectWithSite_QueryInterface,
3559 domdoc_ObjectWithSite_AddRef,
3560 domdoc_ObjectWithSite_Release,
3561 domdoc_ObjectWithSite_SetSite,
3562 domdoc_ObjectWithSite_GetSite
3565 static HRESULT WINAPI domdoc_Safety_QueryInterface(IObjectSafety *iface, REFIID riid, void **ppv)
3567 domdoc *This = impl_from_IObjectSafety(iface);
3568 return IXMLDOMDocument3_QueryInterface(&This->IXMLDOMDocument3_iface, riid, ppv);
3571 static ULONG WINAPI domdoc_Safety_AddRef(IObjectSafety *iface)
3573 domdoc *This = impl_from_IObjectSafety(iface);
3574 return IXMLDOMDocument3_AddRef(&This->IXMLDOMDocument3_iface);
3577 static ULONG WINAPI domdoc_Safety_Release(IObjectSafety *iface)
3579 domdoc *This = impl_from_IObjectSafety(iface);
3580 return IXMLDOMDocument3_Release(&This->IXMLDOMDocument3_iface);
3583 #define SAFETY_SUPPORTED_OPTIONS (INTERFACESAFE_FOR_UNTRUSTED_CALLER|INTERFACESAFE_FOR_UNTRUSTED_DATA|INTERFACE_USES_SECURITY_MANAGER)
3585 static HRESULT WINAPI domdoc_Safety_GetInterfaceSafetyOptions(IObjectSafety *iface, REFIID riid,
3586 DWORD *supported, DWORD *enabled)
3588 domdoc *This = impl_from_IObjectSafety(iface);
3590 TRACE("(%p)->(%s %p %p)\n", This, debugstr_guid(riid), supported, enabled);
3592 if(!supported || !enabled) return E_POINTER;
3594 *supported = SAFETY_SUPPORTED_OPTIONS;
3595 *enabled = This->safeopt;
3597 return S_OK;
3600 static HRESULT WINAPI domdoc_Safety_SetInterfaceSafetyOptions(IObjectSafety *iface, REFIID riid,
3601 DWORD mask, DWORD enabled)
3603 domdoc *This = impl_from_IObjectSafety(iface);
3604 TRACE("(%p)->(%s %x %x)\n", This, debugstr_guid(riid), mask, enabled);
3606 if ((mask & ~SAFETY_SUPPORTED_OPTIONS) != 0)
3607 return E_FAIL;
3609 This->safeopt = (This->safeopt & ~mask) | (mask & enabled);
3611 return S_OK;
3614 #undef SAFETY_SUPPORTED_OPTIONS
3616 static const IObjectSafetyVtbl domdocObjectSafetyVtbl = {
3617 domdoc_Safety_QueryInterface,
3618 domdoc_Safety_AddRef,
3619 domdoc_Safety_Release,
3620 domdoc_Safety_GetInterfaceSafetyOptions,
3621 domdoc_Safety_SetInterfaceSafetyOptions
3624 static const tid_t domdoc_iface_tids[] = {
3625 IXMLDOMDocument3_tid,
3629 static dispex_static_data_t domdoc_dispex = {
3630 NULL,
3631 IXMLDOMDocument3_tid,
3632 NULL,
3633 domdoc_iface_tids
3636 HRESULT get_domdoc_from_xmldoc(xmlDocPtr xmldoc, IXMLDOMDocument3 **document)
3638 domdoc *doc;
3640 doc = heap_alloc( sizeof (*doc) );
3641 if( !doc )
3642 return E_OUTOFMEMORY;
3644 doc->IXMLDOMDocument3_iface.lpVtbl = &XMLDOMDocument3Vtbl;
3645 doc->IPersistStreamInit_iface.lpVtbl = &xmldoc_IPersistStreamInit_VTable;
3646 doc->IObjectWithSite_iface.lpVtbl = &domdocObjectSite;
3647 doc->IObjectSafety_iface.lpVtbl = &domdocObjectSafetyVtbl;
3648 doc->IConnectionPointContainer_iface.lpVtbl = &ConnectionPointContainerVtbl;
3649 doc->ref = 1;
3650 doc->async = VARIANT_TRUE;
3651 doc->validating = 0;
3652 doc->resolving = 0;
3653 doc->properties = properties_from_xmlDocPtr(xmldoc);
3654 doc->error = S_OK;
3655 doc->site = NULL;
3656 doc->safeopt = 0;
3657 doc->cp_list = NULL;
3658 doc->namespaces = NULL;
3659 memset(doc->events, 0, sizeof(doc->events));
3661 /* events connection points */
3662 ConnectionPoint_Init(&doc->cp_dispatch, doc, &IID_IDispatch);
3663 ConnectionPoint_Init(&doc->cp_propnotif, doc, &IID_IPropertyNotifySink);
3664 ConnectionPoint_Init(&doc->cp_domdocevents, doc, &DIID_XMLDOMDocumentEvents);
3666 init_xmlnode(&doc->node, (xmlNodePtr)xmldoc, (IXMLDOMNode*)&doc->IXMLDOMDocument3_iface,
3667 &domdoc_dispex);
3669 *document = &doc->IXMLDOMDocument3_iface;
3671 TRACE("returning iface %p\n", *document);
3672 return S_OK;
3675 HRESULT DOMDocument_create(MSXML_VERSION version, void **ppObj)
3677 xmlDocPtr xmldoc;
3678 HRESULT hr;
3680 TRACE("(%d, %p)\n", version, ppObj);
3682 xmldoc = xmlNewDoc(NULL);
3683 if(!xmldoc)
3684 return E_OUTOFMEMORY;
3686 xmldoc_init(xmldoc, version);
3688 hr = get_domdoc_from_xmldoc(xmldoc, (IXMLDOMDocument3**)ppObj);
3689 if(FAILED(hr))
3691 free_properties(properties_from_xmlDocPtr(xmldoc));
3692 heap_free(xmldoc->_private);
3693 xmlFreeDoc(xmldoc);
3694 return hr;
3697 return hr;
3700 IUnknown* create_domdoc( xmlNodePtr document )
3702 IUnknown *obj = NULL;
3703 HRESULT hr;
3705 TRACE("(%p)\n", document);
3707 hr = get_domdoc_from_xmldoc((xmlDocPtr)document, (IXMLDOMDocument3**)&obj);
3708 if (FAILED(hr))
3709 return NULL;
3711 return obj;
3714 #else
3716 HRESULT DOMDocument_create(MSXML_VERSION version, void **ppObj)
3718 MESSAGE("This program tried to use a DOMDocument object, but\n"
3719 "libxml2 support was not present at compile time.\n");
3720 return E_NOTIMPL;
3723 #endif