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
23 #define NONAMELESSUNION
30 # include <libxml/parser.h>
31 # include <libxml/xmlerror.h>
32 # include <libxml/xpathInternals.h>
33 # include <libxml/xmlsave.h>
34 # include <libxml/SAX2.h>
35 # include <libxml/parserInternals.h>
51 #include "wine/debug.h"
52 #include "wine/list.h"
54 #include "msxml_private.h"
56 WINE_DEFAULT_DEBUG_CHANNEL(msxml);
60 /* not defined in older versions */
61 #define XML_SAVE_FORMAT 1
62 #define XML_SAVE_NO_DECL 2
63 #define XML_SAVE_NO_EMPTY 4
64 #define XML_SAVE_NO_XHTML 8
65 #define XML_SAVE_XHTML 16
66 #define XML_SAVE_AS_XML 32
67 #define XML_SAVE_AS_HTML 64
69 static const WCHAR PropertySelectionLanguageW[] = {'S','e','l','e','c','t','i','o','n','L','a','n','g','u','a','g','e',0};
70 static const WCHAR PropertySelectionNamespacesW[] = {'S','e','l','e','c','t','i','o','n','N','a','m','e','s','p','a','c','e','s',0};
71 static const WCHAR PropertyProhibitDTDW[] = {'P','r','o','h','i','b','i','t','D','T','D',0};
72 static const WCHAR PropertyNewParserW[] = {'N','e','w','P','a','r','s','e','r',0};
73 static const WCHAR PropValueXPathW[] = {'X','P','a','t','h',0};
74 static const WCHAR PropValueXSLPatternW[] = {'X','S','L','P','a','t','t','e','r','n',0};
75 static const WCHAR PropertyResolveExternalsW[] = {'R','e','s','o','l','v','e','E','x','t','e','r','n','a','l','s',0};
77 /* Anything that passes the test_get_ownerDocument()
78 * tests can go here (data shared between all instances).
79 * We need to preserve this when reloading a document,
80 * and also need access to it from the libxml backend. */
82 MSXML_VERSION version;
83 VARIANT_BOOL preserving;
84 IXMLDOMSchemaCollection2* schemaCache;
85 struct list selectNsList;
86 xmlChar const* selectNsStr;
91 typedef struct ConnectionPoint ConnectionPoint;
92 typedef struct domdoc domdoc;
94 struct ConnectionPoint
96 IConnectionPoint IConnectionPoint_iface;
99 ConnectionPoint *next;
100 IConnectionPointContainer *container;
107 IPropertyNotifySink *propnotif;
113 EVENTID_READYSTATECHANGE = 0,
114 EVENTID_DATAAVAILABLE,
115 EVENTID_TRANSFORMNODE,
122 IXMLDOMDocument3 IXMLDOMDocument3_iface;
123 IPersistStreamInit IPersistStreamInit_iface;
124 IObjectWithSite IObjectWithSite_iface;
125 IObjectSafety IObjectSafety_iface;
126 IConnectionPointContainer IConnectionPointContainer_iface;
129 VARIANT_BOOL validating;
130 VARIANT_BOOL resolving;
131 domdoc_properties* properties;
144 /* connection list */
145 ConnectionPoint *cp_list;
146 ConnectionPoint cp_domdocevents;
147 ConnectionPoint cp_propnotif;
148 ConnectionPoint cp_dispatch;
151 IDispatch *events[EVENTID_LAST];
154 static HRESULT set_doc_event(domdoc *doc, eventid_t eid, const VARIANT *v)
162 IUnknown_QueryInterface(V_UNKNOWN(v), &IID_IDispatch, (void**)&disp);
167 disp = V_DISPATCH(v);
168 if (disp) IDispatch_AddRef(disp);
171 return DISP_E_TYPEMISMATCH;
174 if (doc->events[eid]) IDispatch_Release(doc->events[eid]);
175 doc->events[eid] = disp;
180 static inline ConnectionPoint *impl_from_IConnectionPoint(IConnectionPoint *iface)
182 return CONTAINING_RECORD(iface, ConnectionPoint, IConnectionPoint_iface);
186 In native windows, the whole lifetime management of XMLDOMNodes is
187 managed automatically using reference counts. Wine emulates that by
188 maintaining a reference count to the document that is increased for
189 each IXMLDOMNode pointer passed out for this document. If all these
190 pointers are gone, the document is unreachable and gets freed, that
191 is, all nodes in the tree of the document get freed.
193 You are able to create nodes that are associated to a document (in
194 fact, in msxml's XMLDOM model, all nodes are associated to a document),
195 but not in the tree of that document, for example using the createFoo
196 functions from IXMLDOMDocument. These nodes do not get cleaned up
197 by libxml, so we have to do it ourselves.
199 To catch these nodes, a list of "orphan nodes" is introduced.
200 It contains pointers to all roots of node trees that are
201 associated with the document without being part of the document
202 tree. All nodes with parent==NULL (except for the document root nodes)
203 should be in the orphan node list of their document. All orphan nodes
204 get freed together with the document itself.
207 typedef struct _xmldoc_priv {
210 domdoc_properties* properties;
213 typedef struct _orphan_entry {
218 typedef struct _select_ns_entry {
220 xmlChar const* prefix;
226 static inline xmldoc_priv * priv_from_xmlDocPtr(const xmlDocPtr doc)
228 return doc->_private;
231 static inline domdoc_properties * properties_from_xmlDocPtr(xmlDocPtr doc)
233 return priv_from_xmlDocPtr(doc)->properties;
236 BOOL is_xpathmode(const xmlDocPtr doc)
238 return properties_from_xmlDocPtr(doc)->XPath;
241 void set_xpathmode(xmlDocPtr doc, BOOL xpath)
243 properties_from_xmlDocPtr(doc)->XPath = xpath;
246 int registerNamespaces(xmlXPathContextPtr ctxt)
249 const select_ns_entry* ns = NULL;
250 const struct list* pNsList = &properties_from_xmlDocPtr(ctxt->doc)->selectNsList;
252 TRACE("(%p)\n", ctxt);
254 LIST_FOR_EACH_ENTRY( ns, pNsList, select_ns_entry, entry )
256 xmlXPathRegisterNs(ctxt, ns->prefix, ns->href);
263 static inline void clear_selectNsList(struct list* pNsList)
265 select_ns_entry *ns, *ns2;
266 LIST_FOR_EACH_ENTRY_SAFE( ns, ns2, pNsList, select_ns_entry, entry )
273 static xmldoc_priv * create_priv(void)
276 priv = heap_alloc( sizeof (*priv) );
281 list_init( &priv->orphans );
282 priv->properties = NULL;
288 static domdoc_properties *create_properties(MSXML_VERSION version)
290 domdoc_properties *properties = heap_alloc(sizeof(domdoc_properties));
292 list_init(&properties->selectNsList);
293 properties->preserving = VARIANT_FALSE;
294 properties->schemaCache = NULL;
295 properties->selectNsStr = heap_alloc_zero(sizeof(xmlChar));
296 properties->selectNsStr_len = 0;
298 /* properties that are dependent on object versions */
299 properties->version = version;
300 properties->XPath = (version == MSXML4 || version == MSXML6);
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);
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);
341 static void free_properties(domdoc_properties* properties)
345 if (properties->schemaCache)
346 IXMLDOMSchemaCollection2_Release(properties->schemaCache);
347 clear_selectNsList(&properties->selectNsList);
348 heap_free((xmlChar*)properties->selectNsStr);
349 heap_free(properties);
353 /* links a "<?xml" node as a first child */
354 void xmldoc_link_xmldecl(xmlDocPtr doc, xmlNodePtr node)
357 if (doc->standalone != -1) xmlAddPrevSibling( doc->children, node );
360 /* unlinks a first "<?xml" child if it was created */
361 xmlNodePtr xmldoc_unlink_xmldecl(xmlDocPtr doc)
367 if (doc->standalone != -1)
369 node = doc->children;
370 xmlUnlinkNode( node );
378 BOOL is_preserving_whitespace(xmlNodePtr node)
380 domdoc_properties* properties = NULL;
381 /* during parsing the xmlDoc._private stuff is not there */
382 if (priv_from_xmlDocPtr(node->doc))
383 properties = properties_from_xmlDocPtr(node->doc);
384 return ((properties && properties->preserving == VARIANT_TRUE) ||
385 xmlNodeGetSpacePreserve(node) == 1);
388 static inline BOOL strn_isspace(xmlChar const* str, int len)
390 for (; str && len > 0 && *str; ++str, --len)
397 static void sax_characters(void *ctx, const xmlChar *ch, int len)
399 xmlParserCtxtPtr ctxt;
402 ctxt = (xmlParserCtxtPtr) ctx;
403 This = (const domdoc*) ctxt->_private;
407 /* during domdoc_loadXML() the xmlDocPtr->_private data is not available */
408 if (!This->properties->preserving &&
409 !is_preserving_whitespace(ctxt->node) &&
410 strn_isspace(ch, len))
414 xmlSAX2Characters(ctxt, ch, len);
417 static void LIBXML2_LOG_CALLBACK sax_error(void* ctx, char const* msg, ...)
421 LIBXML2_CALLBACK_ERR(doparse, msg, ap);
425 static void LIBXML2_LOG_CALLBACK sax_warning(void* ctx, char const* msg, ...)
429 LIBXML2_CALLBACK_WARN(doparse, msg, ap);
433 static void sax_serror(void* ctx, xmlErrorPtr err)
435 LIBXML2_CALLBACK_SERROR(doparse, err);
438 static xmlDocPtr doparse(domdoc* This, char const* ptr, int len, xmlCharEncoding encoding)
440 xmlDocPtr doc = NULL;
441 xmlParserCtxtPtr pctx;
442 static xmlSAXHandler sax_handler = {
443 xmlSAX2InternalSubset, /* internalSubset */
444 xmlSAX2IsStandalone, /* isStandalone */
445 xmlSAX2HasInternalSubset, /* hasInternalSubset */
446 xmlSAX2HasExternalSubset, /* hasExternalSubset */
447 xmlSAX2ResolveEntity, /* resolveEntity */
448 xmlSAX2GetEntity, /* getEntity */
449 xmlSAX2EntityDecl, /* entityDecl */
450 xmlSAX2NotationDecl, /* notationDecl */
451 xmlSAX2AttributeDecl, /* attributeDecl */
452 xmlSAX2ElementDecl, /* elementDecl */
453 xmlSAX2UnparsedEntityDecl, /* unparsedEntityDecl */
454 xmlSAX2SetDocumentLocator, /* setDocumentLocator */
455 xmlSAX2StartDocument, /* startDocument */
456 xmlSAX2EndDocument, /* endDocument */
457 xmlSAX2StartElement, /* startElement */
458 xmlSAX2EndElement, /* endElement */
459 xmlSAX2Reference, /* reference */
460 sax_characters, /* characters */
461 sax_characters, /* ignorableWhitespace */
462 xmlSAX2ProcessingInstruction, /* processingInstruction */
463 xmlSAX2Comment, /* comment */
464 sax_warning, /* warning */
465 sax_error, /* error */
466 sax_error, /* fatalError */
467 xmlSAX2GetParameterEntity, /* getParameterEntity */
468 xmlSAX2CDataBlock, /* cdataBlock */
469 xmlSAX2ExternalSubset, /* externalSubset */
472 xmlSAX2StartElementNs, /* startElementNs */
473 xmlSAX2EndElementNs, /* endElementNs */
474 sax_serror /* serror */
478 pctx = xmlCreateMemoryParserCtxt(ptr, len);
481 ERR("Failed to create parser context\n");
485 if (pctx->sax) xmlFree(pctx->sax);
486 pctx->sax = &sax_handler;
487 pctx->_private = This;
490 if (encoding != XML_CHAR_ENCODING_NONE)
491 xmlSwitchEncoding(pctx, encoding);
493 xmlParseDocument(pctx);
495 if (pctx->wellFormed)
501 xmlFreeDoc(pctx->myDoc);
505 xmlFreeParserCtxt(pctx);
507 /* TODO: put this in one of the SAX callbacks */
508 /* create first child as a <?xml...?> */
509 if (doc && doc->standalone != -1)
513 xmlChar *xmlbuff = (xmlChar*)buff;
515 node = xmlNewDocPI( doc, (xmlChar*)"xml", NULL );
517 /* version attribute can't be omitted */
518 sprintf(buff, "version=\"%s\"", doc->version ? (char*)doc->version : "1.0");
519 xmlNodeAddContent( node, xmlbuff );
523 sprintf(buff, " encoding=\"%s\"", doc->encoding);
524 xmlNodeAddContent( node, xmlbuff );
527 if (doc->standalone != -2)
529 sprintf(buff, " standalone=\"%s\"", doc->standalone == 0 ? "no" : "yes");
530 xmlNodeAddContent( node, xmlbuff );
533 xmldoc_link_xmldecl( doc, node );
539 void xmldoc_init(xmlDocPtr doc, MSXML_VERSION version)
541 doc->_private = create_priv();
542 priv_from_xmlDocPtr(doc)->properties = create_properties(version);
545 LONG xmldoc_add_ref(xmlDocPtr doc)
547 LONG ref = InterlockedIncrement(&priv_from_xmlDocPtr(doc)->refs);
548 TRACE("(%p)->(%d)\n", doc, ref);
552 LONG xmldoc_release(xmlDocPtr doc)
554 xmldoc_priv *priv = priv_from_xmlDocPtr(doc);
555 LONG ref = InterlockedDecrement(&priv->refs);
556 TRACE("(%p)->(%d)\n", doc, ref);
559 orphan_entry *orphan, *orphan2;
560 TRACE("freeing docptr %p\n", doc);
562 LIST_FOR_EACH_ENTRY_SAFE( orphan, orphan2, &priv->orphans, orphan_entry, entry )
564 xmlFreeNode( orphan->node );
567 free_properties(priv->properties);
568 heap_free(doc->_private);
576 HRESULT xmldoc_add_orphan(xmlDocPtr doc, xmlNodePtr node)
578 xmldoc_priv *priv = priv_from_xmlDocPtr(doc);
581 entry = heap_alloc( sizeof (*entry) );
583 return E_OUTOFMEMORY;
586 list_add_head( &priv->orphans, &entry->entry );
590 HRESULT xmldoc_remove_orphan(xmlDocPtr doc, xmlNodePtr node)
592 xmldoc_priv *priv = priv_from_xmlDocPtr(doc);
593 orphan_entry *entry, *entry2;
595 LIST_FOR_EACH_ENTRY_SAFE( entry, entry2, &priv->orphans, orphan_entry, entry )
597 if( entry->node == node )
599 list_remove( &entry->entry );
608 static inline xmlDocPtr get_doc( domdoc *This )
610 return (xmlDocPtr)This->node.node;
613 static HRESULT attach_xmldoc(domdoc *This, xmlDocPtr xml )
617 priv_from_xmlDocPtr(get_doc(This))->properties = NULL;
618 if (xmldoc_release(get_doc(This)) != 0)
619 priv_from_xmlDocPtr(get_doc(This))->properties =
620 copy_properties(This->properties);
623 This->node.node = (xmlNodePtr) xml;
627 xmldoc_add_ref(get_doc(This));
628 priv_from_xmlDocPtr(get_doc(This))->properties = This->properties;
634 static inline domdoc *impl_from_IXMLDOMDocument3( IXMLDOMDocument3 *iface )
636 return CONTAINING_RECORD(iface, domdoc, IXMLDOMDocument3_iface);
639 static inline domdoc *impl_from_IPersistStreamInit(IPersistStreamInit *iface)
641 return CONTAINING_RECORD(iface, domdoc, IPersistStreamInit_iface);
644 static inline domdoc *impl_from_IObjectWithSite(IObjectWithSite *iface)
646 return CONTAINING_RECORD(iface, domdoc, IObjectWithSite_iface);
649 static inline domdoc *impl_from_IObjectSafety(IObjectSafety *iface)
651 return CONTAINING_RECORD(iface, domdoc, IObjectSafety_iface);
654 static inline domdoc *impl_from_IConnectionPointContainer(IConnectionPointContainer *iface)
656 return CONTAINING_RECORD(iface, domdoc, IConnectionPointContainer_iface);
659 /************************************************************************
660 * domdoc implementation of IPersistStream.
662 static HRESULT WINAPI domdoc_IPersistStreamInit_QueryInterface(
663 IPersistStreamInit *iface, REFIID riid, void **ppvObj)
665 domdoc* This = impl_from_IPersistStreamInit(iface);
666 return IXMLDOMDocument3_QueryInterface(&This->IXMLDOMDocument3_iface, riid, ppvObj);
669 static ULONG WINAPI domdoc_IPersistStreamInit_AddRef(
670 IPersistStreamInit *iface)
672 domdoc* This = impl_from_IPersistStreamInit(iface);
673 return IXMLDOMDocument3_AddRef(&This->IXMLDOMDocument3_iface);
676 static ULONG WINAPI domdoc_IPersistStreamInit_Release(
677 IPersistStreamInit *iface)
679 domdoc* This = impl_from_IPersistStreamInit(iface);
680 return IXMLDOMDocument3_Release(&This->IXMLDOMDocument3_iface);
683 static HRESULT WINAPI domdoc_IPersistStreamInit_GetClassID(
684 IPersistStreamInit *iface, CLSID *classid)
686 domdoc* This = impl_from_IPersistStreamInit(iface);
687 TRACE("(%p)->(%p)\n", This, classid);
692 *classid = *DOMDocument_version(This->properties->version);
697 static HRESULT WINAPI domdoc_IPersistStreamInit_IsDirty(
698 IPersistStreamInit *iface)
700 domdoc *This = impl_from_IPersistStreamInit(iface);
701 FIXME("(%p): stub!\n", This);
705 static HRESULT WINAPI domdoc_IPersistStreamInit_Load(
706 IPersistStreamInit *iface, LPSTREAM pStm)
708 domdoc *This = impl_from_IPersistStreamInit(iface);
711 DWORD read, written, len;
714 xmlDocPtr xmldoc = NULL;
716 TRACE("(%p)->(%p)\n", This, pStm);
721 hr = CreateStreamOnHGlobal(NULL, TRUE, &This->stream);
727 IStream_Read(pStm, buf, sizeof(buf), &read);
728 hr = IStream_Write(This->stream, buf, read, &written);
729 } while(SUCCEEDED(hr) && written != 0 && read != 0);
733 ERR("Failed to copy stream\n");
737 hr = GetHGlobalFromStream(This->stream, &hglobal);
741 len = GlobalSize(hglobal);
742 ptr = GlobalLock(hglobal);
744 xmldoc = doparse(This, ptr, len, XML_CHAR_ENCODING_NONE);
745 GlobalUnlock(hglobal);
749 ERR("Failed to parse xml\n");
753 xmldoc->_private = create_priv();
755 return attach_xmldoc(This, xmldoc);
758 static HRESULT WINAPI domdoc_IPersistStreamInit_Save(
759 IPersistStreamInit *iface, IStream *stream, BOOL clr_dirty)
761 domdoc *This = impl_from_IPersistStreamInit(iface);
765 TRACE("(%p)->(%p %d)\n", This, stream, clr_dirty);
767 hr = IXMLDOMDocument3_get_xml(&This->IXMLDOMDocument3_iface, &xmlString);
770 DWORD len = SysStringLen(xmlString) * sizeof(WCHAR);
772 hr = IStream_Write( stream, xmlString, len, NULL );
773 SysFreeString(xmlString);
776 TRACE("ret 0x%08x\n", hr);
781 static HRESULT WINAPI domdoc_IPersistStreamInit_GetSizeMax(
782 IPersistStreamInit *iface, ULARGE_INTEGER *pcbSize)
784 domdoc *This = impl_from_IPersistStreamInit(iface);
785 TRACE("(%p)->(%p): stub!\n", This, pcbSize);
789 static HRESULT WINAPI domdoc_IPersistStreamInit_InitNew(
790 IPersistStreamInit *iface)
792 domdoc *This = impl_from_IPersistStreamInit(iface);
793 TRACE("(%p)\n", This);
797 static const IPersistStreamInitVtbl xmldoc_IPersistStreamInit_VTable =
799 domdoc_IPersistStreamInit_QueryInterface,
800 domdoc_IPersistStreamInit_AddRef,
801 domdoc_IPersistStreamInit_Release,
802 domdoc_IPersistStreamInit_GetClassID,
803 domdoc_IPersistStreamInit_IsDirty,
804 domdoc_IPersistStreamInit_Load,
805 domdoc_IPersistStreamInit_Save,
806 domdoc_IPersistStreamInit_GetSizeMax,
807 domdoc_IPersistStreamInit_InitNew
810 /* IXMLDOMDocument3 interface */
812 static const tid_t domdoc_se_tids[] = {
815 IXMLDOMDocument2_tid,
816 IXMLDOMDocument3_tid,
820 static HRESULT WINAPI domdoc_QueryInterface( IXMLDOMDocument3 *iface, REFIID riid, void** ppvObject )
822 domdoc *This = impl_from_IXMLDOMDocument3( iface );
824 TRACE("(%p)->(%s %p)\n", This, debugstr_guid( riid ), ppvObject );
828 if ( IsEqualGUID( riid, &IID_IUnknown ) ||
829 IsEqualGUID( riid, &IID_IDispatch ) ||
830 IsEqualGUID( riid, &IID_IXMLDOMNode ) ||
831 IsEqualGUID( riid, &IID_IXMLDOMDocument ) ||
832 IsEqualGUID( riid, &IID_IXMLDOMDocument2 )||
833 IsEqualGUID( riid, &IID_IXMLDOMDocument3 ))
837 else if (IsEqualGUID(&IID_IPersistStream, riid) ||
838 IsEqualGUID(&IID_IPersistStreamInit, riid))
840 *ppvObject = &This->IPersistStreamInit_iface;
842 else if (IsEqualGUID(&IID_IObjectWithSite, riid))
844 *ppvObject = &This->IObjectWithSite_iface;
846 else if (IsEqualGUID(&IID_IObjectSafety, riid))
848 *ppvObject = &This->IObjectSafety_iface;
850 else if( IsEqualGUID( riid, &IID_ISupportErrorInfo ))
852 return node_create_supporterrorinfo(domdoc_se_tids, ppvObject);
854 else if(node_query_interface(&This->node, riid, ppvObject))
856 return *ppvObject ? S_OK : E_NOINTERFACE;
858 else if (IsEqualGUID( riid, &IID_IConnectionPointContainer ))
860 *ppvObject = &This->IConnectionPointContainer_iface;
864 TRACE("interface %s not implemented\n", debugstr_guid(riid));
865 return E_NOINTERFACE;
868 IUnknown_AddRef((IUnknown*)*ppvObject);
873 static ULONG WINAPI domdoc_AddRef( IXMLDOMDocument3 *iface )
875 domdoc *This = impl_from_IXMLDOMDocument3( iface );
876 ULONG ref = InterlockedIncrement( &This->ref );
877 TRACE("(%p)->(%d)\n", This, ref );
881 static ULONG WINAPI domdoc_Release( IXMLDOMDocument3 *iface )
883 domdoc *This = impl_from_IXMLDOMDocument3( iface );
884 LONG ref = InterlockedDecrement( &This->ref );
886 TRACE("(%p)->(%d)\n", This, ref );
893 detach_bsc(This->bsc);
896 IUnknown_Release( This->site );
897 destroy_xmlnode(&This->node);
899 IStream_Release(This->stream);
901 for (eid = 0; eid < EVENTID_LAST; eid++)
902 if (This->events[eid]) IDispatch_Release(This->events[eid]);
910 static HRESULT WINAPI domdoc_GetTypeInfoCount( IXMLDOMDocument3 *iface, UINT* pctinfo )
912 domdoc *This = impl_from_IXMLDOMDocument3( iface );
913 return IDispatchEx_GetTypeInfoCount(&This->node.dispex.IDispatchEx_iface, pctinfo);
916 static HRESULT WINAPI domdoc_GetTypeInfo(
917 IXMLDOMDocument3 *iface,
918 UINT iTInfo, LCID lcid, ITypeInfo** ppTInfo )
920 domdoc *This = impl_from_IXMLDOMDocument3( iface );
921 return IDispatchEx_GetTypeInfo(&This->node.dispex.IDispatchEx_iface, iTInfo, lcid, ppTInfo);
924 static HRESULT WINAPI domdoc_GetIDsOfNames(
925 IXMLDOMDocument3 *iface,
932 domdoc *This = impl_from_IXMLDOMDocument3( iface );
933 return IDispatchEx_GetIDsOfNames(&This->node.dispex.IDispatchEx_iface,
934 riid, rgszNames, cNames, lcid, rgDispId);
937 static HRESULT WINAPI domdoc_Invoke(
938 IXMLDOMDocument3 *iface,
943 DISPPARAMS* pDispParams,
945 EXCEPINFO* pExcepInfo,
948 domdoc *This = impl_from_IXMLDOMDocument3( iface );
949 return IDispatchEx_Invoke(&This->node.dispex.IDispatchEx_iface,
950 dispIdMember, riid, lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
953 static HRESULT WINAPI domdoc_get_nodeName(
954 IXMLDOMDocument3 *iface,
957 domdoc *This = impl_from_IXMLDOMDocument3( iface );
959 static const WCHAR documentW[] = {'#','d','o','c','u','m','e','n','t',0};
961 TRACE("(%p)->(%p)\n", This, name);
963 return return_bstr(documentW, name);
967 static HRESULT WINAPI domdoc_get_nodeValue(
968 IXMLDOMDocument3 *iface,
971 domdoc *This = impl_from_IXMLDOMDocument3( iface );
973 TRACE("(%p)->(%p)\n", This, value);
978 V_VT(value) = VT_NULL;
979 V_BSTR(value) = NULL; /* tests show that we should do this */
984 static HRESULT WINAPI domdoc_put_nodeValue(
985 IXMLDOMDocument3 *iface,
988 domdoc *This = impl_from_IXMLDOMDocument3( iface );
989 TRACE("(%p)->(v%d)\n", This, V_VT(&value));
994 static HRESULT WINAPI domdoc_get_nodeType(
995 IXMLDOMDocument3 *iface,
998 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1000 TRACE("(%p)->(%p)\n", This, type);
1002 *type = NODE_DOCUMENT;
1007 static HRESULT WINAPI domdoc_get_parentNode(
1008 IXMLDOMDocument3 *iface,
1009 IXMLDOMNode** parent )
1011 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1013 TRACE("(%p)->(%p)\n", This, parent);
1015 return node_get_parent(&This->node, parent);
1019 static HRESULT WINAPI domdoc_get_childNodes(
1020 IXMLDOMDocument3 *iface,
1021 IXMLDOMNodeList** childList )
1023 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1025 TRACE("(%p)->(%p)\n", This, childList);
1027 return node_get_child_nodes(&This->node, childList);
1031 static HRESULT WINAPI domdoc_get_firstChild(
1032 IXMLDOMDocument3 *iface,
1033 IXMLDOMNode** firstChild )
1035 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1037 TRACE("(%p)->(%p)\n", This, firstChild);
1039 return node_get_first_child(&This->node, firstChild);
1043 static HRESULT WINAPI domdoc_get_lastChild(
1044 IXMLDOMDocument3 *iface,
1045 IXMLDOMNode** lastChild )
1047 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1049 TRACE("(%p)->(%p)\n", This, lastChild);
1051 return node_get_last_child(&This->node, lastChild);
1055 static HRESULT WINAPI domdoc_get_previousSibling(
1056 IXMLDOMDocument3 *iface,
1057 IXMLDOMNode** previousSibling )
1059 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1061 TRACE("(%p)->(%p)\n", This, previousSibling);
1063 return return_null_node(previousSibling);
1067 static HRESULT WINAPI domdoc_get_nextSibling(
1068 IXMLDOMDocument3 *iface,
1069 IXMLDOMNode** nextSibling )
1071 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1073 TRACE("(%p)->(%p)\n", This, nextSibling);
1075 return return_null_node(nextSibling);
1079 static HRESULT WINAPI domdoc_get_attributes(
1080 IXMLDOMDocument3 *iface,
1081 IXMLDOMNamedNodeMap** attributeMap )
1083 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1085 TRACE("(%p)->(%p)\n", This, attributeMap);
1087 return return_null_ptr((void**)attributeMap);
1091 static HRESULT WINAPI domdoc_insertBefore(
1092 IXMLDOMDocument3 *iface,
1093 IXMLDOMNode* newChild,
1095 IXMLDOMNode** outNewChild )
1097 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1099 TRACE("(%p)->(%p x%d %p)\n", This, newChild, V_VT(&refChild), outNewChild);
1101 return node_insert_before(&This->node, newChild, &refChild, outNewChild);
1105 static HRESULT WINAPI domdoc_replaceChild(
1106 IXMLDOMDocument3 *iface,
1107 IXMLDOMNode* newChild,
1108 IXMLDOMNode* oldChild,
1109 IXMLDOMNode** outOldChild)
1111 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1113 TRACE("(%p)->(%p %p %p)\n", This, newChild, oldChild, outOldChild);
1115 return node_replace_child(&This->node, newChild, oldChild, outOldChild);
1119 static HRESULT WINAPI domdoc_removeChild(
1120 IXMLDOMDocument3 *iface,
1122 IXMLDOMNode **oldChild)
1124 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1125 TRACE("(%p)->(%p %p)\n", This, child, oldChild);
1126 return node_remove_child(&This->node, child, oldChild);
1130 static HRESULT WINAPI domdoc_appendChild(
1131 IXMLDOMDocument3 *iface,
1133 IXMLDOMNode **outChild)
1135 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1136 TRACE("(%p)->(%p %p)\n", This, child, outChild);
1137 return node_append_child(&This->node, child, outChild);
1141 static HRESULT WINAPI domdoc_hasChildNodes(
1142 IXMLDOMDocument3 *iface,
1145 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1146 TRACE("(%p)->(%p)\n", This, ret);
1147 return node_has_childnodes(&This->node, ret);
1151 static HRESULT WINAPI domdoc_get_ownerDocument(
1152 IXMLDOMDocument3 *iface,
1153 IXMLDOMDocument **doc)
1155 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1156 TRACE("(%p)->(%p)\n", This, doc);
1157 return node_get_owner_doc(&This->node, doc);
1161 static HRESULT WINAPI domdoc_cloneNode(
1162 IXMLDOMDocument3 *iface,
1164 IXMLDOMNode** outNode)
1166 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1167 TRACE("(%p)->(%d %p)\n", This, deep, outNode);
1168 return node_clone( &This->node, deep, outNode );
1172 static HRESULT WINAPI domdoc_get_nodeTypeString(
1173 IXMLDOMDocument3 *iface,
1176 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1177 static const WCHAR documentW[] = {'d','o','c','u','m','e','n','t',0};
1179 TRACE("(%p)->(%p)\n", This, p);
1181 return return_bstr(documentW, p);
1185 static HRESULT WINAPI domdoc_get_text(
1186 IXMLDOMDocument3 *iface,
1189 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1190 TRACE("(%p)->(%p)\n", This, p);
1191 return node_get_text(&This->node, p);
1195 static HRESULT WINAPI domdoc_put_text(
1196 IXMLDOMDocument3 *iface,
1199 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1200 TRACE("(%p)->(%s)\n", This, debugstr_w(text));
1205 static HRESULT WINAPI domdoc_get_specified(
1206 IXMLDOMDocument3 *iface,
1207 VARIANT_BOOL* isSpecified )
1209 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1210 FIXME("(%p)->(%p) stub!\n", This, isSpecified);
1211 *isSpecified = VARIANT_TRUE;
1216 static HRESULT WINAPI domdoc_get_definition(
1217 IXMLDOMDocument3 *iface,
1218 IXMLDOMNode** definitionNode )
1220 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1221 FIXME("(%p)->(%p)\n", This, definitionNode);
1226 static HRESULT WINAPI domdoc_get_nodeTypedValue(
1227 IXMLDOMDocument3 *iface,
1230 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1231 TRACE("(%p)->(%p)\n", This, v);
1232 return return_null_var(v);
1235 static HRESULT WINAPI domdoc_put_nodeTypedValue(
1236 IXMLDOMDocument3 *iface,
1237 VARIANT typedValue )
1239 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1240 FIXME("(%p)->(%s)\n", This, debugstr_variant(&typedValue));
1245 static HRESULT WINAPI domdoc_get_dataType(
1246 IXMLDOMDocument3 *iface,
1249 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1250 TRACE("(%p)->(%p)\n", This, typename);
1251 return return_null_var( typename );
1255 static HRESULT WINAPI domdoc_put_dataType(
1256 IXMLDOMDocument3 *iface,
1259 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1261 FIXME("(%p)->(%s)\n", This, debugstr_w(dataTypeName));
1264 return E_INVALIDARG;
1269 static int XMLCALL domdoc_get_xml_writecallback(void *ctx, const char *data, int len)
1271 return xmlBufferAdd((xmlBufferPtr)ctx, (xmlChar*)data, len) == 0 ? len : 0;
1274 static HRESULT WINAPI domdoc_get_xml(
1275 IXMLDOMDocument3 *iface,
1278 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1279 xmlSaveCtxtPtr ctxt;
1284 TRACE("(%p)->(%p)\n", This, p);
1287 return E_INVALIDARG;
1291 buf = xmlBufferCreate();
1293 return E_OUTOFMEMORY;
1295 options = XML_SAVE_FORMAT | XML_SAVE_NO_DECL;
1296 ctxt = xmlSaveToIO(domdoc_get_xml_writecallback, NULL, buf, "UTF-8", options);
1301 return E_OUTOFMEMORY;
1304 ret = xmlSaveDoc(ctxt, get_doc(This));
1305 /* flushes on close */
1308 TRACE("%ld, len=%d\n", ret, xmlBufferLength(buf));
1309 if(ret != -1 && xmlBufferLength(buf) > 0)
1313 content = bstr_from_xmlChar(xmlBufferContent(buf));
1314 content = EnsureCorrectEOL(content);
1320 *p = SysAllocStringLen(NULL, 0);
1325 return *p ? S_OK : E_OUTOFMEMORY;
1329 static HRESULT WINAPI domdoc_transformNode(
1330 IXMLDOMDocument3 *iface,
1334 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1335 TRACE("(%p)->(%p %p)\n", This, node, p);
1336 return node_transform_node(&This->node, node, p);
1340 static HRESULT WINAPI domdoc_selectNodes(
1341 IXMLDOMDocument3 *iface,
1343 IXMLDOMNodeList **outList)
1345 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1346 TRACE("(%p)->(%s %p)\n", This, debugstr_w(p), outList);
1347 return node_select_nodes(&This->node, p, outList);
1351 static HRESULT WINAPI domdoc_selectSingleNode(
1352 IXMLDOMDocument3 *iface,
1354 IXMLDOMNode **outNode)
1356 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1357 TRACE("(%p)->(%s %p)\n", This, debugstr_w(p), outNode);
1358 return node_select_singlenode(&This->node, p, outNode);
1362 static HRESULT WINAPI domdoc_get_parsed(
1363 IXMLDOMDocument3 *iface,
1364 VARIANT_BOOL* isParsed )
1366 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1367 FIXME("(%p)->(%p) stub!\n", This, isParsed);
1368 *isParsed = VARIANT_TRUE;
1372 static HRESULT WINAPI domdoc_get_namespaceURI(
1373 IXMLDOMDocument3 *iface,
1374 BSTR* namespaceURI )
1376 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1377 TRACE("(%p)->(%p)\n", This, namespaceURI);
1378 return return_null_bstr( namespaceURI );
1381 static HRESULT WINAPI domdoc_get_prefix(
1382 IXMLDOMDocument3 *iface,
1385 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1386 TRACE("(%p)->(%p)\n", This, prefix);
1387 return return_null_bstr( prefix );
1391 static HRESULT WINAPI domdoc_get_baseName(
1392 IXMLDOMDocument3 *iface,
1395 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1396 TRACE("(%p)->(%p)\n", This, name);
1397 return return_null_bstr( name );
1401 static HRESULT WINAPI domdoc_transformNodeToObject(
1402 IXMLDOMDocument3 *iface,
1403 IXMLDOMNode* stylesheet,
1404 VARIANT outputObject)
1406 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1407 FIXME("(%p)->(%p %s)\n", This, stylesheet, debugstr_variant(&outputObject));
1412 static HRESULT WINAPI domdoc_get_doctype(
1413 IXMLDOMDocument3 *iface,
1414 IXMLDOMDocumentType** doctype )
1416 domdoc *This = impl_from_IXMLDOMDocument3(iface);
1421 TRACE("(%p)->(%p)\n", This, doctype);
1423 if (!doctype) return E_INVALIDARG;
1427 dtd = xmlGetIntSubset(get_doc(This));
1428 if (!dtd) return S_FALSE;
1430 node = create_node((xmlNodePtr)dtd);
1431 if (!node) return S_FALSE;
1433 hr = IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMDocumentType, (void**)doctype);
1434 IXMLDOMNode_Release(node);
1440 static HRESULT WINAPI domdoc_get_implementation(
1441 IXMLDOMDocument3 *iface,
1442 IXMLDOMImplementation** impl )
1444 domdoc *This = impl_from_IXMLDOMDocument3(iface);
1446 TRACE("(%p)->(%p)\n", This, impl);
1449 return E_INVALIDARG;
1451 *impl = (IXMLDOMImplementation*)create_doc_Implementation();
1456 static HRESULT WINAPI domdoc_get_documentElement(
1457 IXMLDOMDocument3 *iface,
1458 IXMLDOMElement** DOMElement )
1460 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1461 IXMLDOMNode *element_node;
1465 TRACE("(%p)->(%p)\n", This, DOMElement);
1468 return E_INVALIDARG;
1472 root = xmlDocGetRootElement( get_doc(This) );
1476 element_node = create_node( root );
1477 if(!element_node) return S_FALSE;
1479 hr = IXMLDOMNode_QueryInterface(element_node, &IID_IXMLDOMElement, (void**)DOMElement);
1480 IXMLDOMNode_Release(element_node);
1486 static HRESULT WINAPI domdoc_put_documentElement(
1487 IXMLDOMDocument3 *iface,
1488 IXMLDOMElement* DOMElement )
1490 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1491 IXMLDOMNode *elementNode;
1496 TRACE("(%p)->(%p)\n", This, DOMElement);
1498 hr = IXMLDOMElement_QueryInterface( DOMElement, &IID_IXMLDOMNode, (void**)&elementNode );
1502 xmlNode = get_node_obj( elementNode );
1503 if(!xmlNode) return E_FAIL;
1505 if(!xmlNode->node->parent)
1506 if(xmldoc_remove_orphan(xmlNode->node->doc, xmlNode->node) != S_OK)
1507 WARN("%p is not an orphan of %p\n", xmlNode->node->doc, xmlNode->node);
1509 oldRoot = xmlDocSetRootElement( get_doc(This), xmlNode->node);
1510 IXMLDOMNode_Release( elementNode );
1513 xmldoc_add_orphan(oldRoot->doc, oldRoot);
1519 static HRESULT WINAPI domdoc_createElement(
1520 IXMLDOMDocument3 *iface,
1522 IXMLDOMElement** element )
1524 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1529 TRACE("(%p)->(%s %p)\n", This, debugstr_w(tagname), element);
1531 if (!element || !tagname) return E_INVALIDARG;
1533 V_VT(&type) = VT_I1;
1534 V_I1(&type) = NODE_ELEMENT;
1536 hr = IXMLDOMDocument3_createNode(iface, type, tagname, NULL, &node);
1539 IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMElement, (void**)element);
1540 IXMLDOMNode_Release(node);
1547 static HRESULT WINAPI domdoc_createDocumentFragment(
1548 IXMLDOMDocument3 *iface,
1549 IXMLDOMDocumentFragment** frag )
1551 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1556 TRACE("(%p)->(%p)\n", This, frag);
1558 if (!frag) return E_INVALIDARG;
1562 V_VT(&type) = VT_I1;
1563 V_I1(&type) = NODE_DOCUMENT_FRAGMENT;
1565 hr = IXMLDOMDocument3_createNode(iface, type, NULL, NULL, &node);
1568 IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMDocumentFragment, (void**)frag);
1569 IXMLDOMNode_Release(node);
1576 static HRESULT WINAPI domdoc_createTextNode(
1577 IXMLDOMDocument3 *iface,
1579 IXMLDOMText** text )
1581 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1586 TRACE("(%p)->(%s %p)\n", This, debugstr_w(data), text);
1588 if (!text) return E_INVALIDARG;
1592 V_VT(&type) = VT_I1;
1593 V_I1(&type) = NODE_TEXT;
1595 hr = IXMLDOMDocument3_createNode(iface, type, NULL, NULL, &node);
1598 IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMText, (void**)text);
1599 IXMLDOMNode_Release(node);
1600 hr = IXMLDOMText_put_data(*text, data);
1607 static HRESULT WINAPI domdoc_createComment(
1608 IXMLDOMDocument3 *iface,
1610 IXMLDOMComment** comment )
1612 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1617 TRACE("(%p)->(%s %p)\n", This, debugstr_w(data), comment);
1619 if (!comment) return E_INVALIDARG;
1623 V_VT(&type) = VT_I1;
1624 V_I1(&type) = NODE_COMMENT;
1626 hr = IXMLDOMDocument3_createNode(iface, type, NULL, NULL, &node);
1629 IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMComment, (void**)comment);
1630 IXMLDOMNode_Release(node);
1631 hr = IXMLDOMComment_put_data(*comment, data);
1638 static HRESULT WINAPI domdoc_createCDATASection(
1639 IXMLDOMDocument3 *iface,
1641 IXMLDOMCDATASection** cdata )
1643 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1648 TRACE("(%p)->(%s %p)\n", This, debugstr_w(data), cdata);
1650 if (!cdata) return E_INVALIDARG;
1654 V_VT(&type) = VT_I1;
1655 V_I1(&type) = NODE_CDATA_SECTION;
1657 hr = IXMLDOMDocument3_createNode(iface, type, NULL, NULL, &node);
1660 IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMCDATASection, (void**)cdata);
1661 IXMLDOMNode_Release(node);
1662 hr = IXMLDOMCDATASection_put_data(*cdata, data);
1669 static HRESULT WINAPI domdoc_createProcessingInstruction(
1670 IXMLDOMDocument3 *iface,
1673 IXMLDOMProcessingInstruction** pi )
1675 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1680 TRACE("(%p)->(%s %s %p)\n", This, debugstr_w(target), debugstr_w(data), pi);
1682 if (!pi) return E_INVALIDARG;
1686 V_VT(&type) = VT_I1;
1687 V_I1(&type) = NODE_PROCESSING_INSTRUCTION;
1689 hr = IXMLDOMDocument3_createNode(iface, type, target, NULL, &node);
1694 /* this is to bypass check in ::put_data() that blocks "<?xml" PIs */
1695 node_obj = get_node_obj(node);
1696 hr = node_set_content(node_obj, data);
1698 IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMProcessingInstruction, (void**)pi);
1699 IXMLDOMNode_Release(node);
1706 static HRESULT WINAPI domdoc_createAttribute(
1707 IXMLDOMDocument3 *iface,
1709 IXMLDOMAttribute** attribute )
1711 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1716 TRACE("(%p)->(%s %p)\n", This, debugstr_w(name), attribute);
1718 if (!attribute || !name) return E_INVALIDARG;
1720 V_VT(&type) = VT_I1;
1721 V_I1(&type) = NODE_ATTRIBUTE;
1723 hr = IXMLDOMDocument3_createNode(iface, type, name, NULL, &node);
1726 IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMAttribute, (void**)attribute);
1727 IXMLDOMNode_Release(node);
1734 static HRESULT WINAPI domdoc_createEntityReference(
1735 IXMLDOMDocument3 *iface,
1737 IXMLDOMEntityReference** entityref )
1739 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1744 TRACE("(%p)->(%s %p)\n", This, debugstr_w(name), entityref);
1746 if (!entityref) return E_INVALIDARG;
1750 V_VT(&type) = VT_I1;
1751 V_I1(&type) = NODE_ENTITY_REFERENCE;
1753 hr = IXMLDOMDocument3_createNode(iface, type, name, NULL, &node);
1756 IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMEntityReference, (void**)entityref);
1757 IXMLDOMNode_Release(node);
1763 xmlChar* tagName_to_XPath(const BSTR tagName)
1765 xmlChar *query, *tmp;
1766 static const xmlChar mod_pre[] = "*[local-name()='";
1767 static const xmlChar mod_post[] = "']";
1768 static const xmlChar prefix[] = "descendant::";
1769 const WCHAR *tokBegin, *tokEnd;
1772 query = xmlStrdup(prefix);
1775 while (tokBegin && *tokBegin)
1780 query = xmlStrcat(query, BAD_CAST "/");
1784 query = xmlStrcat(query, BAD_CAST "*");
1788 query = xmlStrcat(query, mod_pre);
1790 while (*tokEnd && *tokEnd != '/')
1792 len = WideCharToMultiByte(CP_UTF8, 0, tokBegin, tokEnd-tokBegin, NULL, 0, NULL, NULL);
1793 tmp = xmlMalloc(len);
1794 WideCharToMultiByte(CP_UTF8, 0, tokBegin, tokEnd-tokBegin, (char*)tmp, len, NULL, NULL);
1795 query = xmlStrncat(query, tmp, len);
1798 query = xmlStrcat(query, mod_post);
1805 static HRESULT WINAPI domdoc_getElementsByTagName(
1806 IXMLDOMDocument3 *iface,
1808 IXMLDOMNodeList** resultList )
1810 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1815 TRACE("(%p)->(%s, %p)\n", This, debugstr_w(tagName), resultList);
1817 if (!tagName || !resultList) return E_INVALIDARG;
1819 XPath = This->properties->XPath;
1820 This->properties->XPath = TRUE;
1821 query = tagName_to_XPath(tagName);
1822 hr = create_selection((xmlNodePtr)get_doc(This), query, resultList);
1824 This->properties->XPath = XPath;
1829 static HRESULT get_node_type(VARIANT Type, DOMNodeType * type)
1835 hr = VariantChangeType(&tmp, &Type, 0, VT_I4);
1837 return E_INVALIDARG;
1844 static HRESULT WINAPI domdoc_createNode(
1845 IXMLDOMDocument3 *iface,
1849 IXMLDOMNode** node )
1851 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1852 DOMNodeType node_type;
1854 xmlChar *xml_name, *href;
1857 TRACE("(%p)->(%s %s %p)\n", This, debugstr_w(name), debugstr_w(namespaceURI), node);
1859 if(!node) return E_INVALIDARG;
1861 hr = get_node_type(Type, &node_type);
1862 if(FAILED(hr)) return hr;
1864 if(namespaceURI && namespaceURI[0] && node_type != NODE_ELEMENT)
1865 FIXME("nodes with namespaces currently not supported.\n");
1867 TRACE("node_type %d\n", node_type);
1869 /* exit earlier for types that need name */
1873 case NODE_ATTRIBUTE:
1874 case NODE_ENTITY_REFERENCE:
1875 case NODE_PROCESSING_INSTRUCTION:
1876 if (!name || *name == 0) return E_FAIL;
1882 xml_name = xmlchar_from_wchar(name);
1883 /* prevent empty href to be allocated */
1884 href = namespaceURI ? xmlchar_from_wchar(namespaceURI) : NULL;
1890 xmlChar *local, *prefix;
1892 local = xmlSplitQName2(xml_name, &prefix);
1894 xmlnode = xmlNewDocNode(get_doc(This), NULL, local ? local : xml_name, NULL);
1896 /* allow to create default namespace xmlns= */
1897 if (local || (href && *href))
1899 xmlNsPtr ns = xmlNewNs(xmlnode, href, prefix);
1900 xmlSetNs(xmlnode, ns);
1908 case NODE_ATTRIBUTE:
1909 xmlnode = (xmlNodePtr)xmlNewDocProp(get_doc(This), xml_name, NULL);
1912 xmlnode = (xmlNodePtr)xmlNewDocText(get_doc(This), NULL);
1914 case NODE_CDATA_SECTION:
1915 xmlnode = xmlNewCDataBlock(get_doc(This), NULL, 0);
1917 case NODE_ENTITY_REFERENCE:
1918 xmlnode = xmlNewReference(get_doc(This), xml_name);
1920 case NODE_PROCESSING_INSTRUCTION:
1921 #ifdef HAVE_XMLNEWDOCPI
1922 xmlnode = xmlNewDocPI(get_doc(This), xml_name, NULL);
1924 FIXME("xmlNewDocPI() not supported, use libxml2 2.6.15 or greater\n");
1929 xmlnode = xmlNewDocComment(get_doc(This), NULL);
1931 case NODE_DOCUMENT_FRAGMENT:
1932 xmlnode = xmlNewDocFragment(get_doc(This));
1934 /* unsupported types */
1936 case NODE_DOCUMENT_TYPE:
1939 heap_free(xml_name);
1940 return E_INVALIDARG;
1942 FIXME("unhandled node type %d\n", node_type);
1947 *node = create_node(xmlnode);
1948 heap_free(xml_name);
1953 TRACE("created node (%d, %p, %p)\n", node_type, *node, xmlnode);
1954 xmldoc_add_orphan(xmlnode->doc, xmlnode);
1961 static HRESULT WINAPI domdoc_nodeFromID(
1962 IXMLDOMDocument3 *iface,
1964 IXMLDOMNode** node )
1966 domdoc *This = impl_from_IXMLDOMDocument3(iface);
1967 FIXME("(%p)->(%s %p)\n", This, debugstr_w(idString), node);
1971 static HRESULT domdoc_onDataAvailable(void *obj, char *ptr, DWORD len)
1976 xmldoc = doparse(This, ptr, len, XML_CHAR_ENCODING_NONE);
1978 xmldoc->_private = create_priv();
1979 return attach_xmldoc(This, xmldoc);
1985 static HRESULT doread( domdoc *This, LPWSTR filename )
1990 hr = bind_url(filename, domdoc_onDataAvailable, This, &bsc);
1995 hr = detach_bsc(This->bsc);
2004 static HRESULT WINAPI domdoc_load(
2005 IXMLDOMDocument3 *iface,
2007 VARIANT_BOOL* isSuccessful )
2009 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2010 LPWSTR filename = NULL;
2011 HRESULT hr = S_FALSE;
2012 IXMLDOMDocument3 *pNewDoc = NULL;
2013 IStream *pStream = NULL;
2016 TRACE("(%p)->(%s)\n", This, debugstr_variant(&source));
2020 *isSuccessful = VARIANT_FALSE;
2022 assert( &This->node );
2024 switch( V_VT(&source) )
2027 filename = V_BSTR(&source);
2029 case VT_BSTR|VT_BYREF:
2030 if (!V_BSTRREF(&source)) return E_INVALIDARG;
2031 filename = *V_BSTRREF(&source);
2033 case VT_ARRAY|VT_UI1:
2035 SAFEARRAY *psa = V_ARRAY(&source);
2038 UINT dim = SafeArrayGetDim(psa);
2043 ERR("SAFEARRAY == NULL\n");
2044 hr = This->error = E_INVALIDARG;
2047 /* Only takes UTF-8 strings.
2048 * NOT NULL-terminated. */
2049 SafeArrayAccessData(psa, (void**)&str);
2050 SafeArrayGetUBound(psa, 1, &len);
2052 if ((xmldoc = doparse(This, str, ++len, XML_CHAR_ENCODING_UTF8)))
2054 hr = This->error = S_OK;
2055 *isSuccessful = VARIANT_TRUE;
2056 TRACE("parsed document %p\n", xmldoc);
2060 This->error = E_FAIL;
2061 TRACE("failed to parse document\n");
2064 SafeArrayUnaccessData(psa);
2068 xmldoc->_private = create_priv();
2069 return attach_xmldoc(This, xmldoc);
2073 FIXME("unhandled SAFEARRAY dim: %d\n", dim);
2074 hr = This->error = E_NOTIMPL;
2079 hr = IUnknown_QueryInterface(V_UNKNOWN(&source), &IID_IXMLDOMDocument3, (void**)&pNewDoc);
2084 domdoc *newDoc = impl_from_IXMLDOMDocument3( pNewDoc );
2086 xmldoc = xmlCopyDoc(get_doc(newDoc), 1);
2087 xmldoc->_private = create_priv();
2088 hr = attach_xmldoc(This, xmldoc);
2091 *isSuccessful = VARIANT_TRUE;
2096 hr = IUnknown_QueryInterface(V_UNKNOWN(&source), &IID_IStream, (void**)&pStream);
2099 IPersistStream *pDocStream;
2100 hr = IUnknown_QueryInterface(iface, &IID_IPersistStream, (void**)&pDocStream);
2103 hr = IPersistStream_Load(pDocStream, pStream);
2104 IStream_Release(pStream);
2107 *isSuccessful = VARIANT_TRUE;
2109 TRACE("Using IStream to load Document\n");
2114 ERR("xmldoc_IPersistStream_Load failed (%d)\n", hr);
2119 ERR("QueryInterface IID_IPersistStream failed (%d)\n", hr);
2124 /* ISequentialStream */
2125 FIXME("Unknown type not supported (%d) (%p)(%p)\n", hr, pNewDoc, V_UNKNOWN(&source)->lpVtbl);
2129 FIXME("VT type not supported (%d)\n", V_VT(&source));
2134 hr = doread( This, filename );
2137 This->error = E_FAIL;
2140 hr = This->error = S_OK;
2141 *isSuccessful = VARIANT_TRUE;
2145 if(!filename || FAILED(hr)) {
2146 xmldoc = xmlNewDoc(NULL);
2147 xmldoc->_private = create_priv();
2148 hr = attach_xmldoc(This, xmldoc);
2153 TRACE("ret (%d)\n", hr);
2159 static HRESULT WINAPI domdoc_get_readyState(
2160 IXMLDOMDocument3 *iface,
2163 domdoc *This = impl_from_IXMLDOMDocument3(iface);
2164 FIXME("stub! (%p)->(%p)\n", This, value);
2167 return E_INVALIDARG;
2169 *value = READYSTATE_COMPLETE;
2174 static HRESULT WINAPI domdoc_get_parseError(
2175 IXMLDOMDocument3 *iface,
2176 IXMLDOMParseError** errorObj )
2178 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2179 static const WCHAR err[] = {'e','r','r','o','r',0};
2180 BSTR error_string = NULL;
2182 FIXME("(%p)->(%p): creating a dummy parseError\n", iface, errorObj);
2185 error_string = SysAllocString(err);
2187 *errorObj = create_parseError(This->error, NULL, error_string, NULL, 0, 0, 0);
2188 if(!*errorObj) return E_OUTOFMEMORY;
2193 static HRESULT WINAPI domdoc_get_url(
2194 IXMLDOMDocument3 *iface,
2197 domdoc *This = impl_from_IXMLDOMDocument3(iface);
2198 FIXME("(%p)->(%p)\n", This, urlString);
2203 static HRESULT WINAPI domdoc_get_async(
2204 IXMLDOMDocument3 *iface,
2205 VARIANT_BOOL* isAsync )
2207 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2209 TRACE("(%p)->(%p: %d)\n", This, isAsync, This->async);
2210 *isAsync = This->async;
2215 static HRESULT WINAPI domdoc_put_async(
2216 IXMLDOMDocument3 *iface,
2217 VARIANT_BOOL isAsync )
2219 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2221 TRACE("(%p)->(%d)\n", This, isAsync);
2222 This->async = isAsync;
2227 static HRESULT WINAPI domdoc_abort(
2228 IXMLDOMDocument3 *iface )
2230 domdoc *This = impl_from_IXMLDOMDocument3(iface);
2231 FIXME("%p\n", This);
2235 /* don't rely on data to be in BSTR format, treat it as WCHAR string */
2236 static HRESULT WINAPI domdoc_loadXML(
2237 IXMLDOMDocument3 *iface,
2239 VARIANT_BOOL* isSuccessful )
2241 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2242 xmlDocPtr xmldoc = NULL;
2243 HRESULT hr = S_FALSE, hr2;
2245 TRACE("(%p)->(%s %p)\n", This, debugstr_w(data), isSuccessful );
2247 assert ( &This->node );
2251 *isSuccessful = VARIANT_FALSE;
2257 /* skip leading spaces if needed */
2258 if (This->properties->version == MSXML_DEFAULT || This->properties->version == MSXML26)
2260 if (isspaceW(*ptr)) ptr++; else break;
2262 xmldoc = doparse(This, (char*)ptr, strlenW(ptr)*sizeof(WCHAR), XML_CHAR_ENCODING_UTF16LE);
2265 This->error = E_FAIL;
2266 TRACE("failed to parse document\n");
2270 hr = This->error = S_OK;
2271 *isSuccessful = VARIANT_TRUE;
2272 TRACE("parsed document %p\n", xmldoc);
2277 xmldoc = xmlNewDoc(NULL);
2279 xmldoc->_private = create_priv();
2281 hr2 = attach_xmldoc(This, xmldoc);
2288 static int XMLCALL domdoc_save_writecallback(void *ctx, const char *buffer, int len)
2292 if(!WriteFile(ctx, buffer, len, &written, NULL))
2294 WARN("write error\n");
2301 static int XMLCALL domdoc_save_closecallback(void *ctx)
2303 return CloseHandle(ctx) ? 0 : -1;
2306 static int XMLCALL domdoc_stream_save_writecallback(void *ctx, const char *buffer, int len)
2311 hr = IStream_Write((IStream*)ctx, buffer, len, &written);
2314 WARN("stream write error: 0x%08x\n", hr);
2321 static int XMLCALL domdoc_stream_save_closecallback(void *ctx)
2323 IStream_Release((IStream*)ctx);
2327 static HRESULT WINAPI domdoc_save(
2328 IXMLDOMDocument3 *iface,
2329 VARIANT destination )
2331 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2332 xmlSaveCtxtPtr ctx = NULL;
2336 TRACE("(%p)->(%s)\n", This, debugstr_variant(&destination));
2338 switch (V_VT(&destination))
2342 IUnknown *pUnk = V_UNKNOWN(&destination);
2343 IXMLDOMDocument3 *document;
2346 ret = IUnknown_QueryInterface(pUnk, &IID_IXMLDOMDocument3, (void**)&document);
2349 VARIANT_BOOL success;
2352 ret = IXMLDOMDocument3_get_xml(iface, &xml);
2355 ret = IXMLDOMDocument3_loadXML(document, xml, &success);
2359 IXMLDOMDocument3_Release(document);
2363 ret = IUnknown_QueryInterface(pUnk, &IID_IStream, (void**)&stream);
2366 ctx = xmlSaveToIO(domdoc_stream_save_writecallback,
2367 domdoc_stream_save_closecallback, stream, NULL, XML_SAVE_NO_DECL);
2371 IStream_Release(stream);
2379 case VT_BSTR | VT_BYREF:
2381 /* save with file path */
2382 HANDLE handle = CreateFileW( (V_VT(&destination) & VT_BYREF)? *V_BSTRREF(&destination) : V_BSTR(&destination),
2383 GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL );
2384 if( handle == INVALID_HANDLE_VALUE )
2386 WARN("failed to create file\n");
2390 /* disable top XML declaration */
2391 ctx = xmlSaveToIO(domdoc_save_writecallback, domdoc_save_closecallback,
2392 handle, NULL, XML_SAVE_NO_DECL);
2395 CloseHandle(handle);
2402 FIXME("Unhandled VARIANT: %s\n", debugstr_variant(&destination));
2406 xmldecl = xmldoc_unlink_xmldecl(get_doc(This));
2407 if (xmlSaveDoc(ctx, get_doc(This)) == -1) ret = S_FALSE;
2408 xmldoc_link_xmldecl(get_doc(This), xmldecl);
2410 /* will release resources through close callback */
2416 static HRESULT WINAPI domdoc_get_validateOnParse(
2417 IXMLDOMDocument3 *iface,
2418 VARIANT_BOOL* isValidating )
2420 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2421 TRACE("(%p)->(%p: %d)\n", This, isValidating, This->validating);
2422 *isValidating = This->validating;
2427 static HRESULT WINAPI domdoc_put_validateOnParse(
2428 IXMLDOMDocument3 *iface,
2429 VARIANT_BOOL isValidating )
2431 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2432 TRACE("(%p)->(%d)\n", This, isValidating);
2433 This->validating = isValidating;
2438 static HRESULT WINAPI domdoc_get_resolveExternals(
2439 IXMLDOMDocument3 *iface,
2440 VARIANT_BOOL* isResolving )
2442 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2443 TRACE("(%p)->(%p: %d)\n", This, isResolving, This->resolving);
2444 *isResolving = This->resolving;
2449 static HRESULT WINAPI domdoc_put_resolveExternals(
2450 IXMLDOMDocument3 *iface,
2451 VARIANT_BOOL isResolving )
2453 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2454 TRACE("(%p)->(%d)\n", This, isResolving);
2455 This->resolving = isResolving;
2460 static HRESULT WINAPI domdoc_get_preserveWhiteSpace(
2461 IXMLDOMDocument3 *iface,
2462 VARIANT_BOOL* isPreserving )
2464 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2465 TRACE("(%p)->(%p: %d)\n", This, isPreserving, This->properties->preserving);
2466 *isPreserving = This->properties->preserving;
2471 static HRESULT WINAPI domdoc_put_preserveWhiteSpace(
2472 IXMLDOMDocument3 *iface,
2473 VARIANT_BOOL isPreserving )
2475 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2476 TRACE("(%p)->(%d)\n", This, isPreserving);
2477 This->properties->preserving = isPreserving;
2482 static HRESULT WINAPI domdoc_put_onreadystatechange(
2483 IXMLDOMDocument3 *iface,
2486 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2488 TRACE("(%p)->(%s)\n", This, debugstr_variant(&event));
2489 return set_doc_event(This, EVENTID_READYSTATECHANGE, &event);
2493 static HRESULT WINAPI domdoc_put_onDataAvailable(
2494 IXMLDOMDocument3 *iface,
2495 VARIANT onDataAvailableSink )
2497 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2498 FIXME("%p\n", This);
2502 static HRESULT WINAPI domdoc_put_onTransformNode(
2503 IXMLDOMDocument3 *iface,
2504 VARIANT onTransformNodeSink )
2506 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2507 FIXME("%p\n", This);
2511 static HRESULT WINAPI domdoc_get_namespaces(
2512 IXMLDOMDocument3* iface,
2513 IXMLDOMSchemaCollection** collection )
2515 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2516 FIXME("(%p)->(%p): stub\n", This, collection);
2518 if (!collection) return E_POINTER;
2523 static HRESULT WINAPI domdoc_get_schemas(
2524 IXMLDOMDocument3* iface,
2527 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2528 HRESULT hr = S_FALSE;
2529 IXMLDOMSchemaCollection2* cur_schema = This->properties->schemaCache;
2531 TRACE("(%p)->(%p)\n", This, var1);
2533 VariantInit(var1); /* Test shows we don't call VariantClear here */
2534 V_VT(var1) = VT_NULL;
2538 hr = IXMLDOMSchemaCollection2_QueryInterface(cur_schema, &IID_IDispatch, (void**)&V_DISPATCH(var1));
2540 V_VT(var1) = VT_DISPATCH;
2545 static HRESULT WINAPI domdoc_putref_schemas(
2546 IXMLDOMDocument3* iface,
2549 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2550 HRESULT hr = E_FAIL;
2551 IXMLDOMSchemaCollection2* new_schema = NULL;
2553 FIXME("(%p): semi-stub\n", This);
2557 hr = IUnknown_QueryInterface(V_UNKNOWN(&var1), &IID_IXMLDOMSchemaCollection, (void**)&new_schema);
2561 hr = IDispatch_QueryInterface(V_DISPATCH(&var1), &IID_IXMLDOMSchemaCollection, (void**)&new_schema);
2570 WARN("Can't get schema from vt %x\n", V_VT(&var1));
2575 IXMLDOMSchemaCollection2* old_schema = InterlockedExchangePointer((void**)&This->properties->schemaCache, new_schema);
2576 if(old_schema) IXMLDOMSchemaCollection2_Release(old_schema);
2582 static inline BOOL is_wellformed(xmlDocPtr doc)
2584 #ifdef HAVE_XMLDOC_PROPERTIES
2585 return doc->properties & XML_DOC_WELLFORMED;
2587 /* Not a full check, but catches the worst violations */
2591 for (child = doc->children; child != NULL; child = child->next)
2593 switch (child->type)
2595 case XML_ELEMENT_NODE:
2600 case XML_CDATA_SECTION_NODE:
2612 static void LIBXML2_LOG_CALLBACK validate_error(void* ctx, char const* msg, ...)
2616 LIBXML2_CALLBACK_ERR(domdoc_validateNode, msg, ap);
2620 static void LIBXML2_LOG_CALLBACK validate_warning(void* ctx, char const* msg, ...)
2624 LIBXML2_CALLBACK_WARN(domdoc_validateNode, msg, ap);
2628 static HRESULT WINAPI domdoc_validateNode(
2629 IXMLDOMDocument3* iface,
2631 IXMLDOMParseError** err)
2633 domdoc* This = impl_from_IXMLDOMDocument3(iface);
2634 LONG state, err_code = 0;
2638 TRACE("(%p)->(%p, %p)\n", This, node, err);
2639 domdoc_get_readyState(iface, &state);
2640 if (state != READYSTATE_COMPLETE)
2643 *err = create_parseError(err_code, NULL, NULL, NULL, 0, 0, 0);
2650 *err = create_parseError(err_code, NULL, NULL, NULL, 0, 0, 0);
2654 if (!get_node_obj(node)->node || get_node_obj(node)->node->doc != get_doc(This))
2657 *err = create_parseError(err_code, NULL, NULL, NULL, 0, 0, 0);
2661 if (!is_wellformed(get_doc(This)))
2663 ERR("doc not well-formed\n");
2665 *err = create_parseError(E_XML_NOTWF, NULL, NULL, NULL, 0, 0, 0);
2669 /* DTD validation */
2670 if (get_doc(This)->intSubset || get_doc(This)->extSubset)
2672 xmlValidCtxtPtr vctx = xmlNewValidCtxt();
2673 vctx->error = validate_error;
2674 vctx->warning = validate_warning;
2677 if (!((node == (IXMLDOMNode*)iface)?
2678 xmlValidateDocument(vctx, get_doc(This)) :
2679 xmlValidateElement(vctx, get_doc(This), get_node_obj(node)->node)))
2681 /* TODO: get a real error code here */
2682 TRACE("DTD validation failed\n");
2683 err_code = E_XML_INVALID;
2686 xmlFreeValidCtxt(vctx);
2689 /* Schema validation */
2690 if (hr == S_OK && This->properties->schemaCache != NULL)
2693 hr = SchemaCache_validate_tree(This->properties->schemaCache, get_node_obj(node)->node);
2697 /* TODO: get a real error code here */
2700 TRACE("schema validation succeeded\n");
2704 ERR("schema validation failed\n");
2705 err_code = E_XML_INVALID;
2710 /* not really OK, just didn't find a schema for the ns */
2717 ERR("no DTD or schema found\n");
2718 err_code = E_XML_NODTD;
2723 *err = create_parseError(err_code, NULL, NULL, NULL, 0, 0, 0);
2728 static HRESULT WINAPI domdoc_validate(
2729 IXMLDOMDocument3* iface,
2730 IXMLDOMParseError** err)
2732 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2733 TRACE("(%p)->(%p)\n", This, err);
2734 return domdoc_validateNode(iface, (IXMLDOMNode*)iface, err);
2737 static HRESULT WINAPI domdoc_setProperty(
2738 IXMLDOMDocument3* iface,
2742 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2744 TRACE("(%p)->(%s)\n", This, debugstr_w(p));
2746 if (lstrcmpiW(p, PropertySelectionLanguageW) == 0)
2752 V_VT(&varStr) = VT_EMPTY;
2753 if (V_VT(&var) != VT_BSTR)
2755 if (FAILED(hr = VariantChangeType(&varStr, &var, 0, VT_BSTR)))
2757 bstr = V_BSTR(&varStr);
2760 bstr = V_BSTR(&var);
2763 if (lstrcmpiW(bstr, PropValueXPathW) == 0)
2764 This->properties->XPath = TRUE;
2765 else if (lstrcmpiW(bstr, PropValueXSLPatternW) == 0)
2766 This->properties->XPath = FALSE;
2770 VariantClear(&varStr);
2773 else if (lstrcmpiW(p, PropertySelectionNamespacesW) == 0)
2775 xmlChar *nsStr = (xmlChar*)This->properties->selectNsStr;
2776 struct list *pNsList;
2781 V_VT(&varStr) = VT_EMPTY;
2782 if (V_VT(&var) != VT_BSTR)
2784 if (FAILED(hr = VariantChangeType(&varStr, &var, 0, VT_BSTR)))
2786 bstr = V_BSTR(&varStr);
2789 bstr = V_BSTR(&var);
2793 pNsList = &(This->properties->selectNsList);
2794 clear_selectNsList(pNsList);
2796 nsStr = xmlchar_from_wchar(bstr);
2798 TRACE("property value: \"%s\"\n", debugstr_w(bstr));
2800 This->properties->selectNsStr = nsStr;
2801 This->properties->selectNsStr_len = xmlStrlen(nsStr);
2804 xmlChar *pTokBegin, *pTokEnd, *pTokInner;
2805 select_ns_entry* ns_entry = NULL;
2806 xmlXPathContextPtr ctx;
2808 ctx = xmlXPathNewContext(This->node.node->doc);
2811 /* skip leading spaces */
2812 while (*pTokBegin == ' ' || *pTokBegin == '\n' ||
2813 *pTokBegin == '\t' || *pTokBegin == '\r')
2816 for (; *pTokBegin; pTokBegin = pTokEnd)
2819 memset(ns_entry, 0, sizeof(select_ns_entry));
2821 ns_entry = heap_alloc_zero(sizeof(select_ns_entry));
2823 while (*pTokBegin == ' ')
2825 pTokEnd = pTokBegin;
2826 while (*pTokEnd != ' ' && *pTokEnd != 0)
2829 if (xmlStrncmp(pTokBegin, (xmlChar const*)"xmlns", 5) != 0)
2832 WARN("Syntax error in xmlns string: %s\n\tat token: %s\n",
2833 debugstr_w(bstr), debugstr_an((const char*)pTokBegin, pTokEnd-pTokBegin));
2838 if (*pTokBegin == '=')
2840 /*valid for XSLPattern?*/
2841 FIXME("Setting default xmlns not supported - skipping.\n");
2844 else if (*pTokBegin == ':')
2846 ns_entry->prefix = ++pTokBegin;
2847 for (pTokInner = pTokBegin; pTokInner != pTokEnd && *pTokInner != '='; ++pTokInner)
2850 if (pTokInner == pTokEnd)
2853 WARN("Syntax error in xmlns string: %s\n\tat token: %s\n",
2854 debugstr_w(bstr), debugstr_an((const char*)pTokBegin, pTokEnd-pTokBegin));
2858 ns_entry->prefix_end = *pTokInner;
2862 if (pTokEnd-pTokInner > 1 &&
2863 ((*pTokInner == '\'' && *(pTokEnd-1) == '\'') ||
2864 (*pTokInner == '"' && *(pTokEnd-1) == '"')))
2866 ns_entry->href = ++pTokInner;
2867 ns_entry->href_end = *(pTokEnd-1);
2869 list_add_tail(pNsList, &ns_entry->entry);
2870 /*let libxml figure out if they're valid from here ;)*/
2871 if (xmlXPathRegisterNs(ctx, ns_entry->prefix, ns_entry->href) != 0)
2880 WARN("Syntax error in xmlns string: %s\n\tat token: %s\n",
2881 debugstr_w(bstr), debugstr_an((const char*)pTokInner, pTokEnd-pTokInner));
2882 list_add_tail(pNsList, &ns_entry->entry);
2895 heap_free(ns_entry);
2896 xmlXPathFreeContext(ctx);
2899 VariantClear(&varStr);
2902 else if (lstrcmpiW(p, PropertyProhibitDTDW) == 0 ||
2903 lstrcmpiW(p, PropertyNewParserW) == 0 ||
2904 lstrcmpiW(p, PropertyResolveExternalsW) == 0)
2907 FIXME("Ignoring property %s, value %d\n", debugstr_w(p), V_BOOL(&var));
2911 FIXME("Unknown property %s\n", debugstr_w(p));
2915 static HRESULT WINAPI domdoc_getProperty(
2916 IXMLDOMDocument3* iface,
2920 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2922 TRACE("(%p)->(%p)\n", This, debugstr_w(p));
2925 return E_INVALIDARG;
2927 if (lstrcmpiW(p, PropertySelectionLanguageW) == 0)
2929 V_VT(var) = VT_BSTR;
2930 V_BSTR(var) = This->properties->XPath ?
2931 SysAllocString(PropValueXPathW) :
2932 SysAllocString(PropValueXSLPatternW);
2933 return V_BSTR(var) ? S_OK : E_OUTOFMEMORY;
2935 else if (lstrcmpiW(p, PropertySelectionNamespacesW) == 0)
2938 BSTR rebuiltStr, cur;
2939 const xmlChar *nsStr;
2940 struct list *pNsList;
2941 select_ns_entry* pNsEntry;
2943 V_VT(var) = VT_BSTR;
2944 nsStr = This->properties->selectNsStr;
2945 pNsList = &This->properties->selectNsList;
2946 lenA = This->properties->selectNsStr_len;
2947 lenW = MultiByteToWideChar(CP_UTF8, 0, (LPCSTR)nsStr, lenA+1, NULL, 0);
2948 rebuiltStr = heap_alloc(lenW*sizeof(WCHAR));
2949 MultiByteToWideChar(CP_UTF8, 0, (LPCSTR)nsStr, lenA+1, rebuiltStr, lenW);
2951 /* this is fine because all of the chars that end tokens are ASCII*/
2952 LIST_FOR_EACH_ENTRY(pNsEntry, pNsList, select_ns_entry, entry)
2954 while (*cur != 0) ++cur;
2955 if (pNsEntry->prefix_end)
2957 *cur = pNsEntry->prefix_end;
2958 while (*cur != 0) ++cur;
2961 if (pNsEntry->href_end)
2963 *cur = pNsEntry->href_end;
2966 V_BSTR(var) = SysAllocString(rebuiltStr);
2967 heap_free(rebuiltStr);
2971 FIXME("Unknown property %s\n", debugstr_w(p));
2975 static HRESULT WINAPI domdoc_importNode(
2976 IXMLDOMDocument3* iface,
2979 IXMLDOMNode** clone)
2981 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2982 FIXME("(%p)->(%p %d %p): stub\n", This, node, deep, clone);
2986 static const struct IXMLDOMDocument3Vtbl XMLDOMDocument3Vtbl =
2988 domdoc_QueryInterface,
2991 domdoc_GetTypeInfoCount,
2993 domdoc_GetIDsOfNames,
2995 domdoc_get_nodeName,
2996 domdoc_get_nodeValue,
2997 domdoc_put_nodeValue,
2998 domdoc_get_nodeType,
2999 domdoc_get_parentNode,
3000 domdoc_get_childNodes,
3001 domdoc_get_firstChild,
3002 domdoc_get_lastChild,
3003 domdoc_get_previousSibling,
3004 domdoc_get_nextSibling,
3005 domdoc_get_attributes,
3006 domdoc_insertBefore,
3007 domdoc_replaceChild,
3010 domdoc_hasChildNodes,
3011 domdoc_get_ownerDocument,
3013 domdoc_get_nodeTypeString,
3016 domdoc_get_specified,
3017 domdoc_get_definition,
3018 domdoc_get_nodeTypedValue,
3019 domdoc_put_nodeTypedValue,
3020 domdoc_get_dataType,
3021 domdoc_put_dataType,
3023 domdoc_transformNode,
3025 domdoc_selectSingleNode,
3027 domdoc_get_namespaceURI,
3029 domdoc_get_baseName,
3030 domdoc_transformNodeToObject,
3032 domdoc_get_implementation,
3033 domdoc_get_documentElement,
3034 domdoc_put_documentElement,
3035 domdoc_createElement,
3036 domdoc_createDocumentFragment,
3037 domdoc_createTextNode,
3038 domdoc_createComment,
3039 domdoc_createCDATASection,
3040 domdoc_createProcessingInstruction,
3041 domdoc_createAttribute,
3042 domdoc_createEntityReference,
3043 domdoc_getElementsByTagName,
3047 domdoc_get_readyState,
3048 domdoc_get_parseError,
3055 domdoc_get_validateOnParse,
3056 domdoc_put_validateOnParse,
3057 domdoc_get_resolveExternals,
3058 domdoc_put_resolveExternals,
3059 domdoc_get_preserveWhiteSpace,
3060 domdoc_put_preserveWhiteSpace,
3061 domdoc_put_onreadystatechange,
3062 domdoc_put_onDataAvailable,
3063 domdoc_put_onTransformNode,
3064 domdoc_get_namespaces,
3066 domdoc_putref_schemas,
3070 domdoc_validateNode,
3074 /* IConnectionPointContainer */
3075 static HRESULT WINAPI ConnectionPointContainer_QueryInterface(IConnectionPointContainer *iface,
3076 REFIID riid, void **ppv)
3078 domdoc *This = impl_from_IConnectionPointContainer(iface);
3079 return IXMLDOMDocument3_QueryInterface(&This->IXMLDOMDocument3_iface, riid, ppv);
3082 static ULONG WINAPI ConnectionPointContainer_AddRef(IConnectionPointContainer *iface)
3084 domdoc *This = impl_from_IConnectionPointContainer(iface);
3085 return IXMLDOMDocument3_AddRef(&This->IXMLDOMDocument3_iface);
3088 static ULONG WINAPI ConnectionPointContainer_Release(IConnectionPointContainer *iface)
3090 domdoc *This = impl_from_IConnectionPointContainer(iface);
3091 return IXMLDOMDocument3_Release(&This->IXMLDOMDocument3_iface);
3094 static HRESULT WINAPI ConnectionPointContainer_EnumConnectionPoints(IConnectionPointContainer *iface,
3095 IEnumConnectionPoints **ppEnum)
3097 domdoc *This = impl_from_IConnectionPointContainer(iface);
3098 FIXME("(%p)->(%p): stub\n", This, ppEnum);
3102 static HRESULT WINAPI ConnectionPointContainer_FindConnectionPoint(IConnectionPointContainer *iface,
3103 REFIID riid, IConnectionPoint **cp)
3105 domdoc *This = impl_from_IConnectionPointContainer(iface);
3106 ConnectionPoint *iter;
3108 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), cp);
3112 for(iter = This->cp_list; iter; iter = iter->next)
3114 if (IsEqualGUID(iter->iid, riid))
3115 *cp = &iter->IConnectionPoint_iface;
3120 IConnectionPoint_AddRef(*cp);
3124 FIXME("unsupported riid %s\n", debugstr_guid(riid));
3125 return CONNECT_E_NOCONNECTION;
3129 static const struct IConnectionPointContainerVtbl ConnectionPointContainerVtbl =
3131 ConnectionPointContainer_QueryInterface,
3132 ConnectionPointContainer_AddRef,
3133 ConnectionPointContainer_Release,
3134 ConnectionPointContainer_EnumConnectionPoints,
3135 ConnectionPointContainer_FindConnectionPoint
3138 /* IConnectionPoint */
3139 static HRESULT WINAPI ConnectionPoint_QueryInterface(IConnectionPoint *iface,
3140 REFIID riid, void **ppv)
3142 ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3144 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv );
3148 if (IsEqualGUID(&IID_IUnknown, riid) ||
3149 IsEqualGUID(&IID_IConnectionPoint, riid))
3156 IConnectionPoint_AddRef(iface);
3160 WARN("Unsupported interface %s\n", debugstr_guid(riid));
3161 return E_NOINTERFACE;
3164 static ULONG WINAPI ConnectionPoint_AddRef(IConnectionPoint *iface)
3166 ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3167 return IConnectionPointContainer_AddRef(This->container);
3170 static ULONG WINAPI ConnectionPoint_Release(IConnectionPoint *iface)
3172 ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3173 return IConnectionPointContainer_Release(This->container);
3176 static HRESULT WINAPI ConnectionPoint_GetConnectionInterface(IConnectionPoint *iface, IID *iid)
3178 ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3180 TRACE("(%p)->(%p)\n", This, iid);
3182 if (!iid) return E_POINTER;
3188 static HRESULT WINAPI ConnectionPoint_GetConnectionPointContainer(IConnectionPoint *iface,
3189 IConnectionPointContainer **container)
3191 ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3193 TRACE("(%p)->(%p)\n", This, container);
3195 if (!container) return E_POINTER;
3197 *container = This->container;
3198 IConnectionPointContainer_AddRef(*container);
3202 static HRESULT WINAPI ConnectionPoint_Advise(IConnectionPoint *iface, IUnknown *pUnkSink,
3205 ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3206 FIXME("(%p)->(%p %p): stub\n", This, pUnkSink, pdwCookie);
3210 static HRESULT WINAPI ConnectionPoint_Unadvise(IConnectionPoint *iface, DWORD cookie)
3212 ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3214 TRACE("(%p)->(%d)\n", This, cookie);
3216 if (cookie == 0 || cookie > This->sinks_size || !This->sinks[cookie-1].unk)
3217 return CONNECT_E_NOCONNECTION;
3219 IUnknown_Release(This->sinks[cookie-1].unk);
3220 This->sinks[cookie-1].unk = NULL;
3225 static HRESULT WINAPI ConnectionPoint_EnumConnections(IConnectionPoint *iface,
3226 IEnumConnections **ppEnum)
3228 ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3229 FIXME("(%p)->(%p): stub\n", This, ppEnum);
3233 static const IConnectionPointVtbl ConnectionPointVtbl =
3235 ConnectionPoint_QueryInterface,
3236 ConnectionPoint_AddRef,
3237 ConnectionPoint_Release,
3238 ConnectionPoint_GetConnectionInterface,
3239 ConnectionPoint_GetConnectionPointContainer,
3240 ConnectionPoint_Advise,
3241 ConnectionPoint_Unadvise,
3242 ConnectionPoint_EnumConnections
3245 static void ConnectionPoint_Init(ConnectionPoint *cp, struct domdoc *doc, REFIID riid)
3247 cp->IConnectionPoint_iface.lpVtbl = &ConnectionPointVtbl;
3253 cp->next = doc->cp_list;
3256 cp->container = &doc->IConnectionPointContainer_iface;
3259 /* domdoc implementation of IObjectWithSite */
3260 static HRESULT WINAPI
3261 domdoc_ObjectWithSite_QueryInterface( IObjectWithSite* iface, REFIID riid, void** ppvObject )
3263 domdoc *This = impl_from_IObjectWithSite(iface);
3264 return IXMLDOMDocument3_QueryInterface(&This->IXMLDOMDocument3_iface, riid, ppvObject);
3267 static ULONG WINAPI domdoc_ObjectWithSite_AddRef( IObjectWithSite* iface )
3269 domdoc *This = impl_from_IObjectWithSite(iface);
3270 return IXMLDOMDocument3_AddRef(&This->IXMLDOMDocument3_iface);
3273 static ULONG WINAPI domdoc_ObjectWithSite_Release( IObjectWithSite* iface )
3275 domdoc *This = impl_from_IObjectWithSite(iface);
3276 return IXMLDOMDocument3_Release(&This->IXMLDOMDocument3_iface);
3279 static HRESULT WINAPI domdoc_ObjectWithSite_GetSite( IObjectWithSite *iface, REFIID iid, void **ppvSite )
3281 domdoc *This = impl_from_IObjectWithSite(iface);
3283 TRACE("(%p)->(%s %p)\n", This, debugstr_guid( iid ), ppvSite );
3288 return IUnknown_QueryInterface( This->site, iid, ppvSite );
3291 static HRESULT WINAPI domdoc_ObjectWithSite_SetSite( IObjectWithSite *iface, IUnknown *punk )
3293 domdoc *This = impl_from_IObjectWithSite(iface);
3295 TRACE("(%p)->(%p)\n", iface, punk);
3301 IUnknown_Release( This->site );
3308 IUnknown_AddRef( punk );
3311 IUnknown_Release( This->site );
3318 static const IObjectWithSiteVtbl domdocObjectSite =
3320 domdoc_ObjectWithSite_QueryInterface,
3321 domdoc_ObjectWithSite_AddRef,
3322 domdoc_ObjectWithSite_Release,
3323 domdoc_ObjectWithSite_SetSite,
3324 domdoc_ObjectWithSite_GetSite
3327 static HRESULT WINAPI domdoc_Safety_QueryInterface(IObjectSafety *iface, REFIID riid, void **ppv)
3329 domdoc *This = impl_from_IObjectSafety(iface);
3330 return IXMLDOMDocument3_QueryInterface(&This->IXMLDOMDocument3_iface, riid, ppv);
3333 static ULONG WINAPI domdoc_Safety_AddRef(IObjectSafety *iface)
3335 domdoc *This = impl_from_IObjectSafety(iface);
3336 return IXMLDOMDocument3_AddRef(&This->IXMLDOMDocument3_iface);
3339 static ULONG WINAPI domdoc_Safety_Release(IObjectSafety *iface)
3341 domdoc *This = impl_from_IObjectSafety(iface);
3342 return IXMLDOMDocument3_Release(&This->IXMLDOMDocument3_iface);
3345 #define SAFETY_SUPPORTED_OPTIONS (INTERFACESAFE_FOR_UNTRUSTED_CALLER|INTERFACESAFE_FOR_UNTRUSTED_DATA|INTERFACE_USES_SECURITY_MANAGER)
3347 static HRESULT WINAPI domdoc_Safety_GetInterfaceSafetyOptions(IObjectSafety *iface, REFIID riid,
3348 DWORD *supported, DWORD *enabled)
3350 domdoc *This = impl_from_IObjectSafety(iface);
3352 TRACE("(%p)->(%s %p %p)\n", This, debugstr_guid(riid), supported, enabled);
3354 if(!supported || !enabled) return E_POINTER;
3356 *supported = SAFETY_SUPPORTED_OPTIONS;
3357 *enabled = This->safeopt;
3362 static HRESULT WINAPI domdoc_Safety_SetInterfaceSafetyOptions(IObjectSafety *iface, REFIID riid,
3363 DWORD mask, DWORD enabled)
3365 domdoc *This = impl_from_IObjectSafety(iface);
3366 TRACE("(%p)->(%s %x %x)\n", This, debugstr_guid(riid), mask, enabled);
3368 if ((mask & ~SAFETY_SUPPORTED_OPTIONS) != 0)
3371 This->safeopt = (This->safeopt & ~mask) | (mask & enabled);
3376 #undef SAFETY_SUPPORTED_OPTIONS
3378 static const IObjectSafetyVtbl domdocObjectSafetyVtbl = {
3379 domdoc_Safety_QueryInterface,
3380 domdoc_Safety_AddRef,
3381 domdoc_Safety_Release,
3382 domdoc_Safety_GetInterfaceSafetyOptions,
3383 domdoc_Safety_SetInterfaceSafetyOptions
3386 static const tid_t domdoc_iface_tids[] = {
3387 IXMLDOMDocument3_tid,
3391 static dispex_static_data_t domdoc_dispex = {
3393 IXMLDOMDocument3_tid,
3398 HRESULT get_domdoc_from_xmldoc(xmlDocPtr xmldoc, IXMLDOMDocument3 **document)
3402 doc = heap_alloc( sizeof (*doc) );
3404 return E_OUTOFMEMORY;
3406 doc->IXMLDOMDocument3_iface.lpVtbl = &XMLDOMDocument3Vtbl;
3407 doc->IPersistStreamInit_iface.lpVtbl = &xmldoc_IPersistStreamInit_VTable;
3408 doc->IObjectWithSite_iface.lpVtbl = &domdocObjectSite;
3409 doc->IObjectSafety_iface.lpVtbl = &domdocObjectSafetyVtbl;
3410 doc->IConnectionPointContainer_iface.lpVtbl = &ConnectionPointContainerVtbl;
3412 doc->async = VARIANT_TRUE;
3413 doc->validating = 0;
3415 doc->properties = properties_from_xmlDocPtr(xmldoc);
3421 doc->cp_list = NULL;
3422 memset(doc->events, 0, sizeof(doc->events));
3424 /* events connection points */
3425 ConnectionPoint_Init(&doc->cp_dispatch, doc, &IID_IDispatch);
3426 ConnectionPoint_Init(&doc->cp_propnotif, doc, &IID_IPropertyNotifySink);
3427 ConnectionPoint_Init(&doc->cp_domdocevents, doc, &DIID_XMLDOMDocumentEvents);
3429 init_xmlnode(&doc->node, (xmlNodePtr)xmldoc, (IXMLDOMNode*)&doc->IXMLDOMDocument3_iface,
3432 *document = &doc->IXMLDOMDocument3_iface;
3434 TRACE("returning iface %p\n", *document);
3438 HRESULT DOMDocument_create(MSXML_VERSION version, IUnknown *pUnkOuter, void **ppObj)
3443 TRACE("(%d, %p, %p)\n", version, pUnkOuter, ppObj);
3445 xmldoc = xmlNewDoc(NULL);
3447 return E_OUTOFMEMORY;
3449 xmldoc_init(xmldoc, version);
3451 hr = get_domdoc_from_xmldoc(xmldoc, (IXMLDOMDocument3**)ppObj);
3454 free_properties(properties_from_xmlDocPtr(xmldoc));
3455 heap_free(xmldoc->_private);
3463 IUnknown* create_domdoc( xmlNodePtr document )
3468 TRACE("(%p)\n", document);
3470 hr = get_domdoc_from_xmldoc((xmlDocPtr)document, (IXMLDOMDocument3**)&pObj);
3479 HRESULT DOMDocument_create(MSXML_VERSION version, IUnknown *pUnkOuter, void **ppObj)
3481 MESSAGE("This program tried to use a DOMDocument object, but\n"
3482 "libxml2 support was not present at compile time.\n");