2 * DOM Document implementation
4 * Copyright 2005 Mike McCormack
5 * Copyright 2010 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
43 #include "wine/debug.h"
44 #include "wine/list.h"
46 #include "msxml_private.h"
48 WINE_DEFAULT_DEBUG_CHANNEL(msxml);
52 #include <libxml/xpathInternals.h>
53 #include <libxml/xmlsave.h>
54 #include <libxml/SAX2.h>
55 #include <libxml/parserInternals.h>
57 /* not defined in older versions */
58 #define XML_SAVE_FORMAT 1
59 #define XML_SAVE_NO_DECL 2
60 #define XML_SAVE_NO_EMPTY 4
61 #define XML_SAVE_NO_XHTML 8
62 #define XML_SAVE_XHTML 16
63 #define XML_SAVE_AS_XML 32
64 #define XML_SAVE_AS_HTML 64
66 static const WCHAR PropertySelectionLanguageW[] = {'S','e','l','e','c','t','i','o','n','L','a','n','g','u','a','g','e',0};
67 static const WCHAR PropertySelectionNamespacesW[] = {'S','e','l','e','c','t','i','o','n','N','a','m','e','s','p','a','c','e','s',0};
68 static const WCHAR PropertyProhibitDTDW[] = {'P','r','o','h','i','b','i','t','D','T','D',0};
69 static const WCHAR PropertyNewParserW[] = {'N','e','w','P','a','r','s','e','r',0};
70 static const WCHAR PropValueXPathW[] = {'X','P','a','t','h',0};
71 static const WCHAR PropValueXSLPatternW[] = {'X','S','L','P','a','t','t','e','r','n',0};
73 /* Anything that passes the test_get_ownerDocument()
74 * tests can go here (data shared between all instances).
75 * We need to preserve this when reloading a document,
76 * and also need access to it from the libxml backend. */
77 typedef struct _domdoc_properties {
78 MSXML_VERSION version;
79 VARIANT_BOOL preserving;
80 IXMLDOMSchemaCollection2* schemaCache;
81 struct list selectNsList;
82 xmlChar const* selectNsStr;
87 typedef struct ConnectionPoint ConnectionPoint;
88 typedef struct domdoc domdoc;
90 struct ConnectionPoint
92 const IConnectionPointVtbl *lpVtblConnectionPoint;
95 ConnectionPoint *next;
96 IConnectionPointContainer *container;
103 IPropertyNotifySink *propnotif;
111 const struct IXMLDOMDocument3Vtbl *lpVtbl;
112 const struct IPersistStreamInitVtbl *lpvtblIPersistStreamInit;
113 const struct IObjectWithSiteVtbl *lpvtblIObjectWithSite;
114 const struct IObjectSafetyVtbl *lpvtblIObjectSafety;
115 const struct ISupportErrorInfoVtbl *lpvtblISupportErrorInfo;
116 const struct IConnectionPointContainerVtbl *lpVtblConnectionPointContainer;
119 VARIANT_BOOL validating;
120 VARIANT_BOOL resolving;
121 domdoc_properties* properties;
134 /* connection list */
135 ConnectionPoint *cp_list;
136 ConnectionPoint cp_domdocevents;
137 ConnectionPoint cp_propnotif;
138 ConnectionPoint cp_dispatch;
141 static inline ConnectionPoint *impl_from_IConnectionPoint(IConnectionPoint *iface)
143 return (ConnectionPoint *)((char*)iface - FIELD_OFFSET(ConnectionPoint, lpVtblConnectionPoint));
147 In native windows, the whole lifetime management of XMLDOMNodes is
148 managed automatically using reference counts. Wine emulates that by
149 maintaining a reference count to the document that is increased for
150 each IXMLDOMNode pointer passed out for this document. If all these
151 pointers are gone, the document is unreachable and gets freed, that
152 is, all nodes in the tree of the document get freed.
154 You are able to create nodes that are associated to a document (in
155 fact, in msxml's XMLDOM model, all nodes are associated to a document),
156 but not in the tree of that document, for example using the createFoo
157 functions from IXMLDOMDocument. These nodes do not get cleaned up
158 by libxml, so we have to do it ourselves.
160 To catch these nodes, a list of "orphan nodes" is introduced.
161 It contains pointers to all roots of node trees that are
162 associated with the document without being part of the document
163 tree. All nodes with parent==NULL (except for the document root nodes)
164 should be in the orphan node list of their document. All orphan nodes
165 get freed together with the document itself.
168 typedef struct _xmldoc_priv {
171 domdoc_properties* properties;
174 typedef struct _orphan_entry {
179 typedef struct _select_ns_entry {
181 xmlChar const* prefix;
187 static inline xmldoc_priv * priv_from_xmlDocPtr(const xmlDocPtr doc)
189 return doc->_private;
192 static inline domdoc_properties * properties_from_xmlDocPtr(xmlDocPtr doc)
194 return priv_from_xmlDocPtr(doc)->properties;
197 BOOL is_xpathmode(const xmlDocPtr doc)
199 return properties_from_xmlDocPtr(doc)->XPath;
202 void set_xpathmode(xmlDocPtr doc, BOOL xpath)
204 properties_from_xmlDocPtr(doc)->XPath = xpath;
207 int registerNamespaces(xmlXPathContextPtr ctxt)
210 const select_ns_entry* ns = NULL;
211 const struct list* pNsList = &properties_from_xmlDocPtr(ctxt->doc)->selectNsList;
213 TRACE("(%p)\n", ctxt);
215 LIST_FOR_EACH_ENTRY( ns, pNsList, select_ns_entry, entry )
217 xmlXPathRegisterNs(ctxt, ns->prefix, ns->href);
224 static inline void clear_selectNsList(struct list* pNsList)
226 select_ns_entry *ns, *ns2;
227 LIST_FOR_EACH_ENTRY_SAFE( ns, ns2, pNsList, select_ns_entry, entry )
234 static xmldoc_priv * create_priv(void)
237 priv = heap_alloc( sizeof (*priv) );
242 list_init( &priv->orphans );
243 priv->properties = NULL;
249 static domdoc_properties * create_properties(const GUID *clsid)
251 domdoc_properties *properties = heap_alloc(sizeof(domdoc_properties));
253 list_init(&properties->selectNsList);
254 properties->preserving = VARIANT_FALSE;
255 properties->schemaCache = NULL;
256 properties->selectNsStr = heap_alloc_zero(sizeof(xmlChar));
257 properties->selectNsStr_len = 0;
259 /* properties that are dependent on object versions */
260 if (IsEqualCLSID(clsid, &CLSID_DOMDocument30))
262 properties->version = MSXML3;
263 properties->XPath = FALSE;
265 else if (IsEqualCLSID(clsid, &CLSID_DOMDocument40))
267 properties->version = MSXML4;
268 properties->XPath = TRUE;
270 else if (IsEqualCLSID(clsid, &CLSID_DOMDocument60))
272 properties->version = MSXML6;
273 properties->XPath = TRUE;
277 properties->version = MSXML_DEFAULT;
278 properties->XPath = FALSE;
284 static domdoc_properties* copy_properties(domdoc_properties const* properties)
286 domdoc_properties* pcopy = heap_alloc(sizeof(domdoc_properties));
287 select_ns_entry const* ns = NULL;
288 select_ns_entry* new_ns = NULL;
289 int len = (properties->selectNsStr_len+1)*sizeof(xmlChar);
294 pcopy->version = properties->version;
295 pcopy->preserving = properties->preserving;
296 pcopy->schemaCache = properties->schemaCache;
297 if (pcopy->schemaCache)
298 IXMLDOMSchemaCollection2_AddRef(pcopy->schemaCache);
299 pcopy->XPath = properties->XPath;
300 pcopy->selectNsStr_len = properties->selectNsStr_len;
301 list_init( &pcopy->selectNsList );
302 pcopy->selectNsStr = heap_alloc(len);
303 memcpy((xmlChar*)pcopy->selectNsStr, properties->selectNsStr, len);
304 offset = pcopy->selectNsStr - properties->selectNsStr;
306 LIST_FOR_EACH_ENTRY( ns, (&properties->selectNsList), select_ns_entry, entry )
308 new_ns = heap_alloc(sizeof(select_ns_entry));
309 memcpy(new_ns, ns, sizeof(select_ns_entry));
310 new_ns->href += offset;
311 new_ns->prefix += offset;
312 list_add_tail(&pcopy->selectNsList, &new_ns->entry);
320 static void free_properties(domdoc_properties* properties)
324 if (properties->schemaCache)
325 IXMLDOMSchemaCollection2_Release(properties->schemaCache);
326 clear_selectNsList(&properties->selectNsList);
327 heap_free((xmlChar*)properties->selectNsStr);
328 heap_free(properties);
332 static BOOL xmldoc_has_decl(xmlDocPtr doc)
334 return doc->children && (xmlStrEqual(doc->children->name, (xmlChar*)"xml") == 1);
337 /* links a "<?xml" node as a first child */
338 void xmldoc_link_xmldecl(xmlDocPtr doc, xmlNodePtr node)
341 if (doc->standalone != -1) xmlAddPrevSibling( doc->children, node );
344 /* unlinks a first "<?xml" child if it was created */
345 xmlNodePtr xmldoc_unlink_xmldecl(xmlDocPtr doc)
351 if (doc->standalone != -1)
353 node = doc->children;
354 xmlUnlinkNode( node );
362 BOOL is_preserving_whitespace(xmlNodePtr node)
364 domdoc_properties* properties = NULL;
365 /* during parsing the xmlDoc._private stuff is not there */
366 if (priv_from_xmlDocPtr(node->doc))
367 properties = properties_from_xmlDocPtr(node->doc);
368 return ((properties && properties->preserving == VARIANT_TRUE) ||
369 xmlNodeGetSpacePreserve(node) == 1);
372 static inline BOOL strn_isspace(xmlChar const* str, int len)
374 for (; str && len > 0 && *str; ++str, --len)
381 static void sax_characters(void *ctx, const xmlChar *ch, int len)
383 xmlParserCtxtPtr pctx;
386 pctx = (xmlParserCtxtPtr) ctx;
387 This = (domdoc const*) pctx->_private;
389 /* during domdoc_loadXML() the xmlDocPtr->_private data is not available */
390 if (!This->properties->preserving &&
391 !is_preserving_whitespace(pctx->node) &&
392 strn_isspace(ch, len))
395 xmlSAX2Characters(ctx, ch, len);
398 static void LIBXML2_LOG_CALLBACK sax_error(void* ctx, char const* msg, ...)
402 LIBXML2_CALLBACK_ERR(doparse, msg, ap);
406 static void LIBXML2_LOG_CALLBACK sax_warning(void* ctx, char const* msg, ...)
410 LIBXML2_CALLBACK_WARN(doparse, msg, ap);
414 static void sax_serror(void* ctx, xmlErrorPtr err)
416 LIBXML2_CALLBACK_SERROR(doparse, err);
419 static xmlDocPtr doparse(domdoc* This, char *ptr, int len, xmlChar const* encoding)
421 xmlDocPtr doc = NULL;
422 xmlParserCtxtPtr pctx;
423 static xmlSAXHandler sax_handler = {
424 xmlSAX2InternalSubset, /* internalSubset */
425 xmlSAX2IsStandalone, /* isStandalone */
426 xmlSAX2HasInternalSubset, /* hasInternalSubset */
427 xmlSAX2HasExternalSubset, /* hasExternalSubset */
428 xmlSAX2ResolveEntity, /* resolveEntity */
429 xmlSAX2GetEntity, /* getEntity */
430 xmlSAX2EntityDecl, /* entityDecl */
431 xmlSAX2NotationDecl, /* notationDecl */
432 xmlSAX2AttributeDecl, /* attributeDecl */
433 xmlSAX2ElementDecl, /* elementDecl */
434 xmlSAX2UnparsedEntityDecl, /* unparsedEntityDecl */
435 xmlSAX2SetDocumentLocator, /* setDocumentLocator */
436 xmlSAX2StartDocument, /* startDocument */
437 xmlSAX2EndDocument, /* endDocument */
438 xmlSAX2StartElement, /* startElement */
439 xmlSAX2EndElement, /* endElement */
440 xmlSAX2Reference, /* reference */
441 sax_characters, /* characters */
442 sax_characters, /* ignorableWhitespace */
443 xmlSAX2ProcessingInstruction, /* processingInstruction */
444 xmlSAX2Comment, /* comment */
445 sax_warning, /* warning */
446 sax_error, /* error */
447 sax_error, /* fatalError */
448 xmlSAX2GetParameterEntity, /* getParameterEntity */
449 xmlSAX2CDataBlock, /* cdataBlock */
450 xmlSAX2ExternalSubset, /* externalSubset */
453 xmlSAX2StartElementNs, /* startElementNs */
454 xmlSAX2EndElementNs, /* endElementNs */
455 sax_serror /* serror */
459 pctx = xmlCreateMemoryParserCtxt(ptr, len);
462 ERR("Failed to create parser context\n");
466 if (pctx->sax) xmlFree(pctx->sax);
467 pctx->sax = &sax_handler;
468 pctx->_private = This;
470 pctx->encoding = xmlStrdup(encoding);
471 xmlParseDocument(pctx);
473 if (pctx->wellFormed)
479 xmlFreeDoc(pctx->myDoc);
483 xmlFreeParserCtxt(pctx);
485 /* TODO: put this in one of the SAX callbacks */
486 /* create first child as a <?xml...?> */
487 if (doc && doc->standalone != -1)
491 xmlChar *xmlbuff = (xmlChar*)buff;
493 node = xmlNewDocPI( doc, (xmlChar*)"xml", NULL );
495 /* version attribute can't be omitted */
496 sprintf(buff, "version=\"%s\"", doc->version ? (char*)doc->version : "1.0");
497 xmlNodeAddContent( node, xmlbuff );
501 sprintf(buff, " encoding=\"%s\"", doc->encoding);
502 xmlNodeAddContent( node, xmlbuff );
505 if (doc->standalone != -2)
507 sprintf(buff, " standalone=\"%s\"", doc->standalone == 0 ? "no" : "yes");
508 xmlNodeAddContent( node, xmlbuff );
511 xmldoc_link_xmldecl( doc, node );
517 void xmldoc_init(xmlDocPtr doc, const GUID *clsid)
519 doc->_private = create_priv();
520 priv_from_xmlDocPtr(doc)->properties = create_properties(clsid);
523 LONG xmldoc_add_ref(xmlDocPtr doc)
525 LONG ref = InterlockedIncrement(&priv_from_xmlDocPtr(doc)->refs);
526 TRACE("(%p)->(%d)\n", doc, ref);
530 LONG xmldoc_release(xmlDocPtr doc)
532 xmldoc_priv *priv = priv_from_xmlDocPtr(doc);
533 LONG ref = InterlockedDecrement(&priv->refs);
534 TRACE("(%p)->(%d)\n", doc, ref);
537 orphan_entry *orphan, *orphan2;
538 TRACE("freeing docptr %p\n", doc);
540 LIST_FOR_EACH_ENTRY_SAFE( orphan, orphan2, &priv->orphans, orphan_entry, entry )
542 xmlFreeNode( orphan->node );
545 free_properties(priv->properties);
546 heap_free(doc->_private);
554 HRESULT xmldoc_add_orphan(xmlDocPtr doc, xmlNodePtr node)
556 xmldoc_priv *priv = priv_from_xmlDocPtr(doc);
559 entry = heap_alloc( sizeof (*entry) );
561 return E_OUTOFMEMORY;
564 list_add_head( &priv->orphans, &entry->entry );
568 HRESULT xmldoc_remove_orphan(xmlDocPtr doc, xmlNodePtr node)
570 xmldoc_priv *priv = priv_from_xmlDocPtr(doc);
571 orphan_entry *entry, *entry2;
573 LIST_FOR_EACH_ENTRY_SAFE( entry, entry2, &priv->orphans, orphan_entry, entry )
575 if( entry->node == node )
577 list_remove( &entry->entry );
586 static inline xmlDocPtr get_doc( domdoc *This )
588 return (xmlDocPtr)This->node.node;
591 static HRESULT attach_xmldoc(domdoc *This, xmlDocPtr xml )
595 priv_from_xmlDocPtr(get_doc(This))->properties = NULL;
596 if (xmldoc_release(get_doc(This)) != 0)
597 priv_from_xmlDocPtr(get_doc(This))->properties =
598 copy_properties(This->properties);
601 This->node.node = (xmlNodePtr) xml;
605 xmldoc_add_ref(get_doc(This));
606 priv_from_xmlDocPtr(get_doc(This))->properties = This->properties;
612 static inline domdoc *impl_from_IXMLDOMDocument3( IXMLDOMDocument3 *iface )
614 return (domdoc *)((char*)iface - FIELD_OFFSET(domdoc, lpVtbl));
617 static inline domdoc *impl_from_IPersistStreamInit(IPersistStreamInit *iface)
619 return (domdoc *)((char*)iface - FIELD_OFFSET(domdoc, lpvtblIPersistStreamInit));
622 static inline domdoc *impl_from_IObjectWithSite(IObjectWithSite *iface)
624 return (domdoc *)((char*)iface - FIELD_OFFSET(domdoc, lpvtblIObjectWithSite));
627 static inline domdoc *impl_from_IObjectSafety(IObjectSafety *iface)
629 return (domdoc *)((char*)iface - FIELD_OFFSET(domdoc, lpvtblIObjectSafety));
632 static inline domdoc *impl_from_ISupportErrorInfo(ISupportErrorInfo *iface)
634 return (domdoc *)((char*)iface - FIELD_OFFSET(domdoc, lpvtblISupportErrorInfo));
637 static inline domdoc *impl_from_IConnectionPointContainer(IConnectionPointContainer *iface)
639 return (domdoc *)((char*)iface - FIELD_OFFSET(domdoc, lpVtblConnectionPointContainer));
642 /************************************************************************
643 * domdoc implementation of IPersistStream.
645 static HRESULT WINAPI domdoc_IPersistStreamInit_QueryInterface(
646 IPersistStreamInit *iface, REFIID riid, void **ppvObj)
648 domdoc* This = impl_from_IPersistStreamInit(iface);
649 return IXMLDOMDocument3_QueryInterface((IXMLDOMDocument3*)&This->lpVtbl, riid, ppvObj);
652 static ULONG WINAPI domdoc_IPersistStreamInit_AddRef(
653 IPersistStreamInit *iface)
655 domdoc* This = impl_from_IPersistStreamInit(iface);
656 return IXMLDOMDocument3_AddRef((IXMLDOMDocument3*)&This->lpVtbl);
659 static ULONG WINAPI domdoc_IPersistStreamInit_Release(
660 IPersistStreamInit *iface)
662 domdoc* This = impl_from_IPersistStreamInit(iface);
663 return IXMLDOMDocument3_Release((IXMLDOMDocument3*)&This->lpVtbl);
666 static HRESULT WINAPI domdoc_IPersistStreamInit_GetClassID(
667 IPersistStreamInit *iface, CLSID *classid)
669 domdoc* This = impl_from_IPersistStreamInit(iface);
670 TRACE("(%p)->(%p)\n", This, classid);
675 *classid = *DOMDocument_version(This->properties->version);
680 static HRESULT WINAPI domdoc_IPersistStreamInit_IsDirty(
681 IPersistStreamInit *iface)
683 domdoc *This = impl_from_IPersistStreamInit(iface);
684 FIXME("(%p): stub!\n", This);
688 static HRESULT WINAPI domdoc_IPersistStreamInit_Load(
689 IPersistStreamInit *iface, LPSTREAM pStm)
691 domdoc *This = impl_from_IPersistStreamInit(iface);
694 DWORD read, written, len;
697 xmlDocPtr xmldoc = NULL;
699 TRACE("(%p)->(%p)\n", This, pStm);
704 hr = CreateStreamOnHGlobal(NULL, TRUE, &This->stream);
710 IStream_Read(pStm, buf, sizeof(buf), &read);
711 hr = IStream_Write(This->stream, buf, read, &written);
712 } while(SUCCEEDED(hr) && written != 0 && read != 0);
716 ERR("Failed to copy stream\n");
720 hr = GetHGlobalFromStream(This->stream, &hglobal);
724 len = GlobalSize(hglobal);
725 ptr = GlobalLock(hglobal);
727 xmldoc = doparse(This, ptr, len, NULL);
728 GlobalUnlock(hglobal);
732 ERR("Failed to parse xml\n");
736 xmldoc->_private = create_priv();
738 return attach_xmldoc(This, xmldoc);
741 static HRESULT WINAPI domdoc_IPersistStreamInit_Save(
742 IPersistStreamInit *iface, IStream *stream, BOOL clr_dirty)
744 domdoc *This = impl_from_IPersistStreamInit(iface);
748 TRACE("(%p)->(%p %d)\n", This, stream, clr_dirty);
750 hr = IXMLDOMDocument3_get_xml( (IXMLDOMDocument3*)&This->lpVtbl, &xmlString );
753 DWORD len = SysStringLen(xmlString) * sizeof(WCHAR);
755 hr = IStream_Write( stream, xmlString, len, NULL );
756 SysFreeString(xmlString);
759 TRACE("ret 0x%08x\n", hr);
764 static HRESULT WINAPI domdoc_IPersistStreamInit_GetSizeMax(
765 IPersistStreamInit *iface, ULARGE_INTEGER *pcbSize)
767 domdoc *This = impl_from_IPersistStreamInit(iface);
768 TRACE("(%p)->(%p): stub!\n", This, pcbSize);
772 static HRESULT WINAPI domdoc_IPersistStreamInit_InitNew(
773 IPersistStreamInit *iface)
775 domdoc *This = impl_from_IPersistStreamInit(iface);
776 TRACE("(%p)\n", This);
780 static const IPersistStreamInitVtbl xmldoc_IPersistStreamInit_VTable =
782 domdoc_IPersistStreamInit_QueryInterface,
783 domdoc_IPersistStreamInit_AddRef,
784 domdoc_IPersistStreamInit_Release,
785 domdoc_IPersistStreamInit_GetClassID,
786 domdoc_IPersistStreamInit_IsDirty,
787 domdoc_IPersistStreamInit_Load,
788 domdoc_IPersistStreamInit_Save,
789 domdoc_IPersistStreamInit_GetSizeMax,
790 domdoc_IPersistStreamInit_InitNew
793 /* ISupportErrorInfo interface */
794 static HRESULT WINAPI support_error_QueryInterface(
795 ISupportErrorInfo *iface,
796 REFIID riid, void** ppvObj )
798 domdoc *This = impl_from_ISupportErrorInfo(iface);
799 return IXMLDOMDocument3_QueryInterface((IXMLDOMDocument3 *)This, riid, ppvObj);
802 static ULONG WINAPI support_error_AddRef(
803 ISupportErrorInfo *iface )
805 domdoc *This = impl_from_ISupportErrorInfo(iface);
806 return IXMLDOMDocument3_AddRef((IXMLDOMDocument3 *)This);
809 static ULONG WINAPI support_error_Release(
810 ISupportErrorInfo *iface )
812 domdoc *This = impl_from_ISupportErrorInfo(iface);
813 return IXMLDOMDocument3_Release((IXMLDOMDocument3 *)This);
816 static HRESULT WINAPI support_error_InterfaceSupportsErrorInfo(
817 ISupportErrorInfo *iface,
820 FIXME("(%p)->(%s)\n", iface, debugstr_guid(riid));
824 static const struct ISupportErrorInfoVtbl support_error_vtbl =
826 support_error_QueryInterface,
827 support_error_AddRef,
828 support_error_Release,
829 support_error_InterfaceSupportsErrorInfo
832 /* IXMLDOMDocument2 interface */
833 static HRESULT WINAPI domdoc_QueryInterface( IXMLDOMDocument3 *iface, REFIID riid, void** ppvObject )
835 domdoc *This = impl_from_IXMLDOMDocument3( iface );
837 TRACE("(%p)->(%s %p)\n", This, debugstr_guid( riid ), ppvObject );
841 if ( IsEqualGUID( riid, &IID_IUnknown ) ||
842 IsEqualGUID( riid, &IID_IDispatch ) ||
843 IsEqualGUID( riid, &IID_IXMLDOMNode ) ||
844 IsEqualGUID( riid, &IID_IXMLDOMDocument ) ||
845 IsEqualGUID( riid, &IID_IXMLDOMDocument2 )||
846 IsEqualGUID( riid, &IID_IXMLDOMDocument3 ))
850 else if (IsEqualGUID(&IID_IPersistStream, riid) ||
851 IsEqualGUID(&IID_IPersistStreamInit, riid))
853 *ppvObject = &(This->lpvtblIPersistStreamInit);
855 else if (IsEqualGUID(&IID_IObjectWithSite, riid))
857 *ppvObject = &(This->lpvtblIObjectWithSite);
859 else if (IsEqualGUID(&IID_IObjectSafety, riid))
861 *ppvObject = &(This->lpvtblIObjectSafety);
863 else if( IsEqualGUID( riid, &IID_ISupportErrorInfo ))
865 *ppvObject = &This->lpvtblISupportErrorInfo;
867 else if(node_query_interface(&This->node, riid, ppvObject))
869 return *ppvObject ? S_OK : E_NOINTERFACE;
871 else if (IsEqualGUID( riid, &IID_IConnectionPointContainer ))
873 *ppvObject = &This->lpVtblConnectionPointContainer;
875 else if(IsEqualGUID(&IID_IRunnableObject, riid))
877 TRACE("IID_IRunnableObject not supported returning NULL\n");
878 return E_NOINTERFACE;
882 FIXME("interface %s not implemented\n", debugstr_guid(riid));
883 return E_NOINTERFACE;
886 IUnknown_AddRef((IUnknown*)*ppvObject);
892 static ULONG WINAPI domdoc_AddRef(
893 IXMLDOMDocument3 *iface )
895 domdoc *This = impl_from_IXMLDOMDocument3( iface );
896 ULONG ref = InterlockedIncrement( &This->ref );
897 TRACE("(%p)->(%d)\n", This, ref );
902 static ULONG WINAPI domdoc_Release(
903 IXMLDOMDocument3 *iface )
905 domdoc *This = impl_from_IXMLDOMDocument3( iface );
906 LONG ref = InterlockedDecrement( &This->ref );
908 TRACE("(%p)->(%d)\n", This, ref );
913 detach_bsc(This->bsc);
916 IUnknown_Release( This->site );
917 destroy_xmlnode(&This->node);
919 IStream_Release(This->stream);
926 static HRESULT WINAPI domdoc_GetTypeInfoCount( IXMLDOMDocument3 *iface, UINT* pctinfo )
928 domdoc *This = impl_from_IXMLDOMDocument3( iface );
930 TRACE("(%p)->(%p)\n", This, pctinfo);
937 static HRESULT WINAPI domdoc_GetTypeInfo(
938 IXMLDOMDocument3 *iface,
939 UINT iTInfo, LCID lcid, ITypeInfo** ppTInfo )
941 domdoc *This = impl_from_IXMLDOMDocument3( iface );
944 TRACE("(%p)->(%u %u %p)\n", This, iTInfo, lcid, ppTInfo);
946 hr = get_typeinfo(IXMLDOMDocument2_tid, ppTInfo);
951 static HRESULT WINAPI domdoc_GetIDsOfNames(
952 IXMLDOMDocument3 *iface,
959 domdoc *This = impl_from_IXMLDOMDocument3( iface );
963 TRACE("(%p)->(%s %p %u %u %p)\n", This, debugstr_guid(riid), rgszNames, cNames,
966 if(!rgszNames || cNames == 0 || !rgDispId)
969 hr = get_typeinfo(IXMLDOMDocument2_tid, &typeinfo);
972 hr = ITypeInfo_GetIDsOfNames(typeinfo, rgszNames, cNames, rgDispId);
973 ITypeInfo_Release(typeinfo);
980 static HRESULT WINAPI domdoc_Invoke(
981 IXMLDOMDocument3 *iface,
986 DISPPARAMS* pDispParams,
988 EXCEPINFO* pExcepInfo,
991 domdoc *This = impl_from_IXMLDOMDocument3( iface );
995 TRACE("(%p)->(%d %s %d %d %p %p %p %p)\n", This, dispIdMember, debugstr_guid(riid),
996 lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
998 hr = get_typeinfo(IXMLDOMDocument2_tid, &typeinfo);
1001 hr = ITypeInfo_Invoke(typeinfo, &(This->lpVtbl), dispIdMember, wFlags, pDispParams,
1002 pVarResult, pExcepInfo, puArgErr);
1003 ITypeInfo_Release(typeinfo);
1010 static HRESULT WINAPI domdoc_get_nodeName(
1011 IXMLDOMDocument3 *iface,
1014 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1016 static const WCHAR documentW[] = {'#','d','o','c','u','m','e','n','t',0};
1018 TRACE("(%p)->(%p)\n", This, name);
1020 return return_bstr(documentW, name);
1024 static HRESULT WINAPI domdoc_get_nodeValue(
1025 IXMLDOMDocument3 *iface,
1028 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1030 TRACE("(%p)->(%p)\n", This, value);
1033 return E_INVALIDARG;
1035 V_VT(value) = VT_NULL;
1036 V_BSTR(value) = NULL; /* tests show that we should do this */
1041 static HRESULT WINAPI domdoc_put_nodeValue(
1042 IXMLDOMDocument3 *iface,
1045 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1046 TRACE("(%p)->(v%d)\n", This, V_VT(&value));
1051 static HRESULT WINAPI domdoc_get_nodeType(
1052 IXMLDOMDocument3 *iface,
1055 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1057 TRACE("(%p)->(%p)\n", This, type);
1059 *type = NODE_DOCUMENT;
1064 static HRESULT WINAPI domdoc_get_parentNode(
1065 IXMLDOMDocument3 *iface,
1066 IXMLDOMNode** parent )
1068 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1070 TRACE("(%p)->(%p)\n", This, parent);
1072 return node_get_parent(&This->node, parent);
1076 static HRESULT WINAPI domdoc_get_childNodes(
1077 IXMLDOMDocument3 *iface,
1078 IXMLDOMNodeList** childList )
1080 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1082 TRACE("(%p)->(%p)\n", This, childList);
1084 return node_get_child_nodes(&This->node, childList);
1088 static HRESULT WINAPI domdoc_get_firstChild(
1089 IXMLDOMDocument3 *iface,
1090 IXMLDOMNode** firstChild )
1092 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1094 TRACE("(%p)->(%p)\n", This, firstChild);
1096 return node_get_first_child(&This->node, firstChild);
1100 static HRESULT WINAPI domdoc_get_lastChild(
1101 IXMLDOMDocument3 *iface,
1102 IXMLDOMNode** lastChild )
1104 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1106 TRACE("(%p)->(%p)\n", This, lastChild);
1108 return node_get_last_child(&This->node, lastChild);
1112 static HRESULT WINAPI domdoc_get_previousSibling(
1113 IXMLDOMDocument3 *iface,
1114 IXMLDOMNode** previousSibling )
1116 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1118 TRACE("(%p)->(%p)\n", This, previousSibling);
1120 return return_null_node(previousSibling);
1124 static HRESULT WINAPI domdoc_get_nextSibling(
1125 IXMLDOMDocument3 *iface,
1126 IXMLDOMNode** nextSibling )
1128 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1130 TRACE("(%p)->(%p)\n", This, nextSibling);
1132 return return_null_node(nextSibling);
1136 static HRESULT WINAPI domdoc_get_attributes(
1137 IXMLDOMDocument3 *iface,
1138 IXMLDOMNamedNodeMap** attributeMap )
1140 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1142 TRACE("(%p)->(%p)\n", This, attributeMap);
1144 return return_null_ptr((void**)attributeMap);
1148 static HRESULT WINAPI domdoc_insertBefore(
1149 IXMLDOMDocument3 *iface,
1150 IXMLDOMNode* newChild,
1152 IXMLDOMNode** outNewChild )
1154 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1156 TRACE("(%p)->(%p x%d %p)\n", This, newChild, V_VT(&refChild), outNewChild);
1158 return node_insert_before(&This->node, newChild, &refChild, outNewChild);
1162 static HRESULT WINAPI domdoc_replaceChild(
1163 IXMLDOMDocument3 *iface,
1164 IXMLDOMNode* newChild,
1165 IXMLDOMNode* oldChild,
1166 IXMLDOMNode** outOldChild)
1168 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1170 TRACE("(%p)->(%p %p %p)\n", This, newChild, oldChild, outOldChild);
1172 return node_replace_child(&This->node, newChild, oldChild, outOldChild);
1176 static HRESULT WINAPI domdoc_removeChild(
1177 IXMLDOMDocument3 *iface,
1178 IXMLDOMNode* childNode,
1179 IXMLDOMNode** oldChild)
1181 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1182 return IXMLDOMNode_removeChild( IXMLDOMNode_from_impl(&This->node), childNode, oldChild );
1186 static HRESULT WINAPI domdoc_appendChild(
1187 IXMLDOMDocument3 *iface,
1188 IXMLDOMNode* newChild,
1189 IXMLDOMNode** outNewChild)
1191 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1192 return IXMLDOMNode_appendChild( IXMLDOMNode_from_impl(&This->node), newChild, outNewChild );
1196 static HRESULT WINAPI domdoc_hasChildNodes(
1197 IXMLDOMDocument3 *iface,
1198 VARIANT_BOOL* hasChild)
1200 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1201 return IXMLDOMNode_hasChildNodes( IXMLDOMNode_from_impl(&This->node), hasChild );
1205 static HRESULT WINAPI domdoc_get_ownerDocument(
1206 IXMLDOMDocument3 *iface,
1207 IXMLDOMDocument** DOMDocument)
1209 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1210 return IXMLDOMNode_get_ownerDocument( IXMLDOMNode_from_impl(&This->node), DOMDocument );
1214 static HRESULT WINAPI domdoc_cloneNode(
1215 IXMLDOMDocument3 *iface,
1217 IXMLDOMNode** outNode)
1219 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1220 TRACE("(%p)->(%d %p)\n", This, deep, outNode);
1221 return node_clone( &This->node, deep, outNode );
1225 static HRESULT WINAPI domdoc_get_nodeTypeString(
1226 IXMLDOMDocument3 *iface,
1229 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1230 static const WCHAR documentW[] = {'d','o','c','u','m','e','n','t',0};
1232 TRACE("(%p)->(%p)\n", This, p);
1234 return return_bstr(documentW, p);
1238 static HRESULT WINAPI domdoc_get_text(
1239 IXMLDOMDocument3 *iface,
1242 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1243 return IXMLDOMNode_get_text( IXMLDOMNode_from_impl(&This->node), text );
1247 static HRESULT WINAPI domdoc_put_text(
1248 IXMLDOMDocument3 *iface,
1251 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1252 TRACE("(%p)->(%s)\n", This, debugstr_w(text));
1257 static HRESULT WINAPI domdoc_get_specified(
1258 IXMLDOMDocument3 *iface,
1259 VARIANT_BOOL* isSpecified )
1261 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1262 FIXME("(%p)->(%p) stub!\n", This, isSpecified);
1263 *isSpecified = VARIANT_TRUE;
1268 static HRESULT WINAPI domdoc_get_definition(
1269 IXMLDOMDocument3 *iface,
1270 IXMLDOMNode** definitionNode )
1272 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1273 FIXME("(%p)->(%p)\n", This, definitionNode);
1278 static HRESULT WINAPI domdoc_get_nodeTypedValue(
1279 IXMLDOMDocument3 *iface,
1280 VARIANT* typedValue )
1282 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1283 return IXMLDOMNode_get_nodeTypedValue( IXMLDOMNode_from_impl(&This->node), typedValue );
1286 static HRESULT WINAPI domdoc_put_nodeTypedValue(
1287 IXMLDOMDocument3 *iface,
1288 VARIANT typedValue )
1290 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1291 FIXME("(%p)->(%s)\n", This, debugstr_variant(&typedValue));
1296 static HRESULT WINAPI domdoc_get_dataType(
1297 IXMLDOMDocument3 *iface,
1300 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1301 TRACE("(%p)->(%p)\n", This, typename);
1302 return return_null_var( typename );
1306 static HRESULT WINAPI domdoc_put_dataType(
1307 IXMLDOMDocument3 *iface,
1310 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1312 FIXME("(%p)->(%s)\n", This, debugstr_w(dataTypeName));
1315 return E_INVALIDARG;
1320 static int XMLCALL domdoc_get_xml_writecallback(void *ctx, const char *data, int len)
1322 return xmlBufferAdd((xmlBufferPtr)ctx, (xmlChar*)data, len) == 0 ? len : 0;
1325 static HRESULT WINAPI domdoc_get_xml(
1326 IXMLDOMDocument3 *iface,
1329 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1330 xmlSaveCtxtPtr ctxt;
1335 TRACE("(%p)->(%p)\n", This, p);
1338 return E_INVALIDARG;
1342 buf = xmlBufferCreate();
1344 return E_OUTOFMEMORY;
1346 options = xmldoc_has_decl(get_doc(This)) ? XML_SAVE_NO_DECL : 0;
1347 options |= XML_SAVE_FORMAT;
1348 ctxt = xmlSaveToIO(domdoc_get_xml_writecallback, NULL, buf, "UTF-8", options);
1353 return E_OUTOFMEMORY;
1356 ret = xmlSaveDoc(ctxt, get_doc(This));
1357 /* flushes on close */
1360 TRACE("%ld, len=%d\n", ret, xmlBufferLength(buf));
1361 if(ret != -1 && xmlBufferLength(buf) > 0)
1365 content = bstr_from_xmlChar(xmlBufferContent(buf));
1366 content = EnsureCorrectEOL(content);
1372 *p = SysAllocStringLen(NULL, 0);
1377 return *p ? S_OK : E_OUTOFMEMORY;
1381 static HRESULT WINAPI domdoc_transformNode(
1382 IXMLDOMDocument3 *iface,
1383 IXMLDOMNode* styleSheet,
1386 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1387 return IXMLDOMNode_transformNode( IXMLDOMNode_from_impl(&This->node), styleSheet, xmlString );
1391 static HRESULT WINAPI domdoc_selectNodes(
1392 IXMLDOMDocument3 *iface,
1394 IXMLDOMNodeList** resultList )
1396 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1397 return IXMLDOMNode_selectNodes( IXMLDOMNode_from_impl(&This->node), queryString, resultList );
1401 static HRESULT WINAPI domdoc_selectSingleNode(
1402 IXMLDOMDocument3 *iface,
1404 IXMLDOMNode** resultNode )
1406 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1407 return IXMLDOMNode_selectSingleNode( IXMLDOMNode_from_impl(&This->node), queryString, resultNode );
1411 static HRESULT WINAPI domdoc_get_parsed(
1412 IXMLDOMDocument3 *iface,
1413 VARIANT_BOOL* isParsed )
1415 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1416 FIXME("(%p)->(%p) stub!\n", This, isParsed);
1417 *isParsed = VARIANT_TRUE;
1422 static HRESULT WINAPI domdoc_get_namespaceURI(
1423 IXMLDOMDocument3 *iface,
1424 BSTR* namespaceURI )
1426 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1427 return IXMLDOMNode_get_namespaceURI( IXMLDOMNode_from_impl(&This->node), namespaceURI );
1431 static HRESULT WINAPI domdoc_get_prefix(
1432 IXMLDOMDocument3 *iface,
1435 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1436 TRACE("(%p)->(%p)\n", This, prefix);
1437 return return_null_bstr( prefix );
1441 static HRESULT WINAPI domdoc_get_baseName(
1442 IXMLDOMDocument3 *iface,
1445 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1446 TRACE("(%p)->(%p)\n", This, name);
1447 return return_null_bstr( name );
1451 static HRESULT WINAPI domdoc_transformNodeToObject(
1452 IXMLDOMDocument3 *iface,
1453 IXMLDOMNode* stylesheet,
1454 VARIANT outputObject)
1456 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1457 return IXMLDOMNode_transformNodeToObject( IXMLDOMNode_from_impl(&This->node), stylesheet, outputObject );
1461 static HRESULT WINAPI domdoc_get_doctype(
1462 IXMLDOMDocument3 *iface,
1463 IXMLDOMDocumentType** documentType )
1465 domdoc *This = impl_from_IXMLDOMDocument3(iface);
1466 FIXME("(%p)\n", This);
1471 static HRESULT WINAPI domdoc_get_implementation(
1472 IXMLDOMDocument3 *iface,
1473 IXMLDOMImplementation** impl )
1475 domdoc *This = impl_from_IXMLDOMDocument3(iface);
1477 TRACE("(%p)->(%p)\n", This, impl);
1480 return E_INVALIDARG;
1482 *impl = (IXMLDOMImplementation*)create_doc_Implementation();
1487 static HRESULT WINAPI domdoc_get_documentElement(
1488 IXMLDOMDocument3 *iface,
1489 IXMLDOMElement** DOMElement )
1491 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1492 IXMLDOMNode *element_node;
1496 TRACE("(%p)->(%p)\n", This, DOMElement);
1499 return E_INVALIDARG;
1503 root = xmlDocGetRootElement( get_doc(This) );
1507 element_node = create_node( root );
1508 if(!element_node) return S_FALSE;
1510 hr = IXMLDOMNode_QueryInterface(element_node, &IID_IXMLDOMElement, (void**)DOMElement);
1511 IXMLDOMNode_Release(element_node);
1517 static HRESULT WINAPI domdoc_put_documentElement(
1518 IXMLDOMDocument3 *iface,
1519 IXMLDOMElement* DOMElement )
1521 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1522 IXMLDOMNode *elementNode;
1527 TRACE("(%p)->(%p)\n", This, DOMElement);
1529 hr = IXMLDOMElement_QueryInterface( DOMElement, &IID_IXMLDOMNode, (void**)&elementNode );
1533 xmlNode = get_node_obj( elementNode );
1535 FIXME("elementNode is not our object\n");
1539 if(!xmlNode->node->parent)
1540 if(xmldoc_remove_orphan(xmlNode->node->doc, xmlNode->node) != S_OK)
1541 WARN("%p is not an orphan of %p\n", xmlNode->node->doc, xmlNode->node);
1543 oldRoot = xmlDocSetRootElement( get_doc(This), xmlNode->node);
1544 IXMLDOMNode_Release( elementNode );
1547 xmldoc_add_orphan(oldRoot->doc, oldRoot);
1553 static HRESULT WINAPI domdoc_createElement(
1554 IXMLDOMDocument3 *iface,
1556 IXMLDOMElement** element )
1558 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1563 TRACE("(%p)->(%s %p)\n", This, debugstr_w(tagname), element);
1565 if (!element || !tagname) return E_INVALIDARG;
1567 V_VT(&type) = VT_I1;
1568 V_I1(&type) = NODE_ELEMENT;
1570 hr = IXMLDOMDocument3_createNode(iface, type, tagname, NULL, &node);
1573 IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMElement, (void**)element);
1574 IXMLDOMNode_Release(node);
1581 static HRESULT WINAPI domdoc_createDocumentFragment(
1582 IXMLDOMDocument3 *iface,
1583 IXMLDOMDocumentFragment** frag )
1585 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1590 TRACE("(%p)->(%p)\n", This, frag);
1592 if (!frag) return E_INVALIDARG;
1596 V_VT(&type) = VT_I1;
1597 V_I1(&type) = NODE_DOCUMENT_FRAGMENT;
1599 hr = IXMLDOMDocument3_createNode(iface, type, NULL, NULL, &node);
1602 IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMDocumentFragment, (void**)frag);
1603 IXMLDOMNode_Release(node);
1610 static HRESULT WINAPI domdoc_createTextNode(
1611 IXMLDOMDocument3 *iface,
1613 IXMLDOMText** text )
1615 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1620 TRACE("(%p)->(%s %p)\n", This, debugstr_w(data), text);
1622 if (!text) return E_INVALIDARG;
1626 V_VT(&type) = VT_I1;
1627 V_I1(&type) = NODE_TEXT;
1629 hr = IXMLDOMDocument3_createNode(iface, type, NULL, NULL, &node);
1632 IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMText, (void**)text);
1633 IXMLDOMNode_Release(node);
1634 hr = IXMLDOMText_put_data(*text, data);
1641 static HRESULT WINAPI domdoc_createComment(
1642 IXMLDOMDocument3 *iface,
1644 IXMLDOMComment** comment )
1646 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1651 TRACE("(%p)->(%s %p)\n", This, debugstr_w(data), comment);
1653 if (!comment) return E_INVALIDARG;
1657 V_VT(&type) = VT_I1;
1658 V_I1(&type) = NODE_COMMENT;
1660 hr = IXMLDOMDocument3_createNode(iface, type, NULL, NULL, &node);
1663 IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMComment, (void**)comment);
1664 IXMLDOMNode_Release(node);
1665 hr = IXMLDOMComment_put_data(*comment, data);
1672 static HRESULT WINAPI domdoc_createCDATASection(
1673 IXMLDOMDocument3 *iface,
1675 IXMLDOMCDATASection** cdata )
1677 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1682 TRACE("(%p)->(%s %p)\n", This, debugstr_w(data), cdata);
1684 if (!cdata) return E_INVALIDARG;
1688 V_VT(&type) = VT_I1;
1689 V_I1(&type) = NODE_CDATA_SECTION;
1691 hr = IXMLDOMDocument3_createNode(iface, type, NULL, NULL, &node);
1694 IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMCDATASection, (void**)cdata);
1695 IXMLDOMNode_Release(node);
1696 hr = IXMLDOMCDATASection_put_data(*cdata, data);
1703 static HRESULT WINAPI domdoc_createProcessingInstruction(
1704 IXMLDOMDocument3 *iface,
1707 IXMLDOMProcessingInstruction** pi )
1709 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1714 TRACE("(%p)->(%s %s %p)\n", This, debugstr_w(target), debugstr_w(data), pi);
1716 if (!pi) return E_INVALIDARG;
1720 V_VT(&type) = VT_I1;
1721 V_I1(&type) = NODE_PROCESSING_INSTRUCTION;
1723 hr = IXMLDOMDocument3_createNode(iface, type, target, NULL, &node);
1728 /* this is to bypass check in ::put_data() that blocks "<?xml" PIs */
1729 node_obj = get_node_obj(node);
1730 hr = node_set_content(node_obj, data);
1732 IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMProcessingInstruction, (void**)pi);
1733 IXMLDOMNode_Release(node);
1740 static HRESULT WINAPI domdoc_createAttribute(
1741 IXMLDOMDocument3 *iface,
1743 IXMLDOMAttribute** attribute )
1745 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1750 TRACE("(%p)->(%s %p)\n", This, debugstr_w(name), attribute);
1752 if (!attribute || !name) return E_INVALIDARG;
1754 V_VT(&type) = VT_I1;
1755 V_I1(&type) = NODE_ATTRIBUTE;
1757 hr = IXMLDOMDocument3_createNode(iface, type, name, NULL, &node);
1760 IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMAttribute, (void**)attribute);
1761 IXMLDOMNode_Release(node);
1768 static HRESULT WINAPI domdoc_createEntityReference(
1769 IXMLDOMDocument3 *iface,
1771 IXMLDOMEntityReference** entityref )
1773 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1778 TRACE("(%p)->(%s %p)\n", This, debugstr_w(name), entityref);
1780 if (!entityref) return E_INVALIDARG;
1784 V_VT(&type) = VT_I1;
1785 V_I1(&type) = NODE_ENTITY_REFERENCE;
1787 hr = IXMLDOMDocument3_createNode(iface, type, name, NULL, &node);
1790 IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMEntityReference, (void**)entityref);
1791 IXMLDOMNode_Release(node);
1797 xmlChar* tagName_to_XPath(const BSTR tagName)
1799 xmlChar *query, *tmp;
1800 static const xmlChar mod_pre[] = "*[local-name()='";
1801 static const xmlChar mod_post[] = "']";
1802 static const xmlChar prefix[] = "descendant::";
1803 const WCHAR *tokBegin, *tokEnd;
1806 query = xmlStrdup(prefix);
1809 while (tokBegin && *tokBegin)
1814 query = xmlStrcat(query, BAD_CAST "/");
1818 query = xmlStrcat(query, BAD_CAST "*");
1822 query = xmlStrcat(query, mod_pre);
1824 while (*tokEnd && *tokEnd != '/')
1826 len = WideCharToMultiByte(CP_UTF8, 0, tokBegin, tokEnd-tokBegin, NULL, 0, NULL, NULL);
1827 tmp = xmlMalloc(len);
1828 WideCharToMultiByte(CP_UTF8, 0, tokBegin, tokEnd-tokBegin, (char*)tmp, len, NULL, NULL);
1829 query = xmlStrncat(query, tmp, len);
1832 query = xmlStrcat(query, mod_post);
1839 static HRESULT WINAPI domdoc_getElementsByTagName(
1840 IXMLDOMDocument3 *iface,
1842 IXMLDOMNodeList** resultList )
1844 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1849 TRACE("(%p)->(%s, %p)\n", This, debugstr_w(tagName), resultList);
1851 if (!tagName || !resultList) return E_INVALIDARG;
1853 XPath = This->properties->XPath;
1854 This->properties->XPath = TRUE;
1855 query = tagName_to_XPath(tagName);
1856 hr = queryresult_create((xmlNodePtr)get_doc(This), query, resultList);
1858 This->properties->XPath = XPath;
1863 static HRESULT get_node_type(VARIANT Type, DOMNodeType * type)
1869 hr = VariantChangeType(&tmp, &Type, 0, VT_I4);
1871 return E_INVALIDARG;
1878 static HRESULT WINAPI domdoc_createNode(
1879 IXMLDOMDocument3 *iface,
1883 IXMLDOMNode** node )
1885 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1886 DOMNodeType node_type;
1888 xmlChar *xml_name, *href;
1891 TRACE("(%p)->(%s %s %p)\n", This, debugstr_w(name), debugstr_w(namespaceURI), node);
1893 if(!node) return E_INVALIDARG;
1895 hr = get_node_type(Type, &node_type);
1896 if(FAILED(hr)) return hr;
1898 if(namespaceURI && namespaceURI[0] && node_type != NODE_ELEMENT)
1899 FIXME("nodes with namespaces currently not supported.\n");
1901 TRACE("node_type %d\n", node_type);
1903 /* exit earlier for types that need name */
1907 case NODE_ATTRIBUTE:
1908 case NODE_ENTITY_REFERENCE:
1909 case NODE_PROCESSING_INSTRUCTION:
1910 if (!name || *name == 0) return E_FAIL;
1915 xml_name = xmlChar_from_wchar(name);
1916 /* prevent empty href to be allocated */
1917 href = namespaceURI ? xmlChar_from_wchar(namespaceURI) : NULL;
1923 xmlChar *local, *prefix;
1925 local = xmlSplitQName2(xml_name, &prefix);
1927 xmlnode = xmlNewDocNode(get_doc(This), NULL, local ? local : xml_name, NULL);
1929 /* allow to create default namespace xmlns= */
1930 if (local || (href && *href))
1932 xmlNsPtr ns = xmlNewNs(xmlnode, href, prefix);
1933 xmlSetNs(xmlnode, ns);
1941 case NODE_ATTRIBUTE:
1942 xmlnode = (xmlNodePtr)xmlNewDocProp(get_doc(This), xml_name, NULL);
1945 xmlnode = (xmlNodePtr)xmlNewDocText(get_doc(This), NULL);
1947 case NODE_CDATA_SECTION:
1948 xmlnode = xmlNewCDataBlock(get_doc(This), NULL, 0);
1950 case NODE_ENTITY_REFERENCE:
1951 xmlnode = xmlNewReference(get_doc(This), xml_name);
1953 case NODE_PROCESSING_INSTRUCTION:
1954 #ifdef HAVE_XMLNEWDOCPI
1955 xmlnode = xmlNewDocPI(get_doc(This), xml_name, NULL);
1957 FIXME("xmlNewDocPI() not supported, use libxml2 2.6.15 or greater\n");
1962 xmlnode = xmlNewDocComment(get_doc(This), NULL);
1964 case NODE_DOCUMENT_FRAGMENT:
1965 xmlnode = xmlNewDocFragment(get_doc(This));
1967 /* unsupported types */
1969 case NODE_DOCUMENT_TYPE:
1972 heap_free(xml_name);
1973 return E_INVALIDARG;
1975 FIXME("unhandled node type %d\n", node_type);
1980 *node = create_node(xmlnode);
1981 heap_free(xml_name);
1986 TRACE("created node (%d, %p, %p)\n", node_type, *node, xmlnode);
1987 xmldoc_add_orphan(xmlnode->doc, xmlnode);
1994 static HRESULT WINAPI domdoc_nodeFromID(
1995 IXMLDOMDocument3 *iface,
1997 IXMLDOMNode** node )
1999 domdoc *This = impl_from_IXMLDOMDocument3(iface);
2000 FIXME("(%p)->(%s %p)\n", This, debugstr_w(idString), node);
2004 static HRESULT domdoc_onDataAvailable(void *obj, char *ptr, DWORD len)
2009 xmldoc = doparse(This, ptr, len, NULL);
2011 xmldoc->_private = create_priv();
2012 return attach_xmldoc(This, xmldoc);
2018 static HRESULT doread( domdoc *This, LPWSTR filename )
2023 hr = bind_url(filename, domdoc_onDataAvailable, This, &bsc);
2028 detach_bsc(This->bsc);
2034 static HRESULT WINAPI domdoc_load(
2035 IXMLDOMDocument3 *iface,
2037 VARIANT_BOOL* isSuccessful )
2039 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2040 LPWSTR filename = NULL;
2041 HRESULT hr = S_FALSE;
2042 IXMLDOMDocument3 *pNewDoc = NULL;
2043 IStream *pStream = NULL;
2046 TRACE("(%p)->type %d\n", This, V_VT(&xmlSource) );
2048 *isSuccessful = VARIANT_FALSE;
2050 assert( &This->node );
2052 switch( V_VT(&xmlSource) )
2055 filename = V_BSTR(&xmlSource);
2058 hr = IUnknown_QueryInterface(V_UNKNOWN(&xmlSource), &IID_IXMLDOMDocument3, (void**)&pNewDoc);
2063 domdoc *newDoc = impl_from_IXMLDOMDocument3( pNewDoc );
2064 xmldoc = xmlCopyDoc(get_doc(newDoc), 1);
2065 hr = attach_xmldoc(This, xmldoc);
2068 *isSuccessful = VARIANT_TRUE;
2073 hr = IUnknown_QueryInterface(V_UNKNOWN(&xmlSource), &IID_IStream, (void**)&pStream);
2076 IPersistStream *pDocStream;
2077 hr = IUnknown_QueryInterface(iface, &IID_IPersistStream, (void**)&pDocStream);
2080 hr = IPersistStream_Load(pDocStream, pStream);
2081 IStream_Release(pStream);
2084 *isSuccessful = VARIANT_TRUE;
2086 TRACE("Using IStream to load Document\n");
2091 ERR("xmldoc_IPersistStream_Load failed (%d)\n", hr);
2096 ERR("QueryInterface IID_IPersistStream failed (%d)\n", hr);
2101 /* ISequentialStream */
2102 FIXME("Unknown type not supported (%d) (%p)(%p)\n", hr, pNewDoc, V_UNKNOWN(&xmlSource)->lpVtbl);
2106 FIXME("VT type not supported (%d)\n", V_VT(&xmlSource));
2109 TRACE("filename (%s)\n", debugstr_w(filename));
2113 hr = doread( This, filename );
2116 This->error = E_FAIL;
2119 hr = This->error = S_OK;
2120 *isSuccessful = VARIANT_TRUE;
2124 if(!filename || FAILED(hr)) {
2125 xmldoc = xmlNewDoc(NULL);
2126 xmldoc->_private = create_priv();
2127 hr = attach_xmldoc(This, xmldoc);
2132 TRACE("ret (%d)\n", hr);
2138 static HRESULT WINAPI domdoc_get_readyState(
2139 IXMLDOMDocument3 *iface,
2142 domdoc *This = impl_from_IXMLDOMDocument3(iface);
2143 FIXME("stub! (%p)->(%p)\n", This, value);
2146 return E_INVALIDARG;
2148 *value = READYSTATE_COMPLETE;
2153 static HRESULT WINAPI domdoc_get_parseError(
2154 IXMLDOMDocument3 *iface,
2155 IXMLDOMParseError** errorObj )
2157 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2158 static const WCHAR err[] = {'e','r','r','o','r',0};
2159 BSTR error_string = NULL;
2161 FIXME("(%p)->(%p): creating a dummy parseError\n", iface, errorObj);
2164 error_string = SysAllocString(err);
2166 *errorObj = create_parseError(This->error, NULL, error_string, NULL, 0, 0, 0);
2167 if(!*errorObj) return E_OUTOFMEMORY;
2172 static HRESULT WINAPI domdoc_get_url(
2173 IXMLDOMDocument3 *iface,
2176 domdoc *This = impl_from_IXMLDOMDocument3(iface);
2177 FIXME("(%p)->(%p)\n", This, urlString);
2182 static HRESULT WINAPI domdoc_get_async(
2183 IXMLDOMDocument3 *iface,
2184 VARIANT_BOOL* isAsync )
2186 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2188 TRACE("(%p)->(%p: %d)\n", This, isAsync, This->async);
2189 *isAsync = This->async;
2194 static HRESULT WINAPI domdoc_put_async(
2195 IXMLDOMDocument3 *iface,
2196 VARIANT_BOOL isAsync )
2198 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2200 TRACE("(%p)->(%d)\n", This, isAsync);
2201 This->async = isAsync;
2206 static HRESULT WINAPI domdoc_abort(
2207 IXMLDOMDocument3 *iface )
2209 domdoc *This = impl_from_IXMLDOMDocument3(iface);
2210 FIXME("%p\n", This);
2215 static BOOL bstr_to_utf8( BSTR bstr, char **pstr, int *plen )
2220 len = WideCharToMultiByte( CP_UTF8, 0, bstr, -1, NULL, 0, NULL, NULL );
2221 str = heap_alloc( len );
2224 WideCharToMultiByte( CP_UTF8, 0, bstr, -1, str, len, NULL, NULL );
2230 /* don't rely on data to be in BSTR format, treat it as WCHAR string */
2231 static HRESULT WINAPI domdoc_loadXML(
2232 IXMLDOMDocument3 *iface,
2234 VARIANT_BOOL* isSuccessful )
2236 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2237 static const xmlChar encoding[] = "UTF-8";
2238 xmlDocPtr xmldoc = NULL;
2239 HRESULT hr = S_FALSE, hr2;
2243 TRACE("(%p)->(%s %p)\n", This, debugstr_w( bstrXML ), isSuccessful );
2245 assert ( &This->node );
2249 *isSuccessful = VARIANT_FALSE;
2251 if ( bstrXML && bstr_to_utf8( bstrXML, &str, &len ) )
2253 xmldoc = doparse(This, str, len, encoding);
2257 This->error = E_FAIL;
2258 TRACE("failed to parse document\n");
2262 hr = This->error = S_OK;
2263 *isSuccessful = VARIANT_TRUE;
2264 TRACE("parsed document %p\n", xmldoc);
2269 xmldoc = xmlNewDoc(NULL);
2271 xmldoc->_private = create_priv();
2273 hr2 = attach_xmldoc(This, xmldoc);
2280 static int XMLCALL domdoc_save_writecallback(void *ctx, const char *buffer, int len)
2284 if(!WriteFile(ctx, buffer, len, &written, NULL))
2286 WARN("write error\n");
2293 static int XMLCALL domdoc_save_closecallback(void *ctx)
2295 return CloseHandle(ctx) ? 0 : -1;
2298 static int XMLCALL domdoc_stream_save_writecallback(void *ctx, const char *buffer, int len)
2303 hr = IStream_Write((IStream*)ctx, buffer, len, &written);
2306 WARN("stream write error: 0x%08x\n", hr);
2313 static int XMLCALL domdoc_stream_save_closecallback(void *ctx)
2315 IStream_Release((IStream*)ctx);
2319 static HRESULT WINAPI domdoc_save(
2320 IXMLDOMDocument3 *iface,
2321 VARIANT destination )
2323 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2324 xmlSaveCtxtPtr ctx = NULL;
2328 TRACE("(%p)->(var(vt %d, %s))\n", This, V_VT(&destination),
2329 V_VT(&destination) == VT_BSTR ? debugstr_w(V_BSTR(&destination)) : NULL);
2331 if(V_VT(&destination) != VT_BSTR && V_VT(&destination) != VT_UNKNOWN)
2333 FIXME("Unhandled vt %d\n", V_VT(&destination));
2337 if(V_VT(&destination) == VT_UNKNOWN)
2339 IUnknown *pUnk = V_UNKNOWN(&destination);
2340 IXMLDOMDocument2 *document;
2343 ret = IUnknown_QueryInterface(pUnk, &IID_IXMLDOMDocument3, (void**)&document);
2346 VARIANT_BOOL success;
2349 ret = IXMLDOMDocument3_get_xml(iface, &xml);
2352 ret = IXMLDOMDocument3_loadXML(document, xml, &success);
2356 IXMLDOMDocument3_Release(document);
2360 ret = IUnknown_QueryInterface(pUnk, &IID_IStream, (void**)&stream);
2363 ctx = xmlSaveToIO(domdoc_stream_save_writecallback,
2364 domdoc_stream_save_closecallback, stream, NULL, XML_SAVE_NO_DECL);
2368 IStream_Release(stream);
2375 /* save with file path */
2376 HANDLE handle = CreateFileW( V_BSTR(&destination), GENERIC_WRITE, 0,
2377 NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL );
2378 if( handle == INVALID_HANDLE_VALUE )
2380 WARN("failed to create file\n");
2384 /* disable top XML declaration */
2385 ctx = xmlSaveToIO(domdoc_save_writecallback, domdoc_save_closecallback,
2386 handle, NULL, XML_SAVE_NO_DECL);
2389 CloseHandle(handle);
2394 xmldecl = xmldoc_unlink_xmldecl(get_doc(This));
2395 if (xmlSaveDoc(ctx, get_doc(This)) == -1) ret = S_FALSE;
2396 xmldoc_link_xmldecl(get_doc(This), xmldecl);
2398 /* will release resources through close callback */
2404 static HRESULT WINAPI domdoc_get_validateOnParse(
2405 IXMLDOMDocument3 *iface,
2406 VARIANT_BOOL* isValidating )
2408 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2409 TRACE("(%p)->(%p: %d)\n", This, isValidating, This->validating);
2410 *isValidating = This->validating;
2415 static HRESULT WINAPI domdoc_put_validateOnParse(
2416 IXMLDOMDocument3 *iface,
2417 VARIANT_BOOL isValidating )
2419 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2420 TRACE("(%p)->(%d)\n", This, isValidating);
2421 This->validating = isValidating;
2426 static HRESULT WINAPI domdoc_get_resolveExternals(
2427 IXMLDOMDocument3 *iface,
2428 VARIANT_BOOL* isResolving )
2430 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2431 TRACE("(%p)->(%p: %d)\n", This, isResolving, This->resolving);
2432 *isResolving = This->resolving;
2437 static HRESULT WINAPI domdoc_put_resolveExternals(
2438 IXMLDOMDocument3 *iface,
2439 VARIANT_BOOL isResolving )
2441 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2442 TRACE("(%p)->(%d)\n", This, isResolving);
2443 This->resolving = isResolving;
2448 static HRESULT WINAPI domdoc_get_preserveWhiteSpace(
2449 IXMLDOMDocument3 *iface,
2450 VARIANT_BOOL* isPreserving )
2452 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2453 TRACE("(%p)->(%p: %d)\n", This, isPreserving, This->properties->preserving);
2454 *isPreserving = This->properties->preserving;
2459 static HRESULT WINAPI domdoc_put_preserveWhiteSpace(
2460 IXMLDOMDocument3 *iface,
2461 VARIANT_BOOL isPreserving )
2463 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2464 TRACE("(%p)->(%d)\n", This, isPreserving);
2465 This->properties->preserving = isPreserving;
2470 static HRESULT WINAPI domdoc_put_onReadyStateChange(
2471 IXMLDOMDocument3 *iface,
2472 VARIANT readyStateChangeSink )
2474 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2475 FIXME("%p\n", This);
2480 static HRESULT WINAPI domdoc_put_onDataAvailable(
2481 IXMLDOMDocument3 *iface,
2482 VARIANT onDataAvailableSink )
2484 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2485 FIXME("%p\n", This);
2489 static HRESULT WINAPI domdoc_put_onTransformNode(
2490 IXMLDOMDocument3 *iface,
2491 VARIANT onTransformNodeSink )
2493 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2494 FIXME("%p\n", This);
2498 static HRESULT WINAPI domdoc_get_namespaces(
2499 IXMLDOMDocument3* iface,
2500 IXMLDOMSchemaCollection** schemaCollection )
2502 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2503 FIXME("(%p)->(%p)\n", This, schemaCollection);
2507 static HRESULT WINAPI domdoc_get_schemas(
2508 IXMLDOMDocument3* iface,
2511 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2512 HRESULT hr = S_FALSE;
2513 IXMLDOMSchemaCollection2* cur_schema = This->properties->schemaCache;
2515 TRACE("(%p)->(%p)\n", This, var1);
2517 VariantInit(var1); /* Test shows we don't call VariantClear here */
2518 V_VT(var1) = VT_NULL;
2522 hr = IXMLDOMSchemaCollection2_QueryInterface(cur_schema, &IID_IDispatch, (void**)&V_DISPATCH(var1));
2524 V_VT(var1) = VT_DISPATCH;
2529 static HRESULT WINAPI domdoc_putref_schemas(
2530 IXMLDOMDocument3* iface,
2533 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2534 HRESULT hr = E_FAIL;
2535 IXMLDOMSchemaCollection2* new_schema = NULL;
2537 FIXME("(%p): semi-stub\n", This);
2541 hr = IUnknown_QueryInterface(V_UNKNOWN(&var1), &IID_IXMLDOMSchemaCollection, (void**)&new_schema);
2545 hr = IDispatch_QueryInterface(V_DISPATCH(&var1), &IID_IXMLDOMSchemaCollection, (void**)&new_schema);
2554 WARN("Can't get schema from vt %x\n", V_VT(&var1));
2559 IXMLDOMSchemaCollection2* old_schema = InterlockedExchangePointer((void**)&This->properties->schemaCache, new_schema);
2560 if(old_schema) IXMLDOMSchemaCollection2_Release(old_schema);
2566 static inline BOOL is_wellformed(xmlDocPtr doc)
2568 #ifdef HAVE_XMLDOC_PROPERTIES
2569 return doc->properties & XML_DOC_WELLFORMED;
2571 /* Not a full check, but catches the worst violations */
2575 for (child = doc->children; child != NULL; child = child->next)
2577 switch (child->type)
2579 case XML_ELEMENT_NODE:
2584 case XML_CDATA_SECTION_NODE:
2596 static void LIBXML2_LOG_CALLBACK validate_error(void* ctx, char const* msg, ...)
2600 LIBXML2_CALLBACK_ERR(domdoc_validateNode, msg, ap);
2604 static void LIBXML2_LOG_CALLBACK validate_warning(void* ctx, char const* msg, ...)
2608 LIBXML2_CALLBACK_WARN(domdoc_validateNode, msg, ap);
2612 static HRESULT WINAPI domdoc_validateNode(
2613 IXMLDOMDocument3* iface,
2615 IXMLDOMParseError** err)
2617 domdoc* This = impl_from_IXMLDOMDocument3(iface);
2618 LONG state, err_code = 0;
2622 TRACE("(%p)->(%p, %p)\n", This, node, err);
2623 domdoc_get_readyState(iface, &state);
2624 if (state != READYSTATE_COMPLETE)
2627 *err = create_parseError(err_code, NULL, NULL, NULL, 0, 0, 0);
2634 *err = create_parseError(err_code, NULL, NULL, NULL, 0, 0, 0);
2638 if (!get_node_obj(node)->node || get_node_obj(node)->node->doc != get_doc(This))
2641 *err = create_parseError(err_code, NULL, NULL, NULL, 0, 0, 0);
2645 if (!is_wellformed(get_doc(This)))
2647 ERR("doc not well-formed\n");
2649 *err = create_parseError(E_XML_NOTWF, NULL, NULL, NULL, 0, 0, 0);
2653 /* DTD validation */
2654 if (get_doc(This)->intSubset || get_doc(This)->extSubset)
2656 xmlValidCtxtPtr vctx = xmlNewValidCtxt();
2657 vctx->error = validate_error;
2658 vctx->warning = validate_warning;
2661 if (!((node == (IXMLDOMNode*)iface)?
2662 xmlValidateDocument(vctx, get_doc(This)) :
2663 xmlValidateElement(vctx, get_doc(This), get_node_obj(node)->node)))
2665 /* TODO: get a real error code here */
2666 TRACE("DTD validation failed\n");
2667 err_code = E_XML_INVALID;
2670 xmlFreeValidCtxt(vctx);
2673 /* Schema validation */
2674 if (hr == S_OK && This->properties->schemaCache != NULL)
2677 hr = SchemaCache_validate_tree(This->properties->schemaCache, get_node_obj(node)->node);
2681 /* TODO: get a real error code here */
2684 TRACE("schema validation succeeded\n");
2688 ERR("schema validation failed\n");
2689 err_code = E_XML_INVALID;
2694 /* not really OK, just didn't find a schema for the ns */
2701 ERR("no DTD or schema found\n");
2702 err_code = E_XML_NODTD;
2707 *err = create_parseError(err_code, NULL, NULL, NULL, 0, 0, 0);
2712 static HRESULT WINAPI domdoc_validate(
2713 IXMLDOMDocument3* iface,
2714 IXMLDOMParseError** err)
2716 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2717 TRACE("(%p)->(%p)\n", This, err);
2718 return domdoc_validateNode(iface, (IXMLDOMNode*)iface, err);
2721 static HRESULT WINAPI domdoc_setProperty(
2722 IXMLDOMDocument3* iface,
2726 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2728 TRACE("(%p)->(%s)\n", This, debugstr_w(p));
2730 if (lstrcmpiW(p, PropertySelectionLanguageW) == 0)
2736 V_VT(&varStr) = VT_EMPTY;
2737 if (V_VT(&var) != VT_BSTR)
2739 if (FAILED(hr = VariantChangeType(&varStr, &var, 0, VT_BSTR)))
2741 bstr = V_BSTR(&varStr);
2744 bstr = V_BSTR(&var);
2747 if (lstrcmpiW(bstr, PropValueXPathW) == 0)
2748 This->properties->XPath = TRUE;
2749 else if (lstrcmpiW(bstr, PropValueXSLPatternW) == 0)
2750 This->properties->XPath = FALSE;
2754 VariantClear(&varStr);
2757 else if (lstrcmpiW(p, PropertySelectionNamespacesW) == 0)
2762 xmlChar *pTokBegin, *pTokEnd, *pTokInner;
2763 xmlChar *nsStr = (xmlChar*)This->properties->selectNsStr;
2764 xmlXPathContextPtr ctx;
2765 struct list *pNsList;
2766 select_ns_entry* pNsEntry = NULL;
2768 V_VT(&varStr) = VT_EMPTY;
2769 if (V_VT(&var) != VT_BSTR)
2771 if (FAILED(hr = VariantChangeType(&varStr, &var, 0, VT_BSTR)))
2773 bstr = V_BSTR(&varStr);
2776 bstr = V_BSTR(&var);
2780 pNsList = &(This->properties->selectNsList);
2781 clear_selectNsList(pNsList);
2783 nsStr = xmlChar_from_wchar(bstr);
2786 TRACE("Setting SelectionNamespaces property to: %s\n", nsStr);
2788 This->properties->selectNsStr = nsStr;
2789 This->properties->selectNsStr_len = xmlStrlen(nsStr);
2792 ctx = xmlXPathNewContext(This->node.node->doc);
2795 for (; *pTokBegin; pTokBegin = pTokEnd)
2797 if (pNsEntry != NULL)
2798 memset(pNsEntry, 0, sizeof(select_ns_entry));
2800 pNsEntry = heap_alloc_zero(sizeof(select_ns_entry));
2802 while (*pTokBegin == ' ')
2804 pTokEnd = pTokBegin;
2805 while (*pTokEnd != ' ' && *pTokEnd != 0)
2808 if (xmlStrncmp(pTokBegin, (xmlChar const*)"xmlns", 5) != 0)
2811 WARN("Syntax error in xmlns string: %s\n\tat token: %s\n",
2812 wine_dbgstr_w(bstr), wine_dbgstr_an((const char*)pTokBegin, pTokEnd-pTokBegin));
2817 if (*pTokBegin == '=')
2819 /*valid for XSLPattern?*/
2820 FIXME("Setting default xmlns not supported - skipping.\n");
2821 pTokBegin = pTokEnd;
2824 else if (*pTokBegin == ':')
2826 pNsEntry->prefix = ++pTokBegin;
2827 for (pTokInner = pTokBegin; pTokInner != pTokEnd && *pTokInner != '='; ++pTokInner)
2830 if (pTokInner == pTokEnd)
2833 WARN("Syntax error in xmlns string: %s\n\tat token: %s\n",
2834 wine_dbgstr_w(bstr), wine_dbgstr_an((const char*)pTokBegin, pTokEnd-pTokBegin));
2838 pNsEntry->prefix_end = *pTokInner;
2842 if (pTokEnd-pTokInner > 1 &&
2843 ((*pTokInner == '\'' && *(pTokEnd-1) == '\'') ||
2844 (*pTokInner == '"' && *(pTokEnd-1) == '"')))
2846 pNsEntry->href = ++pTokInner;
2847 pNsEntry->href_end = *(pTokEnd-1);
2849 list_add_tail(pNsList, &pNsEntry->entry);
2850 /*let libxml figure out if they're valid from here ;)*/
2851 if (xmlXPathRegisterNs(ctx, pNsEntry->prefix, pNsEntry->href) != 0)
2860 WARN("Syntax error in xmlns string: %s\n\tat token: %s\n",
2861 wine_dbgstr_w(bstr), wine_dbgstr_an((const char*)pTokInner, pTokEnd-pTokInner));
2862 list_add_tail(pNsList, &pNsEntry->entry);
2875 heap_free(pNsEntry);
2876 xmlXPathFreeContext(ctx);
2879 VariantClear(&varStr);
2882 else if (lstrcmpiW(p, PropertyProhibitDTDW) == 0 ||
2883 lstrcmpiW(p, PropertyNewParserW) == 0)
2886 FIXME("Ignoring property %s, value %d\n", debugstr_w(p), V_BOOL(&var));
2890 FIXME("Unknown property %s\n", wine_dbgstr_w(p));
2894 static HRESULT WINAPI domdoc_getProperty(
2895 IXMLDOMDocument3* iface,
2899 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2901 TRACE("(%p)->(%p)\n", This, debugstr_w(p));
2904 return E_INVALIDARG;
2906 if (lstrcmpiW(p, PropertySelectionLanguageW) == 0)
2908 V_VT(var) = VT_BSTR;
2909 V_BSTR(var) = This->properties->XPath ?
2910 SysAllocString(PropValueXPathW) :
2911 SysAllocString(PropValueXSLPatternW);
2912 return V_BSTR(var) ? S_OK : E_OUTOFMEMORY;
2914 else if (lstrcmpiW(p, PropertySelectionNamespacesW) == 0)
2917 BSTR rebuiltStr, cur;
2918 const xmlChar *nsStr;
2919 struct list *pNsList;
2920 select_ns_entry* pNsEntry;
2922 V_VT(var) = VT_BSTR;
2923 nsStr = This->properties->selectNsStr;
2924 pNsList = &This->properties->selectNsList;
2925 lenA = This->properties->selectNsStr_len;
2926 lenW = MultiByteToWideChar(CP_UTF8, 0, (LPCSTR)nsStr, lenA+1, NULL, 0);
2927 rebuiltStr = heap_alloc(lenW*sizeof(WCHAR));
2928 MultiByteToWideChar(CP_UTF8, 0, (LPCSTR)nsStr, lenA+1, rebuiltStr, lenW);
2930 /* this is fine because all of the chars that end tokens are ASCII*/
2931 LIST_FOR_EACH_ENTRY(pNsEntry, pNsList, select_ns_entry, entry)
2933 while (*cur != 0) ++cur;
2934 if (pNsEntry->prefix_end)
2936 *cur = pNsEntry->prefix_end;
2937 while (*cur != 0) ++cur;
2940 if (pNsEntry->href_end)
2942 *cur = pNsEntry->href_end;
2945 V_BSTR(var) = SysAllocString(rebuiltStr);
2946 heap_free(rebuiltStr);
2950 FIXME("Unknown property %s\n", wine_dbgstr_w(p));
2954 static HRESULT WINAPI domdoc_importNode(
2955 IXMLDOMDocument3* iface,
2958 IXMLDOMNode** clone)
2960 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2961 FIXME("(%p)->(%p %d %p): stub\n", This, node, deep, clone);
2965 static const struct IXMLDOMDocument3Vtbl domdoc_vtbl =
2967 domdoc_QueryInterface,
2970 domdoc_GetTypeInfoCount,
2972 domdoc_GetIDsOfNames,
2974 domdoc_get_nodeName,
2975 domdoc_get_nodeValue,
2976 domdoc_put_nodeValue,
2977 domdoc_get_nodeType,
2978 domdoc_get_parentNode,
2979 domdoc_get_childNodes,
2980 domdoc_get_firstChild,
2981 domdoc_get_lastChild,
2982 domdoc_get_previousSibling,
2983 domdoc_get_nextSibling,
2984 domdoc_get_attributes,
2985 domdoc_insertBefore,
2986 domdoc_replaceChild,
2989 domdoc_hasChildNodes,
2990 domdoc_get_ownerDocument,
2992 domdoc_get_nodeTypeString,
2995 domdoc_get_specified,
2996 domdoc_get_definition,
2997 domdoc_get_nodeTypedValue,
2998 domdoc_put_nodeTypedValue,
2999 domdoc_get_dataType,
3000 domdoc_put_dataType,
3002 domdoc_transformNode,
3004 domdoc_selectSingleNode,
3006 domdoc_get_namespaceURI,
3008 domdoc_get_baseName,
3009 domdoc_transformNodeToObject,
3011 domdoc_get_implementation,
3012 domdoc_get_documentElement,
3013 domdoc_put_documentElement,
3014 domdoc_createElement,
3015 domdoc_createDocumentFragment,
3016 domdoc_createTextNode,
3017 domdoc_createComment,
3018 domdoc_createCDATASection,
3019 domdoc_createProcessingInstruction,
3020 domdoc_createAttribute,
3021 domdoc_createEntityReference,
3022 domdoc_getElementsByTagName,
3026 domdoc_get_readyState,
3027 domdoc_get_parseError,
3034 domdoc_get_validateOnParse,
3035 domdoc_put_validateOnParse,
3036 domdoc_get_resolveExternals,
3037 domdoc_put_resolveExternals,
3038 domdoc_get_preserveWhiteSpace,
3039 domdoc_put_preserveWhiteSpace,
3040 domdoc_put_onReadyStateChange,
3041 domdoc_put_onDataAvailable,
3042 domdoc_put_onTransformNode,
3043 domdoc_get_namespaces,
3045 domdoc_putref_schemas,
3049 domdoc_validateNode,
3053 /* IConnectionPointContainer */
3054 static HRESULT WINAPI ConnectionPointContainer_QueryInterface(IConnectionPointContainer *iface,
3055 REFIID riid, void **ppv)
3057 domdoc *This = impl_from_IConnectionPointContainer(iface);
3058 return IXMLDOMDocument3_QueryInterface((IXMLDOMDocument3*)This, riid, ppv);
3061 static ULONG WINAPI ConnectionPointContainer_AddRef(IConnectionPointContainer *iface)
3063 domdoc *This = impl_from_IConnectionPointContainer(iface);
3064 return IXMLDOMDocument3_AddRef((IXMLDOMDocument3*)This);
3067 static ULONG WINAPI ConnectionPointContainer_Release(IConnectionPointContainer *iface)
3069 domdoc *This = impl_from_IConnectionPointContainer(iface);
3070 return IXMLDOMDocument3_Release((IXMLDOMDocument3*)This);
3073 static HRESULT WINAPI ConnectionPointContainer_EnumConnectionPoints(IConnectionPointContainer *iface,
3074 IEnumConnectionPoints **ppEnum)
3076 domdoc *This = impl_from_IConnectionPointContainer(iface);
3077 FIXME("(%p)->(%p): stub\n", This, ppEnum);
3081 static HRESULT WINAPI ConnectionPointContainer_FindConnectionPoint(IConnectionPointContainer *iface,
3082 REFIID riid, IConnectionPoint **cp)
3084 domdoc *This = impl_from_IConnectionPointContainer(iface);
3085 ConnectionPoint *iter;
3087 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), cp);
3091 for(iter = This->cp_list; iter; iter = iter->next)
3093 if (IsEqualGUID(iter->iid, riid))
3094 *cp = (IConnectionPoint*)&iter->lpVtblConnectionPoint;
3099 IConnectionPoint_AddRef(*cp);
3103 FIXME("unsupported riid %s\n", debugstr_guid(riid));
3104 return CONNECT_E_NOCONNECTION;
3108 static const struct IConnectionPointContainerVtbl ConnectionPointContainerVtbl =
3110 ConnectionPointContainer_QueryInterface,
3111 ConnectionPointContainer_AddRef,
3112 ConnectionPointContainer_Release,
3113 ConnectionPointContainer_EnumConnectionPoints,
3114 ConnectionPointContainer_FindConnectionPoint
3117 /* IConnectionPoint */
3118 static HRESULT WINAPI ConnectionPoint_QueryInterface(IConnectionPoint *iface,
3119 REFIID riid, void **ppv)
3121 ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3123 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv );
3127 if (IsEqualGUID(&IID_IUnknown, riid) ||
3128 IsEqualGUID(&IID_IConnectionPoint, riid))
3135 IConnectionPoint_AddRef(iface);
3139 WARN("Unsupported interface %s\n", debugstr_guid(riid));
3140 return E_NOINTERFACE;
3143 static ULONG WINAPI ConnectionPoint_AddRef(IConnectionPoint *iface)
3145 ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3146 return IConnectionPointContainer_AddRef(This->container);
3149 static ULONG WINAPI ConnectionPoint_Release(IConnectionPoint *iface)
3151 ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3152 return IConnectionPointContainer_Release(This->container);
3155 static HRESULT WINAPI ConnectionPoint_GetConnectionInterface(IConnectionPoint *iface, IID *iid)
3157 ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3159 TRACE("(%p)->(%p)\n", This, iid);
3161 if (!iid) return E_POINTER;
3167 static HRESULT WINAPI ConnectionPoint_GetConnectionPointContainer(IConnectionPoint *iface,
3168 IConnectionPointContainer **container)
3170 ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3172 TRACE("(%p)->(%p)\n", This, container);
3174 if (!container) return E_POINTER;
3176 *container = This->container;
3177 IConnectionPointContainer_AddRef(*container);
3181 static HRESULT WINAPI ConnectionPoint_Advise(IConnectionPoint *iface, IUnknown *pUnkSink,
3184 ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3185 FIXME("(%p)->(%p %p): stub\n", This, pUnkSink, pdwCookie);
3189 static HRESULT WINAPI ConnectionPoint_Unadvise(IConnectionPoint *iface, DWORD cookie)
3191 ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3193 TRACE("(%p)->(%d)\n", This, cookie);
3195 if (cookie == 0 || cookie > This->sinks_size || !This->sinks[cookie-1].unk)
3196 return CONNECT_E_NOCONNECTION;
3198 IUnknown_Release(This->sinks[cookie-1].unk);
3199 This->sinks[cookie-1].unk = NULL;
3204 static HRESULT WINAPI ConnectionPoint_EnumConnections(IConnectionPoint *iface,
3205 IEnumConnections **ppEnum)
3207 ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3208 FIXME("(%p)->(%p): stub\n", This, ppEnum);
3212 static const IConnectionPointVtbl ConnectionPointVtbl =
3214 ConnectionPoint_QueryInterface,
3215 ConnectionPoint_AddRef,
3216 ConnectionPoint_Release,
3217 ConnectionPoint_GetConnectionInterface,
3218 ConnectionPoint_GetConnectionPointContainer,
3219 ConnectionPoint_Advise,
3220 ConnectionPoint_Unadvise,
3221 ConnectionPoint_EnumConnections
3224 void ConnectionPoint_Init(ConnectionPoint *cp, struct domdoc *doc, REFIID riid)
3226 cp->lpVtblConnectionPoint = &ConnectionPointVtbl;
3232 cp->next = doc->cp_list;
3235 cp->container = (IConnectionPointContainer*)&doc->lpVtblConnectionPointContainer;
3238 /* domdoc implementation of IObjectWithSite */
3239 static HRESULT WINAPI
3240 domdoc_ObjectWithSite_QueryInterface( IObjectWithSite* iface, REFIID riid, void** ppvObject )
3242 domdoc *This = impl_from_IObjectWithSite(iface);
3243 return IXMLDOMDocument3_QueryInterface( (IXMLDOMDocument3 *)This, riid, ppvObject );
3246 static ULONG WINAPI domdoc_ObjectWithSite_AddRef( IObjectWithSite* iface )
3248 domdoc *This = impl_from_IObjectWithSite(iface);
3249 return IXMLDOMDocument3_AddRef((IXMLDOMDocument3 *)This);
3252 static ULONG WINAPI domdoc_ObjectWithSite_Release( IObjectWithSite* iface )
3254 domdoc *This = impl_from_IObjectWithSite(iface);
3255 return IXMLDOMDocument3_Release((IXMLDOMDocument3 *)This);
3258 static HRESULT WINAPI domdoc_ObjectWithSite_GetSite( IObjectWithSite *iface, REFIID iid, void **ppvSite )
3260 domdoc *This = impl_from_IObjectWithSite(iface);
3262 TRACE("(%p)->(%s %p)\n", This, debugstr_guid( iid ), ppvSite );
3267 return IUnknown_QueryInterface( This->site, iid, ppvSite );
3270 static HRESULT WINAPI domdoc_ObjectWithSite_SetSite( IObjectWithSite *iface, IUnknown *punk )
3272 domdoc *This = impl_from_IObjectWithSite(iface);
3274 TRACE("(%p)->(%p)\n", iface, punk);
3280 IUnknown_Release( This->site );
3287 IUnknown_AddRef( punk );
3290 IUnknown_Release( This->site );
3297 static const IObjectWithSiteVtbl domdocObjectSite =
3299 domdoc_ObjectWithSite_QueryInterface,
3300 domdoc_ObjectWithSite_AddRef,
3301 domdoc_ObjectWithSite_Release,
3302 domdoc_ObjectWithSite_SetSite,
3303 domdoc_ObjectWithSite_GetSite
3306 static HRESULT WINAPI domdoc_Safety_QueryInterface(IObjectSafety *iface, REFIID riid, void **ppv)
3308 domdoc *This = impl_from_IObjectSafety(iface);
3309 return IXMLDOMDocument3_QueryInterface( (IXMLDOMDocument3 *)This, riid, ppv );
3312 static ULONG WINAPI domdoc_Safety_AddRef(IObjectSafety *iface)
3314 domdoc *This = impl_from_IObjectSafety(iface);
3315 return IXMLDOMDocument3_AddRef((IXMLDOMDocument3 *)This);
3318 static ULONG WINAPI domdoc_Safety_Release(IObjectSafety *iface)
3320 domdoc *This = impl_from_IObjectSafety(iface);
3321 return IXMLDOMDocument3_Release((IXMLDOMDocument3 *)This);
3324 #define SAFETY_SUPPORTED_OPTIONS (INTERFACESAFE_FOR_UNTRUSTED_CALLER|INTERFACESAFE_FOR_UNTRUSTED_DATA|INTERFACE_USES_SECURITY_MANAGER)
3326 static HRESULT WINAPI domdoc_Safety_GetInterfaceSafetyOptions(IObjectSafety *iface, REFIID riid,
3327 DWORD *supported, DWORD *enabled)
3329 domdoc *This = impl_from_IObjectSafety(iface);
3331 TRACE("(%p)->(%s %p %p)\n", This, debugstr_guid(riid), supported, enabled);
3333 if(!supported || !enabled) return E_POINTER;
3335 *supported = SAFETY_SUPPORTED_OPTIONS;
3336 *enabled = This->safeopt;
3341 static HRESULT WINAPI domdoc_Safety_SetInterfaceSafetyOptions(IObjectSafety *iface, REFIID riid,
3342 DWORD mask, DWORD enabled)
3344 domdoc *This = impl_from_IObjectSafety(iface);
3345 TRACE("(%p)->(%s %x %x)\n", This, debugstr_guid(riid), mask, enabled);
3347 if ((mask & ~SAFETY_SUPPORTED_OPTIONS) != 0)
3350 This->safeopt = enabled & mask & SAFETY_SUPPORTED_OPTIONS;
3354 #undef SAFETY_SUPPORTED_OPTIONS
3356 static const IObjectSafetyVtbl domdocObjectSafetyVtbl = {
3357 domdoc_Safety_QueryInterface,
3358 domdoc_Safety_AddRef,
3359 domdoc_Safety_Release,
3360 domdoc_Safety_GetInterfaceSafetyOptions,
3361 domdoc_Safety_SetInterfaceSafetyOptions
3364 static const tid_t domdoc_iface_tids[] = {
3366 IXMLDOMDocument_tid,
3367 IXMLDOMDocument2_tid,
3370 static dispex_static_data_t domdoc_dispex = {
3372 IXMLDOMDocument2_tid,
3377 HRESULT DOMDocument_create_from_xmldoc(xmlDocPtr xmldoc, IXMLDOMDocument3 **document)
3381 doc = heap_alloc( sizeof (*doc) );
3383 return E_OUTOFMEMORY;
3385 doc->lpVtbl = &domdoc_vtbl;
3386 doc->lpvtblIPersistStreamInit = &xmldoc_IPersistStreamInit_VTable;
3387 doc->lpvtblIObjectWithSite = &domdocObjectSite;
3388 doc->lpvtblIObjectSafety = &domdocObjectSafetyVtbl;
3389 doc->lpvtblISupportErrorInfo = &support_error_vtbl;
3390 doc->lpVtblConnectionPointContainer = &ConnectionPointContainerVtbl;
3392 doc->async = VARIANT_TRUE;
3393 doc->validating = 0;
3395 doc->properties = properties_from_xmlDocPtr(xmldoc);
3401 doc->cp_list = NULL;
3403 /* events connection points */
3404 ConnectionPoint_Init(&doc->cp_dispatch, doc, &IID_IDispatch);
3405 ConnectionPoint_Init(&doc->cp_propnotif, doc, &IID_IPropertyNotifySink);
3406 ConnectionPoint_Init(&doc->cp_domdocevents, doc, &DIID_XMLDOMDocumentEvents);
3408 init_xmlnode(&doc->node, (xmlNodePtr)xmldoc, (IXMLDOMNode*)&doc->lpVtbl, &domdoc_dispex);
3410 *document = (IXMLDOMDocument3*)&doc->lpVtbl;
3412 TRACE("returning iface %p\n", *document);
3416 HRESULT DOMDocument_create(const GUID *clsid, IUnknown *pUnkOuter, void **ppObj)
3421 TRACE("(%s, %p, %p)\n", debugstr_guid(clsid), pUnkOuter, ppObj);
3423 xmldoc = xmlNewDoc(NULL);
3425 return E_OUTOFMEMORY;
3427 xmldoc->_private = create_priv();
3428 priv_from_xmlDocPtr(xmldoc)->properties = create_properties(clsid);
3430 hr = DOMDocument_create_from_xmldoc(xmldoc, (IXMLDOMDocument3**)ppObj);
3433 free_properties(properties_from_xmlDocPtr(xmldoc));
3434 heap_free(xmldoc->_private);
3442 IUnknown* create_domdoc( xmlNodePtr document )
3447 TRACE("(%p)\n", document);
3449 hr = DOMDocument_create_from_xmldoc((xmlDocPtr)document, (IXMLDOMDocument3**)&pObj);
3458 HRESULT DOMDocument_create(const GUID *clsid, IUnknown *pUnkOuter, void **ppObj)
3460 MESSAGE("This program tried to use a DOMDocument object, but\n"
3461 "libxml2 support was not present at compile time.\n");