msvcr120: Add _dpcomp implementation.
[wine.git] / dlls / msxml3 / domdoc.c
blob36432190bb4d75e9b0dfdb5ec23fef9dfba7cf2a
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};
75 /* Anything that passes the test_get_ownerDocument()
76 * tests can go here (data shared between all instances).
77 * We need to preserve this when reloading a document,
78 * and also need access to it from the libxml backend. */
79 typedef struct {
80 MSXML_VERSION version;
81 VARIANT_BOOL preserving;
82 IXMLDOMSchemaCollection2* schemaCache;
83 struct list selectNsList;
84 xmlChar const* selectNsStr;
85 LONG selectNsStr_len;
86 BOOL XPath;
87 WCHAR *url;
88 } domdoc_properties;
90 typedef struct ConnectionPoint ConnectionPoint;
91 typedef struct domdoc domdoc;
93 struct ConnectionPoint
95 IConnectionPoint IConnectionPoint_iface;
96 const IID *iid;
98 ConnectionPoint *next;
99 IConnectionPointContainer *container;
100 domdoc *doc;
102 union
104 IUnknown *unk;
105 IDispatch *disp;
106 IPropertyNotifySink *propnotif;
107 } *sinks;
108 DWORD sinks_size;
111 typedef enum {
112 EVENTID_READYSTATECHANGE = 0,
113 EVENTID_DATAAVAILABLE,
114 EVENTID_TRANSFORMNODE,
115 EVENTID_LAST
116 } eventid_t;
118 struct domdoc
120 xmlnode node;
121 IXMLDOMDocument3 IXMLDOMDocument3_iface;
122 IPersistStreamInit IPersistStreamInit_iface;
123 IObjectWithSite IObjectWithSite_iface;
124 IObjectSafety IObjectSafety_iface;
125 IConnectionPointContainer IConnectionPointContainer_iface;
126 LONG ref;
127 VARIANT_BOOL async;
128 VARIANT_BOOL validating;
129 VARIANT_BOOL resolving;
130 domdoc_properties* properties;
131 HRESULT error;
133 /* IObjectWithSite */
134 IUnknown *site;
136 /* IObjectSafety */
137 DWORD safeopt;
139 /* connection list */
140 ConnectionPoint *cp_list;
141 ConnectionPoint cp_domdocevents;
142 ConnectionPoint cp_propnotif;
143 ConnectionPoint cp_dispatch;
145 /* events */
146 IDispatch *events[EVENTID_LAST];
148 IXMLDOMSchemaCollection2 *namespaces;
151 static HRESULT set_doc_event(domdoc *doc, eventid_t eid, const VARIANT *v)
153 IDispatch *disp;
155 switch (V_VT(v))
157 case VT_UNKNOWN:
158 if (V_UNKNOWN(v))
159 IUnknown_QueryInterface(V_UNKNOWN(v), &IID_IDispatch, (void**)&disp);
160 else
161 disp = NULL;
162 break;
163 case VT_DISPATCH:
164 disp = V_DISPATCH(v);
165 if (disp) IDispatch_AddRef(disp);
166 break;
167 default:
168 return DISP_E_TYPEMISMATCH;
171 if (doc->events[eid]) IDispatch_Release(doc->events[eid]);
172 doc->events[eid] = disp;
174 return S_OK;
177 static inline ConnectionPoint *impl_from_IConnectionPoint(IConnectionPoint *iface)
179 return CONTAINING_RECORD(iface, ConnectionPoint, IConnectionPoint_iface);
183 In native windows, the whole lifetime management of XMLDOMNodes is
184 managed automatically using reference counts. Wine emulates that by
185 maintaining a reference count to the document that is increased for
186 each IXMLDOMNode pointer passed out for this document. If all these
187 pointers are gone, the document is unreachable and gets freed, that
188 is, all nodes in the tree of the document get freed.
190 You are able to create nodes that are associated to a document (in
191 fact, in msxml's XMLDOM model, all nodes are associated to a document),
192 but not in the tree of that document, for example using the createFoo
193 functions from IXMLDOMDocument. These nodes do not get cleaned up
194 by libxml, so we have to do it ourselves.
196 To catch these nodes, a list of "orphan nodes" is introduced.
197 It contains pointers to all roots of node trees that are
198 associated with the document without being part of the document
199 tree. All nodes with parent==NULL (except for the document root nodes)
200 should be in the orphan node list of their document. All orphan nodes
201 get freed together with the document itself.
204 typedef struct _xmldoc_priv {
205 LONG refs;
206 struct list orphans;
207 domdoc_properties* properties;
208 } xmldoc_priv;
210 typedef struct _orphan_entry {
211 struct list entry;
212 xmlNode * node;
213 } orphan_entry;
215 typedef struct _select_ns_entry {
216 struct list entry;
217 xmlChar const* prefix;
218 xmlChar prefix_end;
219 xmlChar const* href;
220 xmlChar href_end;
221 } select_ns_entry;
223 static inline xmldoc_priv * priv_from_xmlDocPtr(const xmlDocPtr doc)
225 return doc->_private;
228 static inline domdoc_properties * properties_from_xmlDocPtr(xmlDocPtr doc)
230 return priv_from_xmlDocPtr(doc)->properties;
233 BOOL is_xpathmode(const xmlDocPtr doc)
235 return properties_from_xmlDocPtr(doc)->XPath;
238 void set_xpathmode(xmlDocPtr doc, BOOL xpath)
240 properties_from_xmlDocPtr(doc)->XPath = xpath;
243 int registerNamespaces(xmlXPathContextPtr ctxt)
245 int n = 0;
246 const select_ns_entry* ns = NULL;
247 const struct list* pNsList = &properties_from_xmlDocPtr(ctxt->doc)->selectNsList;
249 TRACE("(%p)\n", ctxt);
251 LIST_FOR_EACH_ENTRY( ns, pNsList, select_ns_entry, entry )
253 xmlXPathRegisterNs(ctxt, ns->prefix, ns->href);
254 ++n;
257 return n;
260 static inline void clear_selectNsList(struct list* pNsList)
262 select_ns_entry *ns, *ns2;
263 LIST_FOR_EACH_ENTRY_SAFE( ns, ns2, pNsList, select_ns_entry, entry )
265 heap_free( ns );
267 list_init(pNsList);
270 static xmldoc_priv * create_priv(void)
272 xmldoc_priv *priv;
273 priv = heap_alloc( sizeof (*priv) );
275 if (priv)
277 priv->refs = 0;
278 list_init( &priv->orphans );
279 priv->properties = NULL;
282 return priv;
285 static domdoc_properties *create_properties(MSXML_VERSION version)
287 domdoc_properties *properties = heap_alloc(sizeof(domdoc_properties));
289 list_init(&properties->selectNsList);
290 properties->preserving = VARIANT_FALSE;
291 properties->schemaCache = NULL;
292 properties->selectNsStr = heap_alloc_zero(sizeof(xmlChar));
293 properties->selectNsStr_len = 0;
295 /* properties that are dependent on object versions */
296 properties->version = version;
297 properties->XPath = (version == MSXML4 || version == MSXML6);
299 /* document url */
300 properties->url = NULL;
302 return properties;
305 static domdoc_properties* copy_properties(domdoc_properties const* properties)
307 domdoc_properties* pcopy = heap_alloc(sizeof(domdoc_properties));
308 select_ns_entry const* ns = NULL;
309 select_ns_entry* new_ns = NULL;
310 int len = (properties->selectNsStr_len+1)*sizeof(xmlChar);
311 ptrdiff_t offset;
313 if (pcopy)
315 pcopy->version = properties->version;
316 pcopy->preserving = properties->preserving;
317 pcopy->schemaCache = properties->schemaCache;
318 if (pcopy->schemaCache)
319 IXMLDOMSchemaCollection2_AddRef(pcopy->schemaCache);
320 pcopy->XPath = properties->XPath;
321 pcopy->selectNsStr_len = properties->selectNsStr_len;
322 list_init( &pcopy->selectNsList );
323 pcopy->selectNsStr = heap_alloc(len);
324 memcpy((xmlChar*)pcopy->selectNsStr, properties->selectNsStr, len);
325 offset = pcopy->selectNsStr - properties->selectNsStr;
327 LIST_FOR_EACH_ENTRY( ns, (&properties->selectNsList), select_ns_entry, entry )
329 new_ns = heap_alloc(sizeof(select_ns_entry));
330 memcpy(new_ns, ns, sizeof(select_ns_entry));
331 new_ns->href += offset;
332 new_ns->prefix += offset;
333 list_add_tail(&pcopy->selectNsList, &new_ns->entry);
336 if (properties->url)
338 int len = strlenW(properties->url);
340 pcopy->url = CoTaskMemAlloc((len+1)*sizeof(WCHAR));
341 memcpy(pcopy->url, properties->url, len*sizeof(WCHAR));
342 pcopy->url[len] = 0;
344 else
345 pcopy->url = NULL;
348 return pcopy;
351 static void free_properties(domdoc_properties* properties)
353 if (properties)
355 if (properties->schemaCache)
356 IXMLDOMSchemaCollection2_Release(properties->schemaCache);
357 clear_selectNsList(&properties->selectNsList);
358 heap_free((xmlChar*)properties->selectNsStr);
359 CoTaskMemFree(properties->url);
360 heap_free(properties);
364 static void release_namespaces(domdoc *This)
366 if (This->namespaces)
368 IXMLDOMSchemaCollection2_Release(This->namespaces);
369 This->namespaces = NULL;
373 /* links a "<?xml" node as a first child */
374 void xmldoc_link_xmldecl(xmlDocPtr doc, xmlNodePtr node)
376 assert(doc != NULL);
377 if (doc->standalone != -1) xmlAddPrevSibling( doc->children, node );
380 /* unlinks a first "<?xml" child if it was created */
381 xmlNodePtr xmldoc_unlink_xmldecl(xmlDocPtr doc)
383 static const xmlChar xmlA[] = "xml";
384 xmlNodePtr node, first_child;
386 assert(doc != NULL);
388 /* xml declaration node could be created automatically after parsing or added
389 to a tree later */
390 first_child = doc->children;
391 if (first_child && first_child->type == XML_PI_NODE && xmlStrEqual(first_child->name, xmlA))
393 node = first_child;
394 xmlUnlinkNode( node );
396 else
397 node = NULL;
399 return node;
402 BOOL is_preserving_whitespace(xmlNodePtr node)
404 domdoc_properties* properties = NULL;
405 /* during parsing the xmlDoc._private stuff is not there */
406 if (priv_from_xmlDocPtr(node->doc))
407 properties = properties_from_xmlDocPtr(node->doc);
408 return ((properties && properties->preserving == VARIANT_TRUE) ||
409 xmlNodeGetSpacePreserve(node) == 1);
412 static inline BOOL strn_isspace(xmlChar const* str, int len)
414 for (; str && len > 0 && *str; ++str, --len)
415 if (!isspace(*str))
416 break;
418 return len == 0;
421 static void sax_characters(void *ctx, const xmlChar *ch, int len)
423 xmlParserCtxtPtr ctxt;
424 const domdoc *This;
426 ctxt = (xmlParserCtxtPtr) ctx;
427 This = (const domdoc*) ctxt->_private;
429 if (ctxt->node)
431 xmlChar cur = *(ctxt->input->cur);
433 /* Characters are reported with multiple calls, for example each charref is reported with a separate
434 call and then parser appends it to a single text node or creates a new node if not created.
435 It's not possible to tell if it's ignorable data or not just looking at data itself cause it could be
436 space chars that separate charrefs or similar case. We only need to skip leading and trailing spaces,
437 or whole node if it has nothing but space chars, so to detect leading space node->last is checked that
438 contains text node pointer if already created, trailing spaces are detected directly looking at parser input
439 for next '<' opening bracket - similar logic is used by libxml2 itself. Basically 'cur' == '<' means the last
440 chunk of char data, in case it's not the last chunk we check for previously added node type and if it's not
441 a text node it's safe to ignore.
443 Note that during domdoc_loadXML() the xmlDocPtr->_private data is not available. */
445 if (!This->properties->preserving &&
446 !is_preserving_whitespace(ctxt->node) &&
447 strn_isspace(ch, len) &&
448 (!ctxt->node->last ||
449 ((ctxt->node->last && (cur == '<' || ctxt->node->last->type != XML_TEXT_NODE))
452 /* Keep information about ignorable whitespace text node in previous or parent node */
453 if (ctxt->node->last)
454 *(DWORD*)&ctxt->node->last->_private |= NODE_PRIV_TRAILING_IGNORABLE_WS;
455 else if (ctxt->node->type != XML_DOCUMENT_NODE)
456 *(DWORD*)&ctxt->node->_private |= NODE_PRIV_CHILD_IGNORABLE_WS;
457 return;
461 xmlSAX2Characters(ctxt, ch, len);
464 static void LIBXML2_LOG_CALLBACK sax_error(void* ctx, char const* msg, ...)
466 va_list ap;
467 va_start(ap, msg);
468 LIBXML2_CALLBACK_ERR(doparse, msg, ap);
469 va_end(ap);
472 static void LIBXML2_LOG_CALLBACK sax_warning(void* ctx, char const* msg, ...)
474 va_list ap;
475 va_start(ap, msg);
476 LIBXML2_CALLBACK_WARN(doparse, msg, ap);
477 va_end(ap);
480 static void sax_serror(void* ctx, xmlErrorPtr err)
482 LIBXML2_CALLBACK_SERROR(doparse, err);
485 static xmlDocPtr doparse(domdoc* This, char const* ptr, int len, xmlCharEncoding encoding)
487 xmlDocPtr doc = NULL;
488 xmlParserCtxtPtr pctx;
489 static xmlSAXHandler sax_handler = {
490 xmlSAX2InternalSubset, /* internalSubset */
491 xmlSAX2IsStandalone, /* isStandalone */
492 xmlSAX2HasInternalSubset, /* hasInternalSubset */
493 xmlSAX2HasExternalSubset, /* hasExternalSubset */
494 xmlSAX2ResolveEntity, /* resolveEntity */
495 xmlSAX2GetEntity, /* getEntity */
496 xmlSAX2EntityDecl, /* entityDecl */
497 xmlSAX2NotationDecl, /* notationDecl */
498 xmlSAX2AttributeDecl, /* attributeDecl */
499 xmlSAX2ElementDecl, /* elementDecl */
500 xmlSAX2UnparsedEntityDecl, /* unparsedEntityDecl */
501 xmlSAX2SetDocumentLocator, /* setDocumentLocator */
502 xmlSAX2StartDocument, /* startDocument */
503 xmlSAX2EndDocument, /* endDocument */
504 xmlSAX2StartElement, /* startElement */
505 xmlSAX2EndElement, /* endElement */
506 xmlSAX2Reference, /* reference */
507 sax_characters, /* characters */
508 sax_characters, /* ignorableWhitespace */
509 xmlSAX2ProcessingInstruction, /* processingInstruction */
510 xmlSAX2Comment, /* comment */
511 sax_warning, /* warning */
512 sax_error, /* error */
513 sax_error, /* fatalError */
514 xmlSAX2GetParameterEntity, /* getParameterEntity */
515 xmlSAX2CDataBlock, /* cdataBlock */
516 xmlSAX2ExternalSubset, /* externalSubset */
517 0, /* initialized */
518 NULL, /* _private */
519 xmlSAX2StartElementNs, /* startElementNs */
520 xmlSAX2EndElementNs, /* endElementNs */
521 sax_serror /* serror */
524 pctx = xmlCreateMemoryParserCtxt(ptr, len);
525 if (!pctx)
527 ERR("Failed to create parser context\n");
528 return NULL;
531 if (pctx->sax) xmlFree(pctx->sax);
532 pctx->sax = &sax_handler;
533 pctx->_private = This;
534 pctx->recovery = 0;
536 if (encoding != XML_CHAR_ENCODING_NONE)
537 xmlSwitchEncoding(pctx, encoding);
539 xmlParseDocument(pctx);
541 if (pctx->wellFormed)
543 doc = pctx->myDoc;
545 else
547 xmlFreeDoc(pctx->myDoc);
548 pctx->myDoc = NULL;
550 pctx->sax = NULL;
551 xmlFreeParserCtxt(pctx);
553 /* TODO: put this in one of the SAX callbacks */
554 /* create first child as a <?xml...?> */
555 if (doc && doc->standalone != -1)
557 xmlNodePtr node;
558 char buff[30];
559 xmlChar *xmlbuff = (xmlChar*)buff;
561 node = xmlNewDocPI( doc, (xmlChar*)"xml", NULL );
563 /* version attribute can't be omitted */
564 sprintf(buff, "version=\"%s\"", doc->version ? (char*)doc->version : "1.0");
565 xmlNodeAddContent( node, xmlbuff );
567 if (doc->encoding)
569 sprintf(buff, " encoding=\"%s\"", doc->encoding);
570 xmlNodeAddContent( node, xmlbuff );
573 if (doc->standalone != -2)
575 sprintf(buff, " standalone=\"%s\"", doc->standalone == 0 ? "no" : "yes");
576 xmlNodeAddContent( node, xmlbuff );
579 xmldoc_link_xmldecl( doc, node );
582 return doc;
585 void xmldoc_init(xmlDocPtr doc, MSXML_VERSION version)
587 doc->_private = create_priv();
588 priv_from_xmlDocPtr(doc)->properties = create_properties(version);
591 LONG xmldoc_add_refs(xmlDocPtr doc, LONG refs)
593 LONG ref = InterlockedExchangeAdd(&priv_from_xmlDocPtr(doc)->refs, refs) + refs;
594 TRACE("(%p)->(%d)\n", doc, ref);
595 return ref;
598 LONG xmldoc_add_ref(xmlDocPtr doc)
600 return xmldoc_add_refs(doc, 1);
603 LONG xmldoc_release_refs(xmlDocPtr doc, LONG refs)
605 xmldoc_priv *priv = priv_from_xmlDocPtr(doc);
606 LONG ref = InterlockedExchangeAdd(&priv->refs, -refs) - refs;
607 TRACE("(%p)->(%d)\n", doc, ref);
609 if (ref < 0)
610 WARN("negative refcount, expect troubles\n");
612 if (ref == 0)
614 orphan_entry *orphan, *orphan2;
615 TRACE("freeing docptr %p\n", doc);
617 LIST_FOR_EACH_ENTRY_SAFE( orphan, orphan2, &priv->orphans, orphan_entry, entry )
619 xmlFreeNode( orphan->node );
620 heap_free( orphan );
622 free_properties(priv->properties);
623 heap_free(doc->_private);
625 xmlFreeDoc(doc);
628 return ref;
631 LONG xmldoc_release(xmlDocPtr doc)
633 return xmldoc_release_refs(doc, 1);
636 HRESULT xmldoc_add_orphan(xmlDocPtr doc, xmlNodePtr node)
638 xmldoc_priv *priv = priv_from_xmlDocPtr(doc);
639 orphan_entry *entry;
641 entry = heap_alloc( sizeof (*entry) );
642 if(!entry)
643 return E_OUTOFMEMORY;
645 entry->node = node;
646 list_add_head( &priv->orphans, &entry->entry );
647 return S_OK;
650 HRESULT xmldoc_remove_orphan(xmlDocPtr doc, xmlNodePtr node)
652 xmldoc_priv *priv = priv_from_xmlDocPtr(doc);
653 orphan_entry *entry, *entry2;
655 LIST_FOR_EACH_ENTRY_SAFE( entry, entry2, &priv->orphans, orphan_entry, entry )
657 if( entry->node == node )
659 list_remove( &entry->entry );
660 heap_free( entry );
661 return S_OK;
665 return S_FALSE;
668 static inline xmlDocPtr get_doc( domdoc *This )
670 return This->node.node->doc;
673 static HRESULT attach_xmldoc(domdoc *This, xmlDocPtr xml )
675 release_namespaces(This);
677 if(This->node.node)
679 priv_from_xmlDocPtr(get_doc(This))->properties = NULL;
680 if (xmldoc_release(get_doc(This)) != 0)
681 priv_from_xmlDocPtr(get_doc(This))->properties =
682 copy_properties(This->properties);
685 This->node.node = (xmlNodePtr) xml;
687 if(This->node.node)
689 xmldoc_add_ref(get_doc(This));
690 priv_from_xmlDocPtr(get_doc(This))->properties = This->properties;
693 return S_OK;
696 static inline domdoc *impl_from_IXMLDOMDocument3( IXMLDOMDocument3 *iface )
698 return CONTAINING_RECORD(iface, domdoc, IXMLDOMDocument3_iface);
701 static inline domdoc *impl_from_IPersistStreamInit(IPersistStreamInit *iface)
703 return CONTAINING_RECORD(iface, domdoc, IPersistStreamInit_iface);
706 static inline domdoc *impl_from_IObjectWithSite(IObjectWithSite *iface)
708 return CONTAINING_RECORD(iface, domdoc, IObjectWithSite_iface);
711 static inline domdoc *impl_from_IObjectSafety(IObjectSafety *iface)
713 return CONTAINING_RECORD(iface, domdoc, IObjectSafety_iface);
716 static inline domdoc *impl_from_IConnectionPointContainer(IConnectionPointContainer *iface)
718 return CONTAINING_RECORD(iface, domdoc, IConnectionPointContainer_iface);
721 /************************************************************************
722 * domdoc implementation of IPersistStream.
724 static HRESULT WINAPI PersistStreamInit_QueryInterface(
725 IPersistStreamInit *iface, REFIID riid, void **ppvObj)
727 domdoc* This = impl_from_IPersistStreamInit(iface);
728 return IXMLDOMDocument3_QueryInterface(&This->IXMLDOMDocument3_iface, riid, ppvObj);
731 static ULONG WINAPI PersistStreamInit_AddRef(
732 IPersistStreamInit *iface)
734 domdoc* This = impl_from_IPersistStreamInit(iface);
735 return IXMLDOMDocument3_AddRef(&This->IXMLDOMDocument3_iface);
738 static ULONG WINAPI PersistStreamInit_Release(
739 IPersistStreamInit *iface)
741 domdoc* This = impl_from_IPersistStreamInit(iface);
742 return IXMLDOMDocument3_Release(&This->IXMLDOMDocument3_iface);
745 static HRESULT WINAPI PersistStreamInit_GetClassID(
746 IPersistStreamInit *iface, CLSID *classid)
748 domdoc* This = impl_from_IPersistStreamInit(iface);
749 TRACE("(%p)->(%p)\n", This, classid);
751 if(!classid)
752 return E_POINTER;
754 *classid = *DOMDocument_version(This->properties->version);
756 return S_OK;
759 static HRESULT WINAPI PersistStreamInit_IsDirty(
760 IPersistStreamInit *iface)
762 domdoc *This = impl_from_IPersistStreamInit(iface);
763 FIXME("(%p): stub!\n", This);
764 return S_FALSE;
767 static HRESULT domdoc_load_from_stream(domdoc *doc, ISequentialStream *stream)
769 DWORD read, written, len;
770 xmlDocPtr xmldoc = NULL;
771 IStream *hstream;
772 HGLOBAL hglobal;
773 BYTE buf[4096];
774 HRESULT hr;
775 char *ptr;
777 hstream = NULL;
778 hr = CreateStreamOnHGlobal(NULL, TRUE, &hstream);
779 if (FAILED(hr))
780 return hr;
784 ISequentialStream_Read(stream, buf, sizeof(buf), &read);
785 hr = IStream_Write(hstream, buf, read, &written);
786 } while(SUCCEEDED(hr) && written != 0 && read != 0);
788 if (FAILED(hr))
790 ERR("failed to copy stream 0x%08x\n", hr);
791 IStream_Release(hstream);
792 return hr;
795 hr = GetHGlobalFromStream(hstream, &hglobal);
796 if (FAILED(hr))
797 return hr;
799 len = GlobalSize(hglobal);
800 ptr = GlobalLock(hglobal);
801 if (len)
802 xmldoc = doparse(doc, ptr, len, XML_CHAR_ENCODING_NONE);
803 GlobalUnlock(hglobal);
805 if (!xmldoc)
807 ERR("Failed to parse xml\n");
808 return E_FAIL;
811 xmldoc->_private = create_priv();
813 return attach_xmldoc(doc, xmldoc);
816 static HRESULT WINAPI PersistStreamInit_Load(IPersistStreamInit *iface, IStream *stream)
818 domdoc *This = impl_from_IPersistStreamInit(iface);
820 TRACE("(%p)->(%p)\n", This, stream);
822 if (!stream)
823 return E_INVALIDARG;
825 return domdoc_load_from_stream(This, (ISequentialStream*)stream);
828 static HRESULT WINAPI PersistStreamInit_Save(
829 IPersistStreamInit *iface, IStream *stream, BOOL clr_dirty)
831 domdoc *This = impl_from_IPersistStreamInit(iface);
832 BSTR xmlString;
833 HRESULT hr;
835 TRACE("(%p)->(%p %d)\n", This, stream, clr_dirty);
837 hr = IXMLDOMDocument3_get_xml(&This->IXMLDOMDocument3_iface, &xmlString);
838 if(hr == S_OK)
840 DWORD len = SysStringLen(xmlString) * sizeof(WCHAR);
842 hr = IStream_Write( stream, xmlString, len, NULL );
843 SysFreeString(xmlString);
846 TRACE("ret 0x%08x\n", hr);
848 return hr;
851 static HRESULT WINAPI PersistStreamInit_GetSizeMax(
852 IPersistStreamInit *iface, ULARGE_INTEGER *pcbSize)
854 domdoc *This = impl_from_IPersistStreamInit(iface);
855 TRACE("(%p)->(%p)\n", This, pcbSize);
856 return E_NOTIMPL;
859 static HRESULT WINAPI PersistStreamInit_InitNew(
860 IPersistStreamInit *iface)
862 domdoc *This = impl_from_IPersistStreamInit(iface);
863 TRACE("(%p)\n", This);
864 return S_OK;
867 static const IPersistStreamInitVtbl xmldoc_IPersistStreamInit_VTable =
869 PersistStreamInit_QueryInterface,
870 PersistStreamInit_AddRef,
871 PersistStreamInit_Release,
872 PersistStreamInit_GetClassID,
873 PersistStreamInit_IsDirty,
874 PersistStreamInit_Load,
875 PersistStreamInit_Save,
876 PersistStreamInit_GetSizeMax,
877 PersistStreamInit_InitNew
880 /* IXMLDOMDocument3 interface */
882 static const tid_t domdoc_se_tids[] = {
883 IXMLDOMNode_tid,
884 IXMLDOMDocument_tid,
885 IXMLDOMDocument2_tid,
886 IXMLDOMDocument3_tid,
887 NULL_tid
890 static HRESULT WINAPI domdoc_QueryInterface( IXMLDOMDocument3 *iface, REFIID riid, void** ppvObject )
892 domdoc *This = impl_from_IXMLDOMDocument3( iface );
894 TRACE("(%p)->(%s %p)\n", This, debugstr_guid( riid ), ppvObject );
896 *ppvObject = NULL;
898 if ( IsEqualGUID( riid, &IID_IUnknown ) ||
899 IsEqualGUID( riid, &IID_IDispatch ) ||
900 IsEqualGUID( riid, &IID_IXMLDOMNode ) ||
901 IsEqualGUID( riid, &IID_IXMLDOMDocument ) ||
902 IsEqualGUID( riid, &IID_IXMLDOMDocument2 )||
903 IsEqualGUID( riid, &IID_IXMLDOMDocument3 ))
905 *ppvObject = iface;
907 else if (IsEqualGUID(&IID_IPersistStream, riid) ||
908 IsEqualGUID(&IID_IPersistStreamInit, riid))
910 *ppvObject = &This->IPersistStreamInit_iface;
912 else if (IsEqualGUID(&IID_IObjectWithSite, riid))
914 *ppvObject = &This->IObjectWithSite_iface;
916 else if (IsEqualGUID(&IID_IObjectSafety, riid))
918 *ppvObject = &This->IObjectSafety_iface;
920 else if( IsEqualGUID( riid, &IID_ISupportErrorInfo ))
922 return node_create_supporterrorinfo(domdoc_se_tids, ppvObject);
924 else if(node_query_interface(&This->node, riid, ppvObject))
926 return *ppvObject ? S_OK : E_NOINTERFACE;
928 else if (IsEqualGUID( riid, &IID_IConnectionPointContainer ))
930 *ppvObject = &This->IConnectionPointContainer_iface;
932 else
934 TRACE("interface %s not implemented\n", debugstr_guid(riid));
935 return E_NOINTERFACE;
938 IUnknown_AddRef((IUnknown*)*ppvObject);
940 return S_OK;
943 static ULONG WINAPI domdoc_AddRef( IXMLDOMDocument3 *iface )
945 domdoc *This = impl_from_IXMLDOMDocument3( iface );
946 ULONG ref = InterlockedIncrement( &This->ref );
947 TRACE("(%p)->(%d)\n", This, ref );
948 return ref;
951 static ULONG WINAPI domdoc_Release( IXMLDOMDocument3 *iface )
953 domdoc *This = impl_from_IXMLDOMDocument3( iface );
954 LONG ref = InterlockedDecrement( &This->ref );
956 TRACE("(%p)->(%d)\n", This, ref );
958 if ( ref == 0 )
960 int eid;
962 if (This->site)
963 IUnknown_Release( This->site );
964 destroy_xmlnode(&This->node);
966 for (eid = 0; eid < EVENTID_LAST; eid++)
967 if (This->events[eid]) IDispatch_Release(This->events[eid]);
969 release_namespaces(This);
970 heap_free(This);
973 return ref;
976 static HRESULT WINAPI domdoc_GetTypeInfoCount( IXMLDOMDocument3 *iface, UINT* pctinfo )
978 domdoc *This = impl_from_IXMLDOMDocument3( iface );
979 return IDispatchEx_GetTypeInfoCount(&This->node.dispex.IDispatchEx_iface, pctinfo);
982 static HRESULT WINAPI domdoc_GetTypeInfo(
983 IXMLDOMDocument3 *iface,
984 UINT iTInfo, LCID lcid, ITypeInfo** ppTInfo )
986 domdoc *This = impl_from_IXMLDOMDocument3( iface );
987 return IDispatchEx_GetTypeInfo(&This->node.dispex.IDispatchEx_iface, iTInfo, lcid, ppTInfo);
990 static HRESULT WINAPI domdoc_GetIDsOfNames(
991 IXMLDOMDocument3 *iface,
992 REFIID riid,
993 LPOLESTR* rgszNames,
994 UINT cNames,
995 LCID lcid,
996 DISPID* rgDispId)
998 domdoc *This = impl_from_IXMLDOMDocument3( iface );
999 return IDispatchEx_GetIDsOfNames(&This->node.dispex.IDispatchEx_iface,
1000 riid, rgszNames, cNames, lcid, rgDispId);
1003 static HRESULT WINAPI domdoc_Invoke(
1004 IXMLDOMDocument3 *iface,
1005 DISPID dispIdMember,
1006 REFIID riid,
1007 LCID lcid,
1008 WORD wFlags,
1009 DISPPARAMS* pDispParams,
1010 VARIANT* pVarResult,
1011 EXCEPINFO* pExcepInfo,
1012 UINT* puArgErr)
1014 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1015 return IDispatchEx_Invoke(&This->node.dispex.IDispatchEx_iface,
1016 dispIdMember, riid, lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
1019 static HRESULT WINAPI domdoc_get_nodeName(
1020 IXMLDOMDocument3 *iface,
1021 BSTR* name )
1023 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1025 static const WCHAR documentW[] = {'#','d','o','c','u','m','e','n','t',0};
1027 TRACE("(%p)->(%p)\n", This, name);
1029 return return_bstr(documentW, name);
1033 static HRESULT WINAPI domdoc_get_nodeValue(
1034 IXMLDOMDocument3 *iface,
1035 VARIANT* value )
1037 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1039 TRACE("(%p)->(%p)\n", This, value);
1041 if(!value)
1042 return E_INVALIDARG;
1044 V_VT(value) = VT_NULL;
1045 V_BSTR(value) = NULL; /* tests show that we should do this */
1046 return S_FALSE;
1050 static HRESULT WINAPI domdoc_put_nodeValue(
1051 IXMLDOMDocument3 *iface,
1052 VARIANT value)
1054 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1055 TRACE("(%p)->(%s)\n", This, debugstr_variant(&value));
1056 return E_FAIL;
1060 static HRESULT WINAPI domdoc_get_nodeType(
1061 IXMLDOMDocument3 *iface,
1062 DOMNodeType* type )
1064 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1066 TRACE("(%p)->(%p)\n", This, type);
1068 *type = NODE_DOCUMENT;
1069 return S_OK;
1073 static HRESULT WINAPI domdoc_get_parentNode(
1074 IXMLDOMDocument3 *iface,
1075 IXMLDOMNode** parent )
1077 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1079 TRACE("(%p)->(%p)\n", This, parent);
1081 return node_get_parent(&This->node, parent);
1085 static HRESULT WINAPI domdoc_get_childNodes(
1086 IXMLDOMDocument3 *iface,
1087 IXMLDOMNodeList** childList )
1089 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1091 TRACE("(%p)->(%p)\n", This, childList);
1093 return node_get_child_nodes(&This->node, childList);
1097 static HRESULT WINAPI domdoc_get_firstChild(
1098 IXMLDOMDocument3 *iface,
1099 IXMLDOMNode** firstChild )
1101 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1103 TRACE("(%p)->(%p)\n", This, firstChild);
1105 return node_get_first_child(&This->node, firstChild);
1109 static HRESULT WINAPI domdoc_get_lastChild(
1110 IXMLDOMDocument3 *iface,
1111 IXMLDOMNode** lastChild )
1113 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1115 TRACE("(%p)->(%p)\n", This, lastChild);
1117 return node_get_last_child(&This->node, lastChild);
1121 static HRESULT WINAPI domdoc_get_previousSibling(
1122 IXMLDOMDocument3 *iface,
1123 IXMLDOMNode** previousSibling )
1125 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1127 TRACE("(%p)->(%p)\n", This, previousSibling);
1129 return return_null_node(previousSibling);
1133 static HRESULT WINAPI domdoc_get_nextSibling(
1134 IXMLDOMDocument3 *iface,
1135 IXMLDOMNode** nextSibling )
1137 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1139 TRACE("(%p)->(%p)\n", This, nextSibling);
1141 return return_null_node(nextSibling);
1145 static HRESULT WINAPI domdoc_get_attributes(
1146 IXMLDOMDocument3 *iface,
1147 IXMLDOMNamedNodeMap** attributeMap )
1149 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1151 TRACE("(%p)->(%p)\n", This, attributeMap);
1153 return return_null_ptr((void**)attributeMap);
1157 static HRESULT WINAPI domdoc_insertBefore(
1158 IXMLDOMDocument3 *iface,
1159 IXMLDOMNode* newChild,
1160 VARIANT refChild,
1161 IXMLDOMNode** outNewChild )
1163 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1164 DOMNodeType type;
1165 HRESULT hr;
1167 TRACE("(%p)->(%p %s %p)\n", This, newChild, debugstr_variant(&refChild), outNewChild);
1169 hr = IXMLDOMNode_get_nodeType(newChild, &type);
1170 if (hr != S_OK) return hr;
1172 TRACE("new node type %d\n", type);
1173 switch (type)
1175 case NODE_ATTRIBUTE:
1176 case NODE_DOCUMENT:
1177 case NODE_CDATA_SECTION:
1178 if (outNewChild) *outNewChild = NULL;
1179 return E_FAIL;
1180 default:
1181 return node_insert_before(&This->node, newChild, &refChild, outNewChild);
1185 static HRESULT WINAPI domdoc_replaceChild(
1186 IXMLDOMDocument3 *iface,
1187 IXMLDOMNode* newChild,
1188 IXMLDOMNode* oldChild,
1189 IXMLDOMNode** outOldChild)
1191 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1193 TRACE("(%p)->(%p %p %p)\n", This, newChild, oldChild, outOldChild);
1195 return node_replace_child(&This->node, newChild, oldChild, outOldChild);
1199 static HRESULT WINAPI domdoc_removeChild(
1200 IXMLDOMDocument3 *iface,
1201 IXMLDOMNode *child,
1202 IXMLDOMNode **oldChild)
1204 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1205 TRACE("(%p)->(%p %p)\n", This, child, oldChild);
1206 return node_remove_child(&This->node, child, oldChild);
1210 static HRESULT WINAPI domdoc_appendChild(
1211 IXMLDOMDocument3 *iface,
1212 IXMLDOMNode *child,
1213 IXMLDOMNode **outChild)
1215 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1216 TRACE("(%p)->(%p %p)\n", This, child, outChild);
1217 return node_append_child(&This->node, child, outChild);
1221 static HRESULT WINAPI domdoc_hasChildNodes(
1222 IXMLDOMDocument3 *iface,
1223 VARIANT_BOOL *ret)
1225 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1226 TRACE("(%p)->(%p)\n", This, ret);
1227 return node_has_childnodes(&This->node, ret);
1231 static HRESULT WINAPI domdoc_get_ownerDocument(
1232 IXMLDOMDocument3 *iface,
1233 IXMLDOMDocument **doc)
1235 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1236 TRACE("(%p)->(%p)\n", This, doc);
1237 return node_get_owner_doc(&This->node, doc);
1241 static HRESULT WINAPI domdoc_cloneNode(
1242 IXMLDOMDocument3 *iface,
1243 VARIANT_BOOL deep,
1244 IXMLDOMNode** outNode)
1246 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1247 xmlNodePtr clone;
1249 TRACE("(%p)->(%d %p)\n", This, deep, outNode);
1251 if (!outNode)
1252 return E_INVALIDARG;
1254 *outNode = NULL;
1256 clone = xmlCopyNode((xmlNodePtr)get_doc(This), deep ? 1 : 2);
1257 if (!clone)
1258 return E_FAIL;
1260 clone->doc->_private = create_priv();
1261 xmldoc_add_orphan(clone->doc, clone);
1262 xmldoc_add_ref(clone->doc);
1264 priv_from_xmlDocPtr(clone->doc)->properties = copy_properties(This->properties);
1265 if (!(*outNode = (IXMLDOMNode*)create_domdoc(clone)))
1267 xmldoc_release(clone->doc);
1268 return E_FAIL;
1271 return S_OK;
1275 static HRESULT WINAPI domdoc_get_nodeTypeString(
1276 IXMLDOMDocument3 *iface,
1277 BSTR *p)
1279 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1280 static const WCHAR documentW[] = {'d','o','c','u','m','e','n','t',0};
1282 TRACE("(%p)->(%p)\n", This, p);
1284 return return_bstr(documentW, p);
1288 static HRESULT WINAPI domdoc_get_text(
1289 IXMLDOMDocument3 *iface,
1290 BSTR *p)
1292 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1293 TRACE("(%p)->(%p)\n", This, p);
1294 return node_get_text(&This->node, p);
1298 static HRESULT WINAPI domdoc_put_text(
1299 IXMLDOMDocument3 *iface,
1300 BSTR text )
1302 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1303 TRACE("(%p)->(%s)\n", This, debugstr_w(text));
1304 return E_FAIL;
1308 static HRESULT WINAPI domdoc_get_specified(
1309 IXMLDOMDocument3 *iface,
1310 VARIANT_BOOL* isSpecified )
1312 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1313 FIXME("(%p)->(%p) stub!\n", This, isSpecified);
1314 *isSpecified = VARIANT_TRUE;
1315 return S_OK;
1319 static HRESULT WINAPI domdoc_get_definition(
1320 IXMLDOMDocument3 *iface,
1321 IXMLDOMNode** definitionNode )
1323 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1324 FIXME("(%p)->(%p)\n", This, definitionNode);
1325 return E_NOTIMPL;
1329 static HRESULT WINAPI domdoc_get_nodeTypedValue(
1330 IXMLDOMDocument3 *iface,
1331 VARIANT* v )
1333 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1334 TRACE("(%p)->(%p)\n", This, v);
1335 return return_null_var(v);
1338 static HRESULT WINAPI domdoc_put_nodeTypedValue(
1339 IXMLDOMDocument3 *iface,
1340 VARIANT typedValue )
1342 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1343 FIXME("(%p)->(%s)\n", This, debugstr_variant(&typedValue));
1344 return E_NOTIMPL;
1348 static HRESULT WINAPI domdoc_get_dataType(
1349 IXMLDOMDocument3 *iface,
1350 VARIANT* typename )
1352 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1353 TRACE("(%p)->(%p)\n", This, typename);
1354 return return_null_var( typename );
1358 static HRESULT WINAPI domdoc_put_dataType(
1359 IXMLDOMDocument3 *iface,
1360 BSTR dataTypeName )
1362 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1364 FIXME("(%p)->(%s)\n", This, debugstr_w(dataTypeName));
1366 if(!dataTypeName)
1367 return E_INVALIDARG;
1369 return E_FAIL;
1372 static int XMLCALL domdoc_get_xml_writecallback(void *ctx, const char *data, int len)
1374 return xmlBufferAdd((xmlBufferPtr)ctx, (xmlChar*)data, len) == 0 ? len : 0;
1377 static HRESULT WINAPI domdoc_get_xml(
1378 IXMLDOMDocument3 *iface,
1379 BSTR* p)
1381 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1382 xmlSaveCtxtPtr ctxt;
1383 xmlBufferPtr buf;
1384 int options;
1385 long ret;
1387 TRACE("(%p)->(%p)\n", This, p);
1389 if(!p)
1390 return E_INVALIDARG;
1392 *p = NULL;
1394 buf = xmlBufferCreate();
1395 if(!buf)
1396 return E_OUTOFMEMORY;
1398 options = XML_SAVE_FORMAT | XML_SAVE_NO_DECL;
1399 ctxt = xmlSaveToIO(domdoc_get_xml_writecallback, NULL, buf, "UTF-8", options);
1401 if(!ctxt)
1403 xmlBufferFree(buf);
1404 return E_OUTOFMEMORY;
1407 ret = xmlSaveDoc(ctxt, get_doc(This));
1408 /* flushes on close */
1409 xmlSaveClose(ctxt);
1411 TRACE("%ld, len=%d\n", ret, xmlBufferLength(buf));
1412 if(ret != -1 && xmlBufferLength(buf) > 0)
1414 BSTR content;
1416 content = bstr_from_xmlChar(xmlBufferContent(buf));
1417 content = EnsureCorrectEOL(content);
1419 *p = content;
1421 else
1423 *p = SysAllocStringLen(NULL, 0);
1426 xmlBufferFree(buf);
1428 return *p ? S_OK : E_OUTOFMEMORY;
1432 static HRESULT WINAPI domdoc_transformNode(
1433 IXMLDOMDocument3 *iface,
1434 IXMLDOMNode *node,
1435 BSTR *p)
1437 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1438 TRACE("(%p)->(%p %p)\n", This, node, p);
1439 return node_transform_node(&This->node, node, p);
1443 static HRESULT WINAPI domdoc_selectNodes(
1444 IXMLDOMDocument3 *iface,
1445 BSTR p,
1446 IXMLDOMNodeList **outList)
1448 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1449 TRACE("(%p)->(%s %p)\n", This, debugstr_w(p), outList);
1450 return node_select_nodes(&This->node, p, outList);
1454 static HRESULT WINAPI domdoc_selectSingleNode(
1455 IXMLDOMDocument3 *iface,
1456 BSTR p,
1457 IXMLDOMNode **outNode)
1459 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1460 TRACE("(%p)->(%s %p)\n", This, debugstr_w(p), outNode);
1461 return node_select_singlenode(&This->node, p, outNode);
1465 static HRESULT WINAPI domdoc_get_parsed(
1466 IXMLDOMDocument3 *iface,
1467 VARIANT_BOOL* isParsed )
1469 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1470 FIXME("(%p)->(%p) stub!\n", This, isParsed);
1471 *isParsed = VARIANT_TRUE;
1472 return S_OK;
1475 static HRESULT WINAPI domdoc_get_namespaceURI(
1476 IXMLDOMDocument3 *iface,
1477 BSTR* namespaceURI )
1479 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1480 TRACE("(%p)->(%p)\n", This, namespaceURI);
1481 return return_null_bstr( namespaceURI );
1484 static HRESULT WINAPI domdoc_get_prefix(
1485 IXMLDOMDocument3 *iface,
1486 BSTR* prefix )
1488 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1489 TRACE("(%p)->(%p)\n", This, prefix);
1490 return return_null_bstr( prefix );
1494 static HRESULT WINAPI domdoc_get_baseName(
1495 IXMLDOMDocument3 *iface,
1496 BSTR* name )
1498 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1499 TRACE("(%p)->(%p)\n", This, name);
1500 return return_null_bstr( name );
1504 static HRESULT WINAPI domdoc_transformNodeToObject(
1505 IXMLDOMDocument3 *iface,
1506 IXMLDOMNode* stylesheet,
1507 VARIANT outputObject)
1509 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1510 FIXME("(%p)->(%p %s)\n", This, stylesheet, debugstr_variant(&outputObject));
1511 return E_NOTIMPL;
1515 static HRESULT WINAPI domdoc_get_doctype(
1516 IXMLDOMDocument3 *iface,
1517 IXMLDOMDocumentType** doctype )
1519 domdoc *This = impl_from_IXMLDOMDocument3(iface);
1520 IXMLDOMNode *node;
1521 xmlDtdPtr dtd;
1522 HRESULT hr;
1524 TRACE("(%p)->(%p)\n", This, doctype);
1526 if (!doctype) return E_INVALIDARG;
1528 *doctype = NULL;
1530 dtd = xmlGetIntSubset(get_doc(This));
1531 if (!dtd) return S_FALSE;
1533 node = create_node((xmlNodePtr)dtd);
1534 if (!node) return S_FALSE;
1536 hr = IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMDocumentType, (void**)doctype);
1537 IXMLDOMNode_Release(node);
1539 return hr;
1543 static HRESULT WINAPI domdoc_get_implementation(
1544 IXMLDOMDocument3 *iface,
1545 IXMLDOMImplementation** impl )
1547 domdoc *This = impl_from_IXMLDOMDocument3(iface);
1549 TRACE("(%p)->(%p)\n", This, impl);
1551 if(!impl)
1552 return E_INVALIDARG;
1554 *impl = (IXMLDOMImplementation*)create_doc_Implementation();
1556 return S_OK;
1559 static HRESULT WINAPI domdoc_get_documentElement(
1560 IXMLDOMDocument3 *iface,
1561 IXMLDOMElement** DOMElement )
1563 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1564 IXMLDOMNode *element_node;
1565 xmlNodePtr root;
1566 HRESULT hr;
1568 TRACE("(%p)->(%p)\n", This, DOMElement);
1570 if(!DOMElement)
1571 return E_INVALIDARG;
1573 *DOMElement = NULL;
1575 root = xmlDocGetRootElement( get_doc(This) );
1576 if ( !root )
1577 return S_FALSE;
1579 element_node = create_node( root );
1580 if(!element_node) return S_FALSE;
1582 hr = IXMLDOMNode_QueryInterface(element_node, &IID_IXMLDOMElement, (void**)DOMElement);
1583 IXMLDOMNode_Release(element_node);
1585 return hr;
1589 static HRESULT WINAPI domdoc_put_documentElement(
1590 IXMLDOMDocument3 *iface,
1591 IXMLDOMElement* DOMElement )
1593 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1594 IXMLDOMNode *elementNode;
1595 xmlNodePtr oldRoot;
1596 xmlDocPtr old_doc;
1597 xmlnode *xmlNode;
1598 int refcount = 0;
1599 HRESULT hr;
1601 TRACE("(%p)->(%p)\n", This, DOMElement);
1603 hr = IXMLDOMElement_QueryInterface( DOMElement, &IID_IXMLDOMNode, (void**)&elementNode );
1604 if(FAILED(hr))
1605 return hr;
1607 xmlNode = get_node_obj( elementNode );
1608 if(!xmlNode) return E_FAIL;
1610 if(!xmlNode->node->parent)
1611 if(xmldoc_remove_orphan(xmlNode->node->doc, xmlNode->node) != S_OK)
1612 WARN("%p is not an orphan of %p\n", xmlNode->node->doc, xmlNode->node);
1614 old_doc = xmlNode->node->doc;
1615 if (old_doc != get_doc(This))
1616 refcount = xmlnode_get_inst_cnt(xmlNode);
1618 /* old root is still orphaned by its document, update refcount from new root */
1619 if (refcount) xmldoc_add_refs(get_doc(This), refcount);
1620 oldRoot = xmlDocSetRootElement( get_doc(This), xmlNode->node);
1621 if (refcount) xmldoc_release_refs(old_doc, refcount);
1622 IXMLDOMNode_Release( elementNode );
1624 if(oldRoot)
1625 xmldoc_add_orphan(oldRoot->doc, oldRoot);
1627 return S_OK;
1631 static HRESULT WINAPI domdoc_createElement(
1632 IXMLDOMDocument3 *iface,
1633 BSTR tagname,
1634 IXMLDOMElement** element )
1636 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1637 IXMLDOMNode *node;
1638 VARIANT type;
1639 HRESULT hr;
1641 TRACE("(%p)->(%s %p)\n", This, debugstr_w(tagname), element);
1643 if (!element || !tagname) return E_INVALIDARG;
1645 V_VT(&type) = VT_I1;
1646 V_I1(&type) = NODE_ELEMENT;
1648 hr = IXMLDOMDocument3_createNode(iface, type, tagname, NULL, &node);
1649 if (hr == S_OK)
1651 IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMElement, (void**)element);
1652 IXMLDOMNode_Release(node);
1655 return hr;
1659 static HRESULT WINAPI domdoc_createDocumentFragment(
1660 IXMLDOMDocument3 *iface,
1661 IXMLDOMDocumentFragment** frag )
1663 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1664 IXMLDOMNode *node;
1665 VARIANT type;
1666 HRESULT hr;
1668 TRACE("(%p)->(%p)\n", This, frag);
1670 if (!frag) return E_INVALIDARG;
1672 *frag = NULL;
1674 V_VT(&type) = VT_I1;
1675 V_I1(&type) = NODE_DOCUMENT_FRAGMENT;
1677 hr = IXMLDOMDocument3_createNode(iface, type, NULL, NULL, &node);
1678 if (hr == S_OK)
1680 IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMDocumentFragment, (void**)frag);
1681 IXMLDOMNode_Release(node);
1684 return hr;
1688 static HRESULT WINAPI domdoc_createTextNode(
1689 IXMLDOMDocument3 *iface,
1690 BSTR data,
1691 IXMLDOMText** text )
1693 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1694 IXMLDOMNode *node;
1695 VARIANT type;
1696 HRESULT hr;
1698 TRACE("(%p)->(%s %p)\n", This, debugstr_w(data), text);
1700 if (!text) return E_INVALIDARG;
1702 *text = NULL;
1704 V_VT(&type) = VT_I1;
1705 V_I1(&type) = NODE_TEXT;
1707 hr = IXMLDOMDocument3_createNode(iface, type, NULL, NULL, &node);
1708 if (hr == S_OK)
1710 IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMText, (void**)text);
1711 IXMLDOMNode_Release(node);
1712 hr = IXMLDOMText_put_data(*text, data);
1715 return hr;
1719 static HRESULT WINAPI domdoc_createComment(
1720 IXMLDOMDocument3 *iface,
1721 BSTR data,
1722 IXMLDOMComment** comment )
1724 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1725 VARIANT type;
1726 HRESULT hr;
1727 IXMLDOMNode *node;
1729 TRACE("(%p)->(%s %p)\n", This, debugstr_w(data), comment);
1731 if (!comment) return E_INVALIDARG;
1733 *comment = NULL;
1735 V_VT(&type) = VT_I1;
1736 V_I1(&type) = NODE_COMMENT;
1738 hr = IXMLDOMDocument3_createNode(iface, type, NULL, NULL, &node);
1739 if (hr == S_OK)
1741 IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMComment, (void**)comment);
1742 IXMLDOMNode_Release(node);
1743 hr = IXMLDOMComment_put_data(*comment, data);
1746 return hr;
1750 static HRESULT WINAPI domdoc_createCDATASection(
1751 IXMLDOMDocument3 *iface,
1752 BSTR data,
1753 IXMLDOMCDATASection** cdata )
1755 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1756 IXMLDOMNode *node;
1757 VARIANT type;
1758 HRESULT hr;
1760 TRACE("(%p)->(%s %p)\n", This, debugstr_w(data), cdata);
1762 if (!cdata) return E_INVALIDARG;
1764 *cdata = NULL;
1766 V_VT(&type) = VT_I1;
1767 V_I1(&type) = NODE_CDATA_SECTION;
1769 hr = IXMLDOMDocument3_createNode(iface, type, NULL, NULL, &node);
1770 if (hr == S_OK)
1772 IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMCDATASection, (void**)cdata);
1773 IXMLDOMNode_Release(node);
1774 hr = IXMLDOMCDATASection_put_data(*cdata, data);
1777 return hr;
1781 static HRESULT WINAPI domdoc_createProcessingInstruction(
1782 IXMLDOMDocument3 *iface,
1783 BSTR target,
1784 BSTR data,
1785 IXMLDOMProcessingInstruction** pi )
1787 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1788 IXMLDOMNode *node;
1789 VARIANT type;
1790 HRESULT hr;
1792 TRACE("(%p)->(%s %s %p)\n", This, debugstr_w(target), debugstr_w(data), pi);
1794 if (!pi) return E_INVALIDARG;
1796 *pi = NULL;
1798 V_VT(&type) = VT_I1;
1799 V_I1(&type) = NODE_PROCESSING_INSTRUCTION;
1801 hr = IXMLDOMDocument3_createNode(iface, type, target, NULL, &node);
1802 if (hr == S_OK)
1804 xmlnode *node_obj;
1806 /* this is to bypass check in ::put_data() that blocks "<?xml" PIs */
1807 node_obj = get_node_obj(node);
1808 hr = node_set_content(node_obj, data);
1810 IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMProcessingInstruction, (void**)pi);
1811 IXMLDOMNode_Release(node);
1814 return hr;
1818 static HRESULT WINAPI domdoc_createAttribute(
1819 IXMLDOMDocument3 *iface,
1820 BSTR name,
1821 IXMLDOMAttribute** attribute )
1823 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1824 IXMLDOMNode *node;
1825 VARIANT type;
1826 HRESULT hr;
1828 TRACE("(%p)->(%s %p)\n", This, debugstr_w(name), attribute);
1830 if (!attribute || !name) return E_INVALIDARG;
1832 V_VT(&type) = VT_I1;
1833 V_I1(&type) = NODE_ATTRIBUTE;
1835 hr = IXMLDOMDocument3_createNode(iface, type, name, NULL, &node);
1836 if (hr == S_OK)
1838 IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMAttribute, (void**)attribute);
1839 IXMLDOMNode_Release(node);
1842 return hr;
1846 static HRESULT WINAPI domdoc_createEntityReference(
1847 IXMLDOMDocument3 *iface,
1848 BSTR name,
1849 IXMLDOMEntityReference** entityref )
1851 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1852 IXMLDOMNode *node;
1853 VARIANT type;
1854 HRESULT hr;
1856 TRACE("(%p)->(%s %p)\n", This, debugstr_w(name), entityref);
1858 if (!entityref) return E_INVALIDARG;
1860 *entityref = NULL;
1862 V_VT(&type) = VT_I1;
1863 V_I1(&type) = NODE_ENTITY_REFERENCE;
1865 hr = IXMLDOMDocument3_createNode(iface, type, name, NULL, &node);
1866 if (hr == S_OK)
1868 IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMEntityReference, (void**)entityref);
1869 IXMLDOMNode_Release(node);
1872 return hr;
1875 xmlChar* tagName_to_XPath(const BSTR tagName)
1877 xmlChar *query, *tmp;
1878 static const xmlChar everything[] = "/descendant::node()";
1879 static const xmlChar mod_pre[] = "*[local-name()='";
1880 static const xmlChar mod_post[] = "']";
1881 static const xmlChar prefix[] = "descendant::";
1882 const WCHAR *tokBegin, *tokEnd;
1883 int len;
1885 /* Special case - empty tagname - means select all nodes,
1886 except document itself. */
1887 if (!*tagName)
1888 return xmlStrdup(everything);
1890 query = xmlStrdup(prefix);
1892 tokBegin = tagName;
1893 while (tokBegin && *tokBegin)
1895 switch (*tokBegin)
1897 case '/':
1898 query = xmlStrcat(query, BAD_CAST "/");
1899 ++tokBegin;
1900 break;
1901 case '*':
1902 query = xmlStrcat(query, BAD_CAST "*");
1903 ++tokBegin;
1904 break;
1905 default:
1906 query = xmlStrcat(query, mod_pre);
1907 tokEnd = tokBegin;
1908 while (*tokEnd && *tokEnd != '/')
1909 ++tokEnd;
1910 len = WideCharToMultiByte(CP_UTF8, 0, tokBegin, tokEnd-tokBegin, NULL, 0, NULL, NULL);
1911 tmp = xmlMalloc(len);
1912 WideCharToMultiByte(CP_UTF8, 0, tokBegin, tokEnd-tokBegin, (char*)tmp, len, NULL, NULL);
1913 query = xmlStrncat(query, tmp, len);
1914 xmlFree(tmp);
1915 tokBegin = tokEnd;
1916 query = xmlStrcat(query, mod_post);
1920 return query;
1923 static HRESULT WINAPI domdoc_getElementsByTagName(
1924 IXMLDOMDocument3 *iface,
1925 BSTR tagName,
1926 IXMLDOMNodeList** resultList )
1928 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1929 xmlChar *query;
1930 HRESULT hr;
1931 BOOL XPath;
1933 TRACE("(%p)->(%s, %p)\n", This, debugstr_w(tagName), resultList);
1935 if (!tagName || !resultList) return E_INVALIDARG;
1937 XPath = This->properties->XPath;
1938 This->properties->XPath = TRUE;
1939 query = tagName_to_XPath(tagName);
1940 hr = create_selection((xmlNodePtr)get_doc(This), query, resultList);
1941 xmlFree(query);
1942 This->properties->XPath = XPath;
1944 return hr;
1947 static HRESULT get_node_type(VARIANT Type, DOMNodeType * type)
1949 VARIANT tmp;
1950 HRESULT hr;
1952 VariantInit(&tmp);
1953 hr = VariantChangeType(&tmp, &Type, 0, VT_I4);
1954 if(FAILED(hr))
1955 return E_INVALIDARG;
1957 *type = V_I4(&tmp);
1959 return S_OK;
1962 static HRESULT WINAPI domdoc_createNode(
1963 IXMLDOMDocument3 *iface,
1964 VARIANT Type,
1965 BSTR name,
1966 BSTR namespaceURI,
1967 IXMLDOMNode** node )
1969 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1970 DOMNodeType node_type;
1971 xmlNodePtr xmlnode;
1972 xmlChar *xml_name, *href;
1973 HRESULT hr;
1975 TRACE("(%p)->(%s %s %s %p)\n", This, debugstr_variant(&Type), debugstr_w(name), debugstr_w(namespaceURI), node);
1977 if(!node) return E_INVALIDARG;
1979 hr = get_node_type(Type, &node_type);
1980 if(FAILED(hr)) return hr;
1982 TRACE("node_type %d\n", node_type);
1984 /* exit earlier for types that need name */
1985 switch(node_type)
1987 case NODE_ELEMENT:
1988 case NODE_ATTRIBUTE:
1989 case NODE_ENTITY_REFERENCE:
1990 case NODE_PROCESSING_INSTRUCTION:
1991 if (!name || *name == 0) return E_FAIL;
1992 break;
1993 default:
1994 break;
1997 xml_name = xmlchar_from_wchar(name);
1998 /* prevent empty href from being allocated */
1999 href = namespaceURI ? xmlchar_from_wchar(namespaceURI) : NULL;
2001 switch(node_type)
2003 case NODE_ELEMENT:
2005 xmlChar *local, *prefix;
2007 local = xmlSplitQName2(xml_name, &prefix);
2009 xmlnode = xmlNewDocNode(get_doc(This), NULL, local ? local : xml_name, NULL);
2011 /* allow creating the default namespace xmlns= */
2012 if (local || (href && *href))
2014 xmlNsPtr ns = xmlNewNs(xmlnode, href, prefix);
2015 xmlSetNs(xmlnode, ns);
2018 xmlFree(local);
2019 xmlFree(prefix);
2021 break;
2023 case NODE_ATTRIBUTE:
2025 xmlChar *local, *prefix;
2027 local = xmlSplitQName2(xml_name, &prefix);
2029 xmlnode = (xmlNodePtr)xmlNewDocProp(get_doc(This), local ? local : xml_name, NULL);
2031 if (local || (href && *href))
2033 /* we need a floating namespace here, it can't be created linked to attribute from
2034 a start */
2035 xmlNsPtr ns = xmlNewNs(NULL, href, prefix);
2036 xmlSetNs(xmlnode, ns);
2039 xmlFree(local);
2040 xmlFree(prefix);
2042 break;
2044 case NODE_TEXT:
2045 xmlnode = (xmlNodePtr)xmlNewDocText(get_doc(This), NULL);
2046 break;
2047 case NODE_CDATA_SECTION:
2048 xmlnode = xmlNewCDataBlock(get_doc(This), NULL, 0);
2049 break;
2050 case NODE_ENTITY_REFERENCE:
2051 xmlnode = xmlNewReference(get_doc(This), xml_name);
2052 break;
2053 case NODE_PROCESSING_INSTRUCTION:
2054 #ifdef HAVE_XMLNEWDOCPI
2055 xmlnode = xmlNewDocPI(get_doc(This), xml_name, NULL);
2056 #else
2057 FIXME("xmlNewDocPI() not supported, use libxml2 2.6.15 or greater\n");
2058 xmlnode = NULL;
2059 #endif
2060 break;
2061 case NODE_COMMENT:
2062 xmlnode = xmlNewDocComment(get_doc(This), NULL);
2063 break;
2064 case NODE_DOCUMENT_FRAGMENT:
2065 xmlnode = xmlNewDocFragment(get_doc(This));
2066 break;
2067 /* unsupported types */
2068 case NODE_DOCUMENT:
2069 case NODE_DOCUMENT_TYPE:
2070 case NODE_ENTITY:
2071 case NODE_NOTATION:
2072 heap_free(xml_name);
2073 return E_INVALIDARG;
2074 default:
2075 FIXME("unhandled node type %d\n", node_type);
2076 xmlnode = NULL;
2077 break;
2080 *node = create_node(xmlnode);
2081 heap_free(xml_name);
2082 heap_free(href);
2084 if(*node)
2086 TRACE("created node (%d, %p, %p)\n", node_type, *node, xmlnode);
2087 xmldoc_add_orphan(xmlnode->doc, xmlnode);
2088 return S_OK;
2091 return E_FAIL;
2094 static HRESULT WINAPI domdoc_nodeFromID(
2095 IXMLDOMDocument3 *iface,
2096 BSTR idString,
2097 IXMLDOMNode** node )
2099 domdoc *This = impl_from_IXMLDOMDocument3(iface);
2100 FIXME("(%p)->(%s %p)\n", This, debugstr_w(idString), node);
2101 return E_NOTIMPL;
2104 static HRESULT domdoc_onDataAvailable(void *obj, char *ptr, DWORD len)
2106 domdoc *This = obj;
2107 xmlDocPtr xmldoc;
2109 xmldoc = doparse(This, ptr, len, XML_CHAR_ENCODING_NONE);
2110 if(xmldoc) {
2111 xmldoc->_private = create_priv();
2112 return attach_xmldoc(This, xmldoc);
2115 return E_FAIL;
2118 static HRESULT domdoc_load_moniker(domdoc *This, IMoniker *mon)
2120 bsc_t *bsc;
2121 HRESULT hr;
2123 hr = bind_url(mon, domdoc_onDataAvailable, This, &bsc);
2124 if(FAILED(hr))
2125 return hr;
2127 return detach_bsc(bsc);
2130 static HRESULT WINAPI domdoc_load(
2131 IXMLDOMDocument3 *iface,
2132 VARIANT source,
2133 VARIANT_BOOL* isSuccessful )
2135 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2136 LPWSTR filename = NULL;
2137 HRESULT hr = S_FALSE;
2138 xmlDocPtr xmldoc;
2140 TRACE("(%p)->(%s)\n", This, debugstr_variant(&source));
2142 if (!isSuccessful)
2143 return E_POINTER;
2144 *isSuccessful = VARIANT_FALSE;
2146 assert( &This->node );
2148 switch( V_VT(&source) )
2150 case VT_BSTR:
2151 filename = V_BSTR(&source);
2152 break;
2153 case VT_BSTR|VT_BYREF:
2154 if (!V_BSTRREF(&source)) return E_INVALIDARG;
2155 filename = *V_BSTRREF(&source);
2156 break;
2157 case VT_ARRAY|VT_UI1:
2159 SAFEARRAY *psa = V_ARRAY(&source);
2160 char *str;
2161 LONG len;
2162 UINT dim = SafeArrayGetDim(psa);
2164 switch (dim)
2166 case 0:
2167 ERR("SAFEARRAY == NULL\n");
2168 hr = This->error = E_INVALIDARG;
2169 break;
2170 case 1:
2171 /* Only takes UTF-8 strings.
2172 * NOT NULL-terminated. */
2173 hr = SafeArrayAccessData(psa, (void**)&str);
2174 if (FAILED(hr))
2176 This->error = hr;
2177 WARN("failed to access array data, 0x%08x\n", hr);
2178 break;
2180 SafeArrayGetUBound(psa, 1, &len);
2182 if ((xmldoc = doparse(This, str, ++len, XML_CHAR_ENCODING_UTF8)))
2184 hr = This->error = S_OK;
2185 *isSuccessful = VARIANT_TRUE;
2186 TRACE("parsed document %p\n", xmldoc);
2188 else
2190 This->error = E_FAIL;
2191 TRACE("failed to parse document\n");
2194 SafeArrayUnaccessData(psa);
2196 if(xmldoc)
2198 xmldoc->_private = create_priv();
2199 return attach_xmldoc(This, xmldoc);
2201 break;
2202 default:
2203 FIXME("unhandled SAFEARRAY dim: %d\n", dim);
2204 hr = This->error = E_NOTIMPL;
2207 break;
2208 case VT_UNKNOWN:
2210 ISequentialStream *stream = NULL;
2211 IXMLDOMDocument3 *newdoc = NULL;
2213 if (!V_UNKNOWN(&source)) return E_INVALIDARG;
2215 hr = IUnknown_QueryInterface(V_UNKNOWN(&source), &IID_IXMLDOMDocument3, (void**)&newdoc);
2216 if(hr == S_OK)
2218 if(newdoc)
2220 domdoc *newDoc = impl_from_IXMLDOMDocument3( newdoc );
2222 xmldoc = xmlCopyDoc(get_doc(newDoc), 1);
2223 xmldoc->_private = create_priv();
2224 hr = attach_xmldoc(This, xmldoc);
2226 if(SUCCEEDED(hr))
2227 *isSuccessful = VARIANT_TRUE;
2229 return hr;
2233 hr = IUnknown_QueryInterface(V_UNKNOWN(&source), &IID_IStream, (void**)&stream);
2234 if (FAILED(hr))
2235 hr = IUnknown_QueryInterface(V_UNKNOWN(&source), &IID_ISequentialStream, (void**)&stream);
2237 if (hr == S_OK)
2239 hr = domdoc_load_from_stream(This, stream);
2240 if (hr == S_OK)
2241 *isSuccessful = VARIANT_TRUE;
2242 ISequentialStream_Release(stream);
2243 return hr;
2246 FIXME("unsupported IUnknown type (0x%08x) (%p)\n", hr, V_UNKNOWN(&source)->lpVtbl);
2247 break;
2249 default:
2250 FIXME("VT type not supported (%d)\n", V_VT(&source));
2253 if ( filename )
2255 IMoniker *mon;
2257 CoTaskMemFree(This->properties->url);
2258 This->properties->url = NULL;
2260 hr = create_moniker_from_url( filename, &mon);
2261 if ( SUCCEEDED(hr) )
2263 hr = domdoc_load_moniker( This, mon );
2264 if (hr == S_OK)
2265 IMoniker_GetDisplayName(mon, NULL, NULL, &This->properties->url);
2266 IMoniker_Release(mon);
2269 if ( FAILED(hr) )
2270 This->error = E_FAIL;
2271 else
2273 hr = This->error = S_OK;
2274 *isSuccessful = VARIANT_TRUE;
2278 if(!filename || FAILED(hr)) {
2279 xmldoc = xmlNewDoc(NULL);
2280 xmldoc->_private = create_priv();
2281 hr = attach_xmldoc(This, xmldoc);
2282 if(SUCCEEDED(hr))
2283 hr = S_FALSE;
2286 TRACE("ret (%d)\n", hr);
2288 return hr;
2292 static HRESULT WINAPI domdoc_get_readyState(
2293 IXMLDOMDocument3 *iface,
2294 LONG *value )
2296 domdoc *This = impl_from_IXMLDOMDocument3(iface);
2297 FIXME("stub! (%p)->(%p)\n", This, value);
2299 if (!value)
2300 return E_INVALIDARG;
2302 *value = READYSTATE_COMPLETE;
2303 return S_OK;
2307 static HRESULT WINAPI domdoc_get_parseError(
2308 IXMLDOMDocument3 *iface,
2309 IXMLDOMParseError** errorObj )
2311 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2312 static const WCHAR err[] = {'e','r','r','o','r',0};
2313 BSTR error_string = NULL;
2315 FIXME("(%p)->(%p): creating a dummy parseError\n", iface, errorObj);
2317 if(This->error)
2318 error_string = SysAllocString(err);
2320 *errorObj = create_parseError(This->error, NULL, error_string, NULL, 0, 0, 0);
2321 if(!*errorObj) return E_OUTOFMEMORY;
2322 return S_OK;
2326 static HRESULT WINAPI domdoc_get_url(
2327 IXMLDOMDocument3 *iface,
2328 BSTR* url )
2330 domdoc *This = impl_from_IXMLDOMDocument3(iface);
2332 TRACE("(%p)->(%p)\n", This, url);
2334 if (!url)
2335 return E_INVALIDARG;
2337 if (This->properties->url)
2339 *url = SysAllocString(This->properties->url);
2340 if (!*url)
2341 return E_OUTOFMEMORY;
2343 return S_OK;
2345 else
2346 return return_null_bstr(url);
2350 static HRESULT WINAPI domdoc_get_async(
2351 IXMLDOMDocument3 *iface,
2352 VARIANT_BOOL* isAsync )
2354 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2356 TRACE("(%p)->(%p: %d)\n", This, isAsync, This->async);
2357 *isAsync = This->async;
2358 return S_OK;
2362 static HRESULT WINAPI domdoc_put_async(
2363 IXMLDOMDocument3 *iface,
2364 VARIANT_BOOL isAsync )
2366 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2368 TRACE("(%p)->(%d)\n", This, isAsync);
2369 This->async = isAsync;
2370 return S_OK;
2374 static HRESULT WINAPI domdoc_abort(
2375 IXMLDOMDocument3 *iface )
2377 domdoc *This = impl_from_IXMLDOMDocument3(iface);
2378 FIXME("%p\n", This);
2379 return E_NOTIMPL;
2382 /* don't rely on data to be in BSTR format, treat it as WCHAR string */
2383 static HRESULT WINAPI domdoc_loadXML(
2384 IXMLDOMDocument3 *iface,
2385 BSTR data,
2386 VARIANT_BOOL* isSuccessful )
2388 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2389 xmlDocPtr xmldoc = NULL;
2390 HRESULT hr = S_FALSE, hr2;
2392 TRACE("(%p)->(%s %p)\n", This, debugstr_w(data), isSuccessful );
2394 assert ( &This->node );
2396 if ( isSuccessful )
2398 *isSuccessful = VARIANT_FALSE;
2400 if (data)
2402 WCHAR *ptr = data;
2404 /* skip leading spaces if needed */
2405 if (This->properties->version == MSXML_DEFAULT || This->properties->version == MSXML26)
2406 while (*ptr && isspaceW(*ptr)) ptr++;
2408 xmldoc = doparse(This, (char*)ptr, strlenW(ptr)*sizeof(WCHAR), XML_CHAR_ENCODING_UTF16LE);
2409 if ( !xmldoc )
2411 This->error = E_FAIL;
2412 TRACE("failed to parse document\n");
2414 else
2416 hr = This->error = S_OK;
2417 *isSuccessful = VARIANT_TRUE;
2418 TRACE("parsed document %p\n", xmldoc);
2423 if(!xmldoc)
2424 xmldoc = xmlNewDoc(NULL);
2425 xmldoc->_private = create_priv();
2426 hr2 = attach_xmldoc(This, xmldoc);
2427 if( FAILED(hr2) )
2428 hr = hr2;
2430 return hr;
2433 static int XMLCALL domdoc_save_writecallback(void *ctx, const char *buffer, int len)
2435 DWORD written = -1;
2437 if(!WriteFile(ctx, buffer, len, &written, NULL))
2439 WARN("write error\n");
2440 return -1;
2442 else
2443 return written;
2446 static int XMLCALL domdoc_save_closecallback(void *ctx)
2448 return CloseHandle(ctx) ? 0 : -1;
2451 static int XMLCALL domdoc_stream_save_writecallback(void *ctx, const char *buffer, int len)
2453 ULONG written = 0;
2454 HRESULT hr;
2456 hr = IStream_Write((IStream*)ctx, buffer, len, &written);
2457 TRACE("0x%08x %p %d %u\n", hr, buffer, len, written);
2458 if (hr != S_OK)
2460 WARN("stream write error: 0x%08x\n", hr);
2461 return -1;
2463 else
2464 return len;
2467 static int XMLCALL domdoc_stream_save_closecallback(void *ctx)
2469 IStream_Release((IStream*)ctx);
2470 return 0;
2473 static HRESULT WINAPI domdoc_save(
2474 IXMLDOMDocument3 *iface,
2475 VARIANT destination )
2477 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2478 xmlSaveCtxtPtr ctx = NULL;
2479 xmlNodePtr xmldecl;
2480 HRESULT ret = S_OK;
2482 TRACE("(%p)->(%s)\n", This, debugstr_variant(&destination));
2484 switch (V_VT(&destination))
2486 case VT_UNKNOWN:
2488 IUnknown *pUnk = V_UNKNOWN(&destination);
2489 IXMLDOMDocument3 *document;
2490 IStream *stream;
2492 ret = IUnknown_QueryInterface(pUnk, &IID_IXMLDOMDocument3, (void**)&document);
2493 if(ret == S_OK)
2495 VARIANT_BOOL success;
2496 BSTR xml;
2498 ret = IXMLDOMDocument3_get_xml(iface, &xml);
2499 if(ret == S_OK)
2501 ret = IXMLDOMDocument3_loadXML(document, xml, &success);
2502 SysFreeString(xml);
2505 IXMLDOMDocument3_Release(document);
2506 return ret;
2509 ret = IUnknown_QueryInterface(pUnk, &IID_IStream, (void**)&stream);
2510 if(ret == S_OK)
2512 int options = get_doc(This)->standalone == -1 ? XML_SAVE_NO_DECL : 0;
2513 ctx = xmlSaveToIO(domdoc_stream_save_writecallback,
2514 domdoc_stream_save_closecallback, stream, NULL, options);
2516 if(!ctx)
2518 IStream_Release(stream);
2519 return E_FAIL;
2523 break;
2525 case VT_BSTR:
2526 case VT_BSTR | VT_BYREF:
2528 int options = get_doc(This)->standalone == -1 ? XML_SAVE_NO_DECL : 0;
2530 /* save with file path */
2531 HANDLE handle = CreateFileW( (V_VT(&destination) & VT_BYREF)? *V_BSTRREF(&destination) : V_BSTR(&destination),
2532 GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL );
2533 if( handle == INVALID_HANDLE_VALUE )
2535 WARN("failed to create file\n");
2536 return E_FAIL;
2539 /* disable top XML declaration */
2540 ctx = xmlSaveToIO(domdoc_save_writecallback, domdoc_save_closecallback,
2541 handle, NULL, options);
2542 if (!ctx)
2544 CloseHandle(handle);
2545 return E_FAIL;
2548 break;
2550 default:
2551 FIXME("Unhandled VARIANT: %s\n", debugstr_variant(&destination));
2552 return S_FALSE;
2555 xmldecl = xmldoc_unlink_xmldecl(get_doc(This));
2556 if (xmlSaveDoc(ctx, get_doc(This)) == -1) ret = S_FALSE;
2557 xmldoc_link_xmldecl(get_doc(This), xmldecl);
2559 /* will release resources through close callback */
2560 xmlSaveClose(ctx);
2562 return ret;
2565 static HRESULT WINAPI domdoc_get_validateOnParse(
2566 IXMLDOMDocument3 *iface,
2567 VARIANT_BOOL* isValidating )
2569 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2570 TRACE("(%p)->(%p: %d)\n", This, isValidating, This->validating);
2571 *isValidating = This->validating;
2572 return S_OK;
2576 static HRESULT WINAPI domdoc_put_validateOnParse(
2577 IXMLDOMDocument3 *iface,
2578 VARIANT_BOOL isValidating )
2580 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2581 TRACE("(%p)->(%d)\n", This, isValidating);
2582 This->validating = isValidating;
2583 return S_OK;
2587 static HRESULT WINAPI domdoc_get_resolveExternals(
2588 IXMLDOMDocument3 *iface,
2589 VARIANT_BOOL* isResolving )
2591 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2592 TRACE("(%p)->(%p: %d)\n", This, isResolving, This->resolving);
2593 *isResolving = This->resolving;
2594 return S_OK;
2598 static HRESULT WINAPI domdoc_put_resolveExternals(
2599 IXMLDOMDocument3 *iface,
2600 VARIANT_BOOL isResolving )
2602 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2603 TRACE("(%p)->(%d)\n", This, isResolving);
2604 This->resolving = isResolving;
2605 return S_OK;
2609 static HRESULT WINAPI domdoc_get_preserveWhiteSpace(
2610 IXMLDOMDocument3 *iface,
2611 VARIANT_BOOL* isPreserving )
2613 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2614 TRACE("(%p)->(%p: %d)\n", This, isPreserving, This->properties->preserving);
2615 *isPreserving = This->properties->preserving;
2616 return S_OK;
2620 static HRESULT WINAPI domdoc_put_preserveWhiteSpace(
2621 IXMLDOMDocument3 *iface,
2622 VARIANT_BOOL isPreserving )
2624 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2625 TRACE("(%p)->(%d)\n", This, isPreserving);
2626 This->properties->preserving = isPreserving;
2627 return S_OK;
2631 static HRESULT WINAPI domdoc_put_onreadystatechange(
2632 IXMLDOMDocument3 *iface,
2633 VARIANT event )
2635 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2637 TRACE("(%p)->(%s)\n", This, debugstr_variant(&event));
2638 return set_doc_event(This, EVENTID_READYSTATECHANGE, &event);
2642 static HRESULT WINAPI domdoc_put_onDataAvailable(IXMLDOMDocument3 *iface, VARIANT sink)
2644 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2645 FIXME("(%p)->(%s): stub\n", This, debugstr_variant(&sink));
2646 return E_NOTIMPL;
2649 static HRESULT WINAPI domdoc_put_onTransformNode(IXMLDOMDocument3 *iface, VARIANT sink )
2651 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2652 FIXME("(%p)->(%s): stub\n", This, debugstr_variant(&sink));
2653 return E_NOTIMPL;
2656 static HRESULT WINAPI domdoc_get_namespaces(
2657 IXMLDOMDocument3* iface,
2658 IXMLDOMSchemaCollection** collection )
2660 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2661 HRESULT hr;
2663 FIXME("(%p)->(%p): semi-stub\n", This, collection);
2665 if (!collection) return E_POINTER;
2667 if (!This->namespaces)
2669 hr = SchemaCache_create(This->properties->version, (void**)&This->namespaces);
2670 if (hr != S_OK) return hr;
2672 hr = cache_from_doc_ns(This->namespaces, &This->node);
2673 if (hr != S_OK)
2674 release_namespaces(This);
2677 if (This->namespaces)
2678 return IXMLDOMSchemaCollection2_QueryInterface(This->namespaces,
2679 &IID_IXMLDOMSchemaCollection, (void**)collection);
2681 return hr;
2684 static HRESULT WINAPI domdoc_get_schemas(
2685 IXMLDOMDocument3* iface,
2686 VARIANT* schema )
2688 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2689 IXMLDOMSchemaCollection2* cur_schema = This->properties->schemaCache;
2690 HRESULT hr = S_FALSE;
2692 TRACE("(%p)->(%p)\n", This, schema);
2694 V_VT(schema) = VT_NULL;
2695 /* just to reset pointer part, cause that's what application is expected to use */
2696 V_DISPATCH(schema) = NULL;
2698 if(cur_schema)
2700 hr = IXMLDOMSchemaCollection2_QueryInterface(cur_schema, &IID_IDispatch, (void**)&V_DISPATCH(schema));
2701 if(SUCCEEDED(hr))
2702 V_VT(schema) = VT_DISPATCH;
2704 return hr;
2707 static HRESULT WINAPI domdoc_putref_schemas(
2708 IXMLDOMDocument3* iface,
2709 VARIANT schema)
2711 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2712 HRESULT hr = E_FAIL;
2713 IXMLDOMSchemaCollection2* new_schema = NULL;
2715 FIXME("(%p)->(%s): semi-stub\n", This, debugstr_variant(&schema));
2716 switch(V_VT(&schema))
2718 case VT_UNKNOWN:
2719 if (V_UNKNOWN(&schema))
2721 hr = IUnknown_QueryInterface(V_UNKNOWN(&schema), &IID_IXMLDOMSchemaCollection, (void**)&new_schema);
2722 break;
2724 /* fallthrough */
2725 case VT_DISPATCH:
2726 if (V_DISPATCH(&schema))
2728 hr = IDispatch_QueryInterface(V_DISPATCH(&schema), &IID_IXMLDOMSchemaCollection, (void**)&new_schema);
2729 break;
2731 /* fallthrough */
2732 case VT_NULL:
2733 case VT_EMPTY:
2734 hr = S_OK;
2735 break;
2737 default:
2738 WARN("Can't get schema from vt %x\n", V_VT(&schema));
2741 if(SUCCEEDED(hr))
2743 IXMLDOMSchemaCollection2* old_schema = InterlockedExchangePointer((void**)&This->properties->schemaCache, new_schema);
2744 if(old_schema) IXMLDOMSchemaCollection2_Release(old_schema);
2747 return hr;
2750 static inline BOOL is_wellformed(xmlDocPtr doc)
2752 #ifdef HAVE_XMLDOC_PROPERTIES
2753 return doc->properties & XML_DOC_WELLFORMED;
2754 #else
2755 /* Not a full check, but catches the worst violations */
2756 xmlNodePtr child;
2757 int root = 0;
2759 for (child = doc->children; child != NULL; child = child->next)
2761 switch (child->type)
2763 case XML_ELEMENT_NODE:
2764 if (++root > 1)
2765 return FALSE;
2766 break;
2767 case XML_TEXT_NODE:
2768 case XML_CDATA_SECTION_NODE:
2769 return FALSE;
2770 break;
2771 default:
2772 break;
2776 return root == 1;
2777 #endif
2780 static void LIBXML2_LOG_CALLBACK validate_error(void* ctx, char const* msg, ...)
2782 va_list ap;
2783 va_start(ap, msg);
2784 LIBXML2_CALLBACK_ERR(domdoc_validateNode, msg, ap);
2785 va_end(ap);
2788 static void LIBXML2_LOG_CALLBACK validate_warning(void* ctx, char const* msg, ...)
2790 va_list ap;
2791 va_start(ap, msg);
2792 LIBXML2_CALLBACK_WARN(domdoc_validateNode, msg, ap);
2793 va_end(ap);
2796 static HRESULT WINAPI domdoc_validateNode(
2797 IXMLDOMDocument3* iface,
2798 IXMLDOMNode* node,
2799 IXMLDOMParseError** err)
2801 domdoc* This = impl_from_IXMLDOMDocument3(iface);
2802 LONG state, err_code = 0;
2803 HRESULT hr = S_OK;
2804 int validated = 0;
2806 TRACE("(%p)->(%p, %p)\n", This, node, err);
2807 IXMLDOMDocument3_get_readyState(iface, &state);
2808 if (state != READYSTATE_COMPLETE)
2810 if (err)
2811 *err = create_parseError(err_code, NULL, NULL, NULL, 0, 0, 0);
2812 return E_PENDING;
2815 if (!node)
2817 if (err)
2818 *err = create_parseError(err_code, NULL, NULL, NULL, 0, 0, 0);
2819 return E_POINTER;
2822 if (!get_node_obj(node)->node || get_node_obj(node)->node->doc != get_doc(This))
2824 if (err)
2825 *err = create_parseError(err_code, NULL, NULL, NULL, 0, 0, 0);
2826 return E_FAIL;
2829 if (!is_wellformed(get_doc(This)))
2831 ERR("doc not well-formed\n");
2832 if (err)
2833 *err = create_parseError(E_XML_NOTWF, NULL, NULL, NULL, 0, 0, 0);
2834 return S_FALSE;
2837 /* DTD validation */
2838 if (get_doc(This)->intSubset || get_doc(This)->extSubset)
2840 xmlValidCtxtPtr vctx = xmlNewValidCtxt();
2841 vctx->error = validate_error;
2842 vctx->warning = validate_warning;
2843 ++validated;
2845 if (!((node == (IXMLDOMNode*)iface)?
2846 xmlValidateDocument(vctx, get_doc(This)) :
2847 xmlValidateElement(vctx, get_doc(This), get_node_obj(node)->node)))
2849 /* TODO: get a real error code here */
2850 TRACE("DTD validation failed\n");
2851 err_code = E_XML_INVALID;
2852 hr = S_FALSE;
2854 xmlFreeValidCtxt(vctx);
2857 /* Schema validation */
2858 if (hr == S_OK && This->properties->schemaCache != NULL)
2861 hr = SchemaCache_validate_tree(This->properties->schemaCache, get_node_obj(node)->node);
2862 if (SUCCEEDED(hr))
2864 ++validated;
2865 /* TODO: get a real error code here */
2866 if (hr == S_OK)
2868 TRACE("schema validation succeeded\n");
2870 else
2872 ERR("schema validation failed\n");
2873 err_code = E_XML_INVALID;
2876 else
2878 /* not really OK, just didn't find a schema for the ns */
2879 hr = S_OK;
2883 if (!validated)
2885 ERR("no DTD or schema found\n");
2886 err_code = E_XML_NODTD;
2887 hr = S_FALSE;
2890 if (err)
2891 *err = create_parseError(err_code, NULL, NULL, NULL, 0, 0, 0);
2893 return hr;
2896 static HRESULT WINAPI domdoc_validate(
2897 IXMLDOMDocument3* iface,
2898 IXMLDOMParseError** err)
2900 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2901 TRACE("(%p)->(%p)\n", This, err);
2902 return IXMLDOMDocument3_validateNode(iface, (IXMLDOMNode*)iface, err);
2905 static HRESULT WINAPI domdoc_setProperty(
2906 IXMLDOMDocument3* iface,
2907 BSTR p,
2908 VARIANT value)
2910 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2912 TRACE("(%p)->(%s %s)\n", This, debugstr_w(p), debugstr_variant(&value));
2914 if (lstrcmpiW(p, PropertySelectionLanguageW) == 0)
2916 VARIANT varStr;
2917 HRESULT hr;
2918 BSTR bstr;
2920 V_VT(&varStr) = VT_EMPTY;
2921 if (V_VT(&value) != VT_BSTR)
2923 if (FAILED(hr = VariantChangeType(&varStr, &value, 0, VT_BSTR)))
2924 return hr;
2925 bstr = V_BSTR(&varStr);
2927 else
2928 bstr = V_BSTR(&value);
2930 hr = S_OK;
2931 if (lstrcmpiW(bstr, PropValueXPathW) == 0)
2932 This->properties->XPath = TRUE;
2933 else if (lstrcmpiW(bstr, PropValueXSLPatternW) == 0)
2934 This->properties->XPath = FALSE;
2935 else
2936 hr = E_FAIL;
2938 VariantClear(&varStr);
2939 return hr;
2941 else if (lstrcmpiW(p, PropertySelectionNamespacesW) == 0)
2943 xmlChar *nsStr = (xmlChar*)This->properties->selectNsStr;
2944 struct list *pNsList;
2945 VARIANT varStr;
2946 HRESULT hr;
2947 BSTR bstr;
2949 V_VT(&varStr) = VT_EMPTY;
2950 if (V_VT(&value) != VT_BSTR)
2952 if (FAILED(hr = VariantChangeType(&varStr, &value, 0, VT_BSTR)))
2953 return hr;
2954 bstr = V_BSTR(&varStr);
2956 else
2957 bstr = V_BSTR(&value);
2959 hr = S_OK;
2961 pNsList = &(This->properties->selectNsList);
2962 clear_selectNsList(pNsList);
2963 heap_free(nsStr);
2964 nsStr = xmlchar_from_wchar(bstr);
2966 TRACE("property value: \"%s\"\n", debugstr_w(bstr));
2968 This->properties->selectNsStr = nsStr;
2969 This->properties->selectNsStr_len = xmlStrlen(nsStr);
2970 if (bstr && *bstr)
2972 xmlChar *pTokBegin, *pTokEnd, *pTokInner;
2973 select_ns_entry* ns_entry = NULL;
2974 xmlXPathContextPtr ctx;
2976 ctx = xmlXPathNewContext(This->node.node->doc);
2977 pTokBegin = nsStr;
2979 /* skip leading spaces */
2980 while (*pTokBegin == ' ' || *pTokBegin == '\n' ||
2981 *pTokBegin == '\t' || *pTokBegin == '\r')
2982 ++pTokBegin;
2984 for (; *pTokBegin; pTokBegin = pTokEnd)
2986 if (ns_entry)
2987 memset(ns_entry, 0, sizeof(select_ns_entry));
2988 else
2989 ns_entry = heap_alloc_zero(sizeof(select_ns_entry));
2991 while (*pTokBegin == ' ')
2992 ++pTokBegin;
2993 pTokEnd = pTokBegin;
2994 while (*pTokEnd != ' ' && *pTokEnd != 0)
2995 ++pTokEnd;
2997 /* so it failed to advance which means we've got some trailing spaces */
2998 if (pTokEnd == pTokBegin) break;
3000 if (xmlStrncmp(pTokBegin, (xmlChar const*)"xmlns", 5) != 0)
3002 hr = E_FAIL;
3003 WARN("Syntax error in xmlns string: %s\n\tat token: %s\n",
3004 debugstr_w(bstr), debugstr_an((const char*)pTokBegin, pTokEnd-pTokBegin));
3005 continue;
3008 pTokBegin += 5;
3009 if (*pTokBegin == '=')
3011 /*valid for XSLPattern?*/
3012 FIXME("Setting default xmlns not supported - skipping.\n");
3013 continue;
3015 else if (*pTokBegin == ':')
3017 ns_entry->prefix = ++pTokBegin;
3018 for (pTokInner = pTokBegin; pTokInner != pTokEnd && *pTokInner != '='; ++pTokInner)
3021 if (pTokInner == pTokEnd)
3023 hr = E_FAIL;
3024 WARN("Syntax error in xmlns string: %s\n\tat token: %s\n",
3025 debugstr_w(bstr), debugstr_an((const char*)pTokBegin, pTokEnd-pTokBegin));
3026 continue;
3029 ns_entry->prefix_end = *pTokInner;
3030 *pTokInner = 0;
3031 ++pTokInner;
3033 if (pTokEnd-pTokInner > 1 &&
3034 ((*pTokInner == '\'' && *(pTokEnd-1) == '\'') ||
3035 (*pTokInner == '"' && *(pTokEnd-1) == '"')))
3037 ns_entry->href = ++pTokInner;
3038 ns_entry->href_end = *(pTokEnd-1);
3039 *(pTokEnd-1) = 0;
3040 list_add_tail(pNsList, &ns_entry->entry);
3041 /*let libxml figure out if they're valid from here ;)*/
3042 if (xmlXPathRegisterNs(ctx, ns_entry->prefix, ns_entry->href) != 0)
3044 hr = E_FAIL;
3046 ns_entry = NULL;
3047 continue;
3049 else
3051 WARN("Syntax error in xmlns string: %s\n\tat token: %s\n",
3052 debugstr_w(bstr), debugstr_an((const char*)pTokInner, pTokEnd-pTokInner));
3053 list_add_tail(pNsList, &ns_entry->entry);
3055 ns_entry = NULL;
3056 hr = E_FAIL;
3057 continue;
3060 else
3062 hr = E_FAIL;
3063 continue;
3066 heap_free(ns_entry);
3067 xmlXPathFreeContext(ctx);
3070 VariantClear(&varStr);
3071 return hr;
3073 else if (lstrcmpiW(p, PropertyProhibitDTDW) == 0 ||
3074 lstrcmpiW(p, PropertyNewParserW) == 0 ||
3075 lstrcmpiW(p, PropertyResolveExternalsW) == 0)
3077 /* Ignore */
3078 FIXME("Ignoring property %s, value %s\n", debugstr_w(p), debugstr_variant(&value));
3079 return S_OK;
3082 FIXME("Unknown property %s\n", debugstr_w(p));
3083 return E_FAIL;
3086 static HRESULT WINAPI domdoc_getProperty(
3087 IXMLDOMDocument3* iface,
3088 BSTR p,
3089 VARIANT* var)
3091 domdoc *This = impl_from_IXMLDOMDocument3( iface );
3093 TRACE("(%p)->(%s)\n", This, debugstr_w(p));
3095 if (!var)
3096 return E_INVALIDARG;
3098 if (lstrcmpiW(p, PropertySelectionLanguageW) == 0)
3100 V_VT(var) = VT_BSTR;
3101 V_BSTR(var) = This->properties->XPath ?
3102 SysAllocString(PropValueXPathW) :
3103 SysAllocString(PropValueXSLPatternW);
3104 return V_BSTR(var) ? S_OK : E_OUTOFMEMORY;
3106 else if (lstrcmpiW(p, PropertySelectionNamespacesW) == 0)
3108 int lenA, lenW;
3109 BSTR rebuiltStr, cur;
3110 const xmlChar *nsStr;
3111 struct list *pNsList;
3112 select_ns_entry* pNsEntry;
3114 V_VT(var) = VT_BSTR;
3115 nsStr = This->properties->selectNsStr;
3116 pNsList = &This->properties->selectNsList;
3117 lenA = This->properties->selectNsStr_len;
3118 lenW = MultiByteToWideChar(CP_UTF8, 0, (LPCSTR)nsStr, lenA+1, NULL, 0);
3119 rebuiltStr = heap_alloc(lenW*sizeof(WCHAR));
3120 MultiByteToWideChar(CP_UTF8, 0, (LPCSTR)nsStr, lenA+1, rebuiltStr, lenW);
3121 cur = rebuiltStr;
3122 /* this is fine because all of the chars that end tokens are ASCII*/
3123 LIST_FOR_EACH_ENTRY(pNsEntry, pNsList, select_ns_entry, entry)
3125 while (*cur != 0) ++cur;
3126 if (pNsEntry->prefix_end)
3128 *cur = pNsEntry->prefix_end;
3129 while (*cur != 0) ++cur;
3132 if (pNsEntry->href_end)
3134 *cur = pNsEntry->href_end;
3137 V_BSTR(var) = SysAllocString(rebuiltStr);
3138 heap_free(rebuiltStr);
3139 return S_OK;
3142 FIXME("Unknown property %s\n", debugstr_w(p));
3143 return E_FAIL;
3146 static HRESULT WINAPI domdoc_importNode(
3147 IXMLDOMDocument3* iface,
3148 IXMLDOMNode* node,
3149 VARIANT_BOOL deep,
3150 IXMLDOMNode** clone)
3152 domdoc *This = impl_from_IXMLDOMDocument3( iface );
3153 FIXME("(%p)->(%p %d %p): stub\n", This, node, deep, clone);
3154 return E_NOTIMPL;
3157 static const struct IXMLDOMDocument3Vtbl XMLDOMDocument3Vtbl =
3159 domdoc_QueryInterface,
3160 domdoc_AddRef,
3161 domdoc_Release,
3162 domdoc_GetTypeInfoCount,
3163 domdoc_GetTypeInfo,
3164 domdoc_GetIDsOfNames,
3165 domdoc_Invoke,
3166 domdoc_get_nodeName,
3167 domdoc_get_nodeValue,
3168 domdoc_put_nodeValue,
3169 domdoc_get_nodeType,
3170 domdoc_get_parentNode,
3171 domdoc_get_childNodes,
3172 domdoc_get_firstChild,
3173 domdoc_get_lastChild,
3174 domdoc_get_previousSibling,
3175 domdoc_get_nextSibling,
3176 domdoc_get_attributes,
3177 domdoc_insertBefore,
3178 domdoc_replaceChild,
3179 domdoc_removeChild,
3180 domdoc_appendChild,
3181 domdoc_hasChildNodes,
3182 domdoc_get_ownerDocument,
3183 domdoc_cloneNode,
3184 domdoc_get_nodeTypeString,
3185 domdoc_get_text,
3186 domdoc_put_text,
3187 domdoc_get_specified,
3188 domdoc_get_definition,
3189 domdoc_get_nodeTypedValue,
3190 domdoc_put_nodeTypedValue,
3191 domdoc_get_dataType,
3192 domdoc_put_dataType,
3193 domdoc_get_xml,
3194 domdoc_transformNode,
3195 domdoc_selectNodes,
3196 domdoc_selectSingleNode,
3197 domdoc_get_parsed,
3198 domdoc_get_namespaceURI,
3199 domdoc_get_prefix,
3200 domdoc_get_baseName,
3201 domdoc_transformNodeToObject,
3202 domdoc_get_doctype,
3203 domdoc_get_implementation,
3204 domdoc_get_documentElement,
3205 domdoc_put_documentElement,
3206 domdoc_createElement,
3207 domdoc_createDocumentFragment,
3208 domdoc_createTextNode,
3209 domdoc_createComment,
3210 domdoc_createCDATASection,
3211 domdoc_createProcessingInstruction,
3212 domdoc_createAttribute,
3213 domdoc_createEntityReference,
3214 domdoc_getElementsByTagName,
3215 domdoc_createNode,
3216 domdoc_nodeFromID,
3217 domdoc_load,
3218 domdoc_get_readyState,
3219 domdoc_get_parseError,
3220 domdoc_get_url,
3221 domdoc_get_async,
3222 domdoc_put_async,
3223 domdoc_abort,
3224 domdoc_loadXML,
3225 domdoc_save,
3226 domdoc_get_validateOnParse,
3227 domdoc_put_validateOnParse,
3228 domdoc_get_resolveExternals,
3229 domdoc_put_resolveExternals,
3230 domdoc_get_preserveWhiteSpace,
3231 domdoc_put_preserveWhiteSpace,
3232 domdoc_put_onreadystatechange,
3233 domdoc_put_onDataAvailable,
3234 domdoc_put_onTransformNode,
3235 domdoc_get_namespaces,
3236 domdoc_get_schemas,
3237 domdoc_putref_schemas,
3238 domdoc_validate,
3239 domdoc_setProperty,
3240 domdoc_getProperty,
3241 domdoc_validateNode,
3242 domdoc_importNode
3245 /* IConnectionPointContainer */
3246 static HRESULT WINAPI ConnectionPointContainer_QueryInterface(IConnectionPointContainer *iface,
3247 REFIID riid, void **ppv)
3249 domdoc *This = impl_from_IConnectionPointContainer(iface);
3250 return IXMLDOMDocument3_QueryInterface(&This->IXMLDOMDocument3_iface, riid, ppv);
3253 static ULONG WINAPI ConnectionPointContainer_AddRef(IConnectionPointContainer *iface)
3255 domdoc *This = impl_from_IConnectionPointContainer(iface);
3256 return IXMLDOMDocument3_AddRef(&This->IXMLDOMDocument3_iface);
3259 static ULONG WINAPI ConnectionPointContainer_Release(IConnectionPointContainer *iface)
3261 domdoc *This = impl_from_IConnectionPointContainer(iface);
3262 return IXMLDOMDocument3_Release(&This->IXMLDOMDocument3_iface);
3265 static HRESULT WINAPI ConnectionPointContainer_EnumConnectionPoints(IConnectionPointContainer *iface,
3266 IEnumConnectionPoints **ppEnum)
3268 domdoc *This = impl_from_IConnectionPointContainer(iface);
3269 FIXME("(%p)->(%p): stub\n", This, ppEnum);
3270 return E_NOTIMPL;
3273 static HRESULT WINAPI ConnectionPointContainer_FindConnectionPoint(IConnectionPointContainer *iface,
3274 REFIID riid, IConnectionPoint **cp)
3276 domdoc *This = impl_from_IConnectionPointContainer(iface);
3277 ConnectionPoint *iter;
3279 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), cp);
3281 *cp = NULL;
3283 for(iter = This->cp_list; iter; iter = iter->next)
3285 if (IsEqualGUID(iter->iid, riid))
3286 *cp = &iter->IConnectionPoint_iface;
3289 if (*cp)
3291 IConnectionPoint_AddRef(*cp);
3292 return S_OK;
3295 FIXME("unsupported riid %s\n", debugstr_guid(riid));
3296 return CONNECT_E_NOCONNECTION;
3300 static const struct IConnectionPointContainerVtbl ConnectionPointContainerVtbl =
3302 ConnectionPointContainer_QueryInterface,
3303 ConnectionPointContainer_AddRef,
3304 ConnectionPointContainer_Release,
3305 ConnectionPointContainer_EnumConnectionPoints,
3306 ConnectionPointContainer_FindConnectionPoint
3309 /* IConnectionPoint */
3310 static HRESULT WINAPI ConnectionPoint_QueryInterface(IConnectionPoint *iface,
3311 REFIID riid, void **ppv)
3313 ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3315 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv );
3317 *ppv = NULL;
3319 if (IsEqualGUID(&IID_IUnknown, riid) ||
3320 IsEqualGUID(&IID_IConnectionPoint, riid))
3322 *ppv = iface;
3325 if (*ppv)
3327 IConnectionPoint_AddRef(iface);
3328 return S_OK;
3331 WARN("Unsupported interface %s\n", debugstr_guid(riid));
3332 return E_NOINTERFACE;
3335 static ULONG WINAPI ConnectionPoint_AddRef(IConnectionPoint *iface)
3337 ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3338 return IConnectionPointContainer_AddRef(This->container);
3341 static ULONG WINAPI ConnectionPoint_Release(IConnectionPoint *iface)
3343 ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3344 return IConnectionPointContainer_Release(This->container);
3347 static HRESULT WINAPI ConnectionPoint_GetConnectionInterface(IConnectionPoint *iface, IID *iid)
3349 ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3351 TRACE("(%p)->(%p)\n", This, iid);
3353 if (!iid) return E_POINTER;
3355 *iid = *This->iid;
3356 return S_OK;
3359 static HRESULT WINAPI ConnectionPoint_GetConnectionPointContainer(IConnectionPoint *iface,
3360 IConnectionPointContainer **container)
3362 ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3364 TRACE("(%p)->(%p)\n", This, container);
3366 if (!container) return E_POINTER;
3368 *container = This->container;
3369 IConnectionPointContainer_AddRef(*container);
3370 return S_OK;
3373 static HRESULT WINAPI ConnectionPoint_Advise(IConnectionPoint *iface, IUnknown *unk_sink,
3374 DWORD *cookie)
3376 ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3377 IUnknown *sink;
3378 HRESULT hr;
3379 DWORD i;
3381 TRACE("(%p)->(%p %p)\n", This, unk_sink, cookie);
3383 hr = IUnknown_QueryInterface(unk_sink, This->iid, (void**)&sink);
3384 if(FAILED(hr) && !IsEqualGUID(&IID_IPropertyNotifySink, This->iid))
3385 hr = IUnknown_QueryInterface(unk_sink, &IID_IDispatch, (void**)&sink);
3386 if(FAILED(hr))
3387 return CONNECT_E_CANNOTCONNECT;
3389 if(This->sinks)
3391 for (i = 0; i < This->sinks_size; i++)
3392 if (!This->sinks[i].unk)
3393 break;
3395 if (i == This->sinks_size)
3396 This->sinks = heap_realloc(This->sinks,(++This->sinks_size)*sizeof(*This->sinks));
3398 else
3400 This->sinks = heap_alloc(sizeof(*This->sinks));
3401 This->sinks_size = 1;
3402 i = 0;
3405 This->sinks[i].unk = sink;
3406 if (cookie)
3407 *cookie = i+1;
3409 return S_OK;
3412 static HRESULT WINAPI ConnectionPoint_Unadvise(IConnectionPoint *iface, DWORD cookie)
3414 ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3416 TRACE("(%p)->(%d)\n", This, cookie);
3418 if (cookie == 0 || cookie > This->sinks_size || !This->sinks[cookie-1].unk)
3419 return CONNECT_E_NOCONNECTION;
3421 IUnknown_Release(This->sinks[cookie-1].unk);
3422 This->sinks[cookie-1].unk = NULL;
3424 return S_OK;
3427 static HRESULT WINAPI ConnectionPoint_EnumConnections(IConnectionPoint *iface,
3428 IEnumConnections **ppEnum)
3430 ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3431 FIXME("(%p)->(%p): stub\n", This, ppEnum);
3432 return E_NOTIMPL;
3435 static const IConnectionPointVtbl ConnectionPointVtbl =
3437 ConnectionPoint_QueryInterface,
3438 ConnectionPoint_AddRef,
3439 ConnectionPoint_Release,
3440 ConnectionPoint_GetConnectionInterface,
3441 ConnectionPoint_GetConnectionPointContainer,
3442 ConnectionPoint_Advise,
3443 ConnectionPoint_Unadvise,
3444 ConnectionPoint_EnumConnections
3447 static void ConnectionPoint_Init(ConnectionPoint *cp, struct domdoc *doc, REFIID riid)
3449 cp->IConnectionPoint_iface.lpVtbl = &ConnectionPointVtbl;
3450 cp->doc = doc;
3451 cp->iid = riid;
3452 cp->sinks = NULL;
3453 cp->sinks_size = 0;
3455 cp->next = doc->cp_list;
3456 doc->cp_list = cp;
3458 cp->container = &doc->IConnectionPointContainer_iface;
3461 /* domdoc implementation of IObjectWithSite */
3462 static HRESULT WINAPI
3463 domdoc_ObjectWithSite_QueryInterface( IObjectWithSite* iface, REFIID riid, void** ppvObject )
3465 domdoc *This = impl_from_IObjectWithSite(iface);
3466 return IXMLDOMDocument3_QueryInterface(&This->IXMLDOMDocument3_iface, riid, ppvObject);
3469 static ULONG WINAPI domdoc_ObjectWithSite_AddRef( IObjectWithSite* iface )
3471 domdoc *This = impl_from_IObjectWithSite(iface);
3472 return IXMLDOMDocument3_AddRef(&This->IXMLDOMDocument3_iface);
3475 static ULONG WINAPI domdoc_ObjectWithSite_Release( IObjectWithSite* iface )
3477 domdoc *This = impl_from_IObjectWithSite(iface);
3478 return IXMLDOMDocument3_Release(&This->IXMLDOMDocument3_iface);
3481 static HRESULT WINAPI domdoc_ObjectWithSite_GetSite( IObjectWithSite *iface, REFIID iid, void **ppvSite )
3483 domdoc *This = impl_from_IObjectWithSite(iface);
3485 TRACE("(%p)->(%s %p)\n", This, debugstr_guid( iid ), ppvSite );
3487 if ( !This->site )
3488 return E_FAIL;
3490 return IUnknown_QueryInterface( This->site, iid, ppvSite );
3493 static HRESULT WINAPI domdoc_ObjectWithSite_SetSite( IObjectWithSite *iface, IUnknown *punk )
3495 domdoc *This = impl_from_IObjectWithSite(iface);
3497 TRACE("(%p)->(%p)\n", iface, punk);
3499 if(!punk)
3501 if(This->site)
3503 IUnknown_Release( This->site );
3504 This->site = NULL;
3507 return S_OK;
3510 IUnknown_AddRef( punk );
3512 if(This->site)
3513 IUnknown_Release( This->site );
3515 This->site = punk;
3517 return S_OK;
3520 static const IObjectWithSiteVtbl domdocObjectSite =
3522 domdoc_ObjectWithSite_QueryInterface,
3523 domdoc_ObjectWithSite_AddRef,
3524 domdoc_ObjectWithSite_Release,
3525 domdoc_ObjectWithSite_SetSite,
3526 domdoc_ObjectWithSite_GetSite
3529 static HRESULT WINAPI domdoc_Safety_QueryInterface(IObjectSafety *iface, REFIID riid, void **ppv)
3531 domdoc *This = impl_from_IObjectSafety(iface);
3532 return IXMLDOMDocument3_QueryInterface(&This->IXMLDOMDocument3_iface, riid, ppv);
3535 static ULONG WINAPI domdoc_Safety_AddRef(IObjectSafety *iface)
3537 domdoc *This = impl_from_IObjectSafety(iface);
3538 return IXMLDOMDocument3_AddRef(&This->IXMLDOMDocument3_iface);
3541 static ULONG WINAPI domdoc_Safety_Release(IObjectSafety *iface)
3543 domdoc *This = impl_from_IObjectSafety(iface);
3544 return IXMLDOMDocument3_Release(&This->IXMLDOMDocument3_iface);
3547 #define SAFETY_SUPPORTED_OPTIONS (INTERFACESAFE_FOR_UNTRUSTED_CALLER|INTERFACESAFE_FOR_UNTRUSTED_DATA|INTERFACE_USES_SECURITY_MANAGER)
3549 static HRESULT WINAPI domdoc_Safety_GetInterfaceSafetyOptions(IObjectSafety *iface, REFIID riid,
3550 DWORD *supported, DWORD *enabled)
3552 domdoc *This = impl_from_IObjectSafety(iface);
3554 TRACE("(%p)->(%s %p %p)\n", This, debugstr_guid(riid), supported, enabled);
3556 if(!supported || !enabled) return E_POINTER;
3558 *supported = SAFETY_SUPPORTED_OPTIONS;
3559 *enabled = This->safeopt;
3561 return S_OK;
3564 static HRESULT WINAPI domdoc_Safety_SetInterfaceSafetyOptions(IObjectSafety *iface, REFIID riid,
3565 DWORD mask, DWORD enabled)
3567 domdoc *This = impl_from_IObjectSafety(iface);
3568 TRACE("(%p)->(%s %x %x)\n", This, debugstr_guid(riid), mask, enabled);
3570 if ((mask & ~SAFETY_SUPPORTED_OPTIONS) != 0)
3571 return E_FAIL;
3573 This->safeopt = (This->safeopt & ~mask) | (mask & enabled);
3575 return S_OK;
3578 #undef SAFETY_SUPPORTED_OPTIONS
3580 static const IObjectSafetyVtbl domdocObjectSafetyVtbl = {
3581 domdoc_Safety_QueryInterface,
3582 domdoc_Safety_AddRef,
3583 domdoc_Safety_Release,
3584 domdoc_Safety_GetInterfaceSafetyOptions,
3585 domdoc_Safety_SetInterfaceSafetyOptions
3588 static const tid_t domdoc_iface_tids[] = {
3589 IXMLDOMDocument3_tid,
3593 static dispex_static_data_t domdoc_dispex = {
3594 NULL,
3595 IXMLDOMDocument3_tid,
3596 NULL,
3597 domdoc_iface_tids
3600 HRESULT get_domdoc_from_xmldoc(xmlDocPtr xmldoc, IXMLDOMDocument3 **document)
3602 domdoc *doc;
3604 doc = heap_alloc( sizeof (*doc) );
3605 if( !doc )
3606 return E_OUTOFMEMORY;
3608 doc->IXMLDOMDocument3_iface.lpVtbl = &XMLDOMDocument3Vtbl;
3609 doc->IPersistStreamInit_iface.lpVtbl = &xmldoc_IPersistStreamInit_VTable;
3610 doc->IObjectWithSite_iface.lpVtbl = &domdocObjectSite;
3611 doc->IObjectSafety_iface.lpVtbl = &domdocObjectSafetyVtbl;
3612 doc->IConnectionPointContainer_iface.lpVtbl = &ConnectionPointContainerVtbl;
3613 doc->ref = 1;
3614 doc->async = VARIANT_TRUE;
3615 doc->validating = 0;
3616 doc->resolving = 0;
3617 doc->properties = properties_from_xmlDocPtr(xmldoc);
3618 doc->error = S_OK;
3619 doc->site = NULL;
3620 doc->safeopt = 0;
3621 doc->cp_list = NULL;
3622 doc->namespaces = NULL;
3623 memset(doc->events, 0, sizeof(doc->events));
3625 /* events connection points */
3626 ConnectionPoint_Init(&doc->cp_dispatch, doc, &IID_IDispatch);
3627 ConnectionPoint_Init(&doc->cp_propnotif, doc, &IID_IPropertyNotifySink);
3628 ConnectionPoint_Init(&doc->cp_domdocevents, doc, &DIID_XMLDOMDocumentEvents);
3630 init_xmlnode(&doc->node, (xmlNodePtr)xmldoc, (IXMLDOMNode*)&doc->IXMLDOMDocument3_iface,
3631 &domdoc_dispex);
3633 *document = &doc->IXMLDOMDocument3_iface;
3635 TRACE("returning iface %p\n", *document);
3636 return S_OK;
3639 HRESULT DOMDocument_create(MSXML_VERSION version, void **ppObj)
3641 xmlDocPtr xmldoc;
3642 HRESULT hr;
3644 TRACE("(%d, %p)\n", version, ppObj);
3646 xmldoc = xmlNewDoc(NULL);
3647 if(!xmldoc)
3648 return E_OUTOFMEMORY;
3650 xmldoc_init(xmldoc, version);
3652 hr = get_domdoc_from_xmldoc(xmldoc, (IXMLDOMDocument3**)ppObj);
3653 if(FAILED(hr))
3655 free_properties(properties_from_xmlDocPtr(xmldoc));
3656 heap_free(xmldoc->_private);
3657 xmlFreeDoc(xmldoc);
3658 return hr;
3661 return hr;
3664 IUnknown* create_domdoc( xmlNodePtr document )
3666 IUnknown *obj = NULL;
3667 HRESULT hr;
3669 TRACE("(%p)\n", document);
3671 hr = get_domdoc_from_xmldoc((xmlDocPtr)document, (IXMLDOMDocument3**)&obj);
3672 if (FAILED(hr))
3673 return NULL;
3675 return obj;
3678 #else
3680 HRESULT DOMDocument_create(MSXML_VERSION version, void **ppObj)
3682 MESSAGE("This program tried to use a DOMDocument object, but\n"
3683 "libxml2 support was not present at compile time.\n");
3684 return E_NOTIMPL;
3687 #endif