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 return IXMLDOMNode_put_nodeTypedValue( IXMLDOMNode_from_impl(&This->node), typedValue );
1295 static HRESULT WINAPI domdoc_get_dataType(
1296 IXMLDOMDocument3 *iface,
1299 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1300 TRACE("(%p)->(%p)\n", This, typename);
1301 return return_null_var( typename );
1305 static HRESULT WINAPI domdoc_put_dataType(
1306 IXMLDOMDocument3 *iface,
1309 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1310 return IXMLDOMNode_put_dataType( IXMLDOMNode_from_impl(&This->node), dataTypeName );
1313 static int XMLCALL domdoc_get_xml_writecallback(void *ctx, const char *data, int len)
1315 return xmlBufferAdd((xmlBufferPtr)ctx, (xmlChar*)data, len) == 0 ? len : 0;
1318 static HRESULT WINAPI domdoc_get_xml(
1319 IXMLDOMDocument3 *iface,
1322 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1323 xmlSaveCtxtPtr ctxt;
1328 TRACE("(%p)->(%p)\n", This, p);
1331 return E_INVALIDARG;
1335 buf = xmlBufferCreate();
1337 return E_OUTOFMEMORY;
1339 options = xmldoc_has_decl(get_doc(This)) ? XML_SAVE_NO_DECL : 0;
1340 options |= XML_SAVE_FORMAT;
1341 ctxt = xmlSaveToIO(domdoc_get_xml_writecallback, NULL, buf, "UTF-8", options);
1346 return E_OUTOFMEMORY;
1349 ret = xmlSaveDoc(ctxt, get_doc(This));
1350 /* flushes on close */
1353 TRACE("%ld, len=%d\n", ret, xmlBufferLength(buf));
1354 if(ret != -1 && xmlBufferLength(buf) > 0)
1358 content = bstr_from_xmlChar(xmlBufferContent(buf));
1359 content = EnsureCorrectEOL(content);
1365 *p = SysAllocStringLen(NULL, 0);
1370 return *p ? S_OK : E_OUTOFMEMORY;
1374 static HRESULT WINAPI domdoc_transformNode(
1375 IXMLDOMDocument3 *iface,
1376 IXMLDOMNode* styleSheet,
1379 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1380 return IXMLDOMNode_transformNode( IXMLDOMNode_from_impl(&This->node), styleSheet, xmlString );
1384 static HRESULT WINAPI domdoc_selectNodes(
1385 IXMLDOMDocument3 *iface,
1387 IXMLDOMNodeList** resultList )
1389 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1390 return IXMLDOMNode_selectNodes( IXMLDOMNode_from_impl(&This->node), queryString, resultList );
1394 static HRESULT WINAPI domdoc_selectSingleNode(
1395 IXMLDOMDocument3 *iface,
1397 IXMLDOMNode** resultNode )
1399 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1400 return IXMLDOMNode_selectSingleNode( IXMLDOMNode_from_impl(&This->node), queryString, resultNode );
1404 static HRESULT WINAPI domdoc_get_parsed(
1405 IXMLDOMDocument3 *iface,
1406 VARIANT_BOOL* isParsed )
1408 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1409 FIXME("(%p)->(%p) stub!\n", This, isParsed);
1410 *isParsed = VARIANT_TRUE;
1415 static HRESULT WINAPI domdoc_get_namespaceURI(
1416 IXMLDOMDocument3 *iface,
1417 BSTR* namespaceURI )
1419 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1420 return IXMLDOMNode_get_namespaceURI( IXMLDOMNode_from_impl(&This->node), namespaceURI );
1424 static HRESULT WINAPI domdoc_get_prefix(
1425 IXMLDOMDocument3 *iface,
1428 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1429 TRACE("(%p)->(%p)\n", This, prefix);
1430 return return_null_bstr( prefix );
1434 static HRESULT WINAPI domdoc_get_baseName(
1435 IXMLDOMDocument3 *iface,
1438 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1439 TRACE("(%p)->(%p)\n", This, name);
1440 return return_null_bstr( name );
1444 static HRESULT WINAPI domdoc_transformNodeToObject(
1445 IXMLDOMDocument3 *iface,
1446 IXMLDOMNode* stylesheet,
1447 VARIANT outputObject)
1449 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1450 return IXMLDOMNode_transformNodeToObject( IXMLDOMNode_from_impl(&This->node), stylesheet, outputObject );
1454 static HRESULT WINAPI domdoc_get_doctype(
1455 IXMLDOMDocument3 *iface,
1456 IXMLDOMDocumentType** documentType )
1458 domdoc *This = impl_from_IXMLDOMDocument3(iface);
1459 FIXME("(%p)\n", This);
1464 static HRESULT WINAPI domdoc_get_implementation(
1465 IXMLDOMDocument3 *iface,
1466 IXMLDOMImplementation** impl )
1468 domdoc *This = impl_from_IXMLDOMDocument3(iface);
1470 TRACE("(%p)->(%p)\n", This, impl);
1473 return E_INVALIDARG;
1475 *impl = (IXMLDOMImplementation*)create_doc_Implementation();
1480 static HRESULT WINAPI domdoc_get_documentElement(
1481 IXMLDOMDocument3 *iface,
1482 IXMLDOMElement** DOMElement )
1484 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1485 IXMLDOMNode *element_node;
1489 TRACE("(%p)->(%p)\n", This, DOMElement);
1492 return E_INVALIDARG;
1496 root = xmlDocGetRootElement( get_doc(This) );
1500 element_node = create_node( root );
1501 if(!element_node) return S_FALSE;
1503 hr = IXMLDOMNode_QueryInterface(element_node, &IID_IXMLDOMElement, (void**)DOMElement);
1504 IXMLDOMNode_Release(element_node);
1510 static HRESULT WINAPI domdoc_put_documentElement(
1511 IXMLDOMDocument3 *iface,
1512 IXMLDOMElement* DOMElement )
1514 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1515 IXMLDOMNode *elementNode;
1520 TRACE("(%p)->(%p)\n", This, DOMElement);
1522 hr = IXMLDOMElement_QueryInterface( DOMElement, &IID_IXMLDOMNode, (void**)&elementNode );
1526 xmlNode = get_node_obj( elementNode );
1528 FIXME("elementNode is not our object\n");
1532 if(!xmlNode->node->parent)
1533 if(xmldoc_remove_orphan(xmlNode->node->doc, xmlNode->node) != S_OK)
1534 WARN("%p is not an orphan of %p\n", xmlNode->node->doc, xmlNode->node);
1536 oldRoot = xmlDocSetRootElement( get_doc(This), xmlNode->node);
1537 IXMLDOMNode_Release( elementNode );
1540 xmldoc_add_orphan(oldRoot->doc, oldRoot);
1546 static HRESULT WINAPI domdoc_createElement(
1547 IXMLDOMDocument3 *iface,
1549 IXMLDOMElement** element )
1551 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1556 TRACE("(%p)->(%s %p)\n", This, debugstr_w(tagname), element);
1558 if (!element || !tagname) return E_INVALIDARG;
1560 V_VT(&type) = VT_I1;
1561 V_I1(&type) = NODE_ELEMENT;
1563 hr = IXMLDOMDocument3_createNode(iface, type, tagname, NULL, &node);
1566 IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMElement, (void**)element);
1567 IXMLDOMNode_Release(node);
1574 static HRESULT WINAPI domdoc_createDocumentFragment(
1575 IXMLDOMDocument3 *iface,
1576 IXMLDOMDocumentFragment** frag )
1578 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1583 TRACE("(%p)->(%p)\n", This, frag);
1585 if (!frag) return E_INVALIDARG;
1589 V_VT(&type) = VT_I1;
1590 V_I1(&type) = NODE_DOCUMENT_FRAGMENT;
1592 hr = IXMLDOMDocument3_createNode(iface, type, NULL, NULL, &node);
1595 IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMDocumentFragment, (void**)frag);
1596 IXMLDOMNode_Release(node);
1603 static HRESULT WINAPI domdoc_createTextNode(
1604 IXMLDOMDocument3 *iface,
1606 IXMLDOMText** text )
1608 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1613 TRACE("(%p)->(%s %p)\n", This, debugstr_w(data), text);
1615 if (!text) return E_INVALIDARG;
1619 V_VT(&type) = VT_I1;
1620 V_I1(&type) = NODE_TEXT;
1622 hr = IXMLDOMDocument3_createNode(iface, type, NULL, NULL, &node);
1625 IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMText, (void**)text);
1626 IXMLDOMNode_Release(node);
1627 hr = IXMLDOMText_put_data(*text, data);
1634 static HRESULT WINAPI domdoc_createComment(
1635 IXMLDOMDocument3 *iface,
1637 IXMLDOMComment** comment )
1639 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1644 TRACE("(%p)->(%s %p)\n", This, debugstr_w(data), comment);
1646 if (!comment) return E_INVALIDARG;
1650 V_VT(&type) = VT_I1;
1651 V_I1(&type) = NODE_COMMENT;
1653 hr = IXMLDOMDocument3_createNode(iface, type, NULL, NULL, &node);
1656 IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMComment, (void**)comment);
1657 IXMLDOMNode_Release(node);
1658 hr = IXMLDOMComment_put_data(*comment, data);
1665 static HRESULT WINAPI domdoc_createCDATASection(
1666 IXMLDOMDocument3 *iface,
1668 IXMLDOMCDATASection** cdata )
1670 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1675 TRACE("(%p)->(%s %p)\n", This, debugstr_w(data), cdata);
1677 if (!cdata) return E_INVALIDARG;
1681 V_VT(&type) = VT_I1;
1682 V_I1(&type) = NODE_CDATA_SECTION;
1684 hr = IXMLDOMDocument3_createNode(iface, type, NULL, NULL, &node);
1687 IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMCDATASection, (void**)cdata);
1688 IXMLDOMNode_Release(node);
1689 hr = IXMLDOMCDATASection_put_data(*cdata, data);
1696 static HRESULT WINAPI domdoc_createProcessingInstruction(
1697 IXMLDOMDocument3 *iface,
1700 IXMLDOMProcessingInstruction** pi )
1702 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1707 TRACE("(%p)->(%s %s %p)\n", This, debugstr_w(target), debugstr_w(data), pi);
1709 if (!pi) return E_INVALIDARG;
1713 V_VT(&type) = VT_I1;
1714 V_I1(&type) = NODE_PROCESSING_INSTRUCTION;
1716 hr = IXMLDOMDocument3_createNode(iface, type, target, NULL, &node);
1721 /* this is to bypass check in ::put_data() that blocks "<?xml" PIs */
1722 node_obj = get_node_obj(node);
1723 hr = node_set_content(node_obj, data);
1725 IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMProcessingInstruction, (void**)pi);
1726 IXMLDOMNode_Release(node);
1733 static HRESULT WINAPI domdoc_createAttribute(
1734 IXMLDOMDocument3 *iface,
1736 IXMLDOMAttribute** attribute )
1738 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1743 TRACE("(%p)->(%s %p)\n", This, debugstr_w(name), attribute);
1745 if (!attribute || !name) return E_INVALIDARG;
1747 V_VT(&type) = VT_I1;
1748 V_I1(&type) = NODE_ATTRIBUTE;
1750 hr = IXMLDOMDocument3_createNode(iface, type, name, NULL, &node);
1753 IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMAttribute, (void**)attribute);
1754 IXMLDOMNode_Release(node);
1761 static HRESULT WINAPI domdoc_createEntityReference(
1762 IXMLDOMDocument3 *iface,
1764 IXMLDOMEntityReference** entityref )
1766 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1771 TRACE("(%p)->(%s %p)\n", This, debugstr_w(name), entityref);
1773 if (!entityref) return E_INVALIDARG;
1777 V_VT(&type) = VT_I1;
1778 V_I1(&type) = NODE_ENTITY_REFERENCE;
1780 hr = IXMLDOMDocument3_createNode(iface, type, name, NULL, &node);
1783 IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMEntityReference, (void**)entityref);
1784 IXMLDOMNode_Release(node);
1790 xmlChar* tagName_to_XPath(const BSTR tagName)
1792 xmlChar *query, *tmp;
1793 static const xmlChar mod_pre[] = "*[local-name()='";
1794 static const xmlChar mod_post[] = "']";
1795 static const xmlChar prefix[] = "descendant::";
1796 const WCHAR *tokBegin, *tokEnd;
1799 query = xmlStrdup(prefix);
1802 while (tokBegin && *tokBegin)
1807 query = xmlStrcat(query, BAD_CAST "/");
1811 query = xmlStrcat(query, BAD_CAST "*");
1815 query = xmlStrcat(query, mod_pre);
1817 while (*tokEnd && *tokEnd != '/')
1819 len = WideCharToMultiByte(CP_UTF8, 0, tokBegin, tokEnd-tokBegin, NULL, 0, NULL, NULL);
1820 tmp = xmlMalloc(len);
1821 WideCharToMultiByte(CP_UTF8, 0, tokBegin, tokEnd-tokBegin, (char*)tmp, len, NULL, NULL);
1822 query = xmlStrncat(query, tmp, len);
1825 query = xmlStrcat(query, mod_post);
1832 static HRESULT WINAPI domdoc_getElementsByTagName(
1833 IXMLDOMDocument3 *iface,
1835 IXMLDOMNodeList** resultList )
1837 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1842 TRACE("(%p)->(%s, %p)\n", This, debugstr_w(tagName), resultList);
1844 if (!tagName || !resultList) return E_INVALIDARG;
1846 XPath = This->properties->XPath;
1847 This->properties->XPath = TRUE;
1848 query = tagName_to_XPath(tagName);
1849 hr = queryresult_create((xmlNodePtr)get_doc(This), query, resultList);
1851 This->properties->XPath = XPath;
1856 static HRESULT get_node_type(VARIANT Type, DOMNodeType * type)
1862 hr = VariantChangeType(&tmp, &Type, 0, VT_I4);
1864 return E_INVALIDARG;
1871 static HRESULT WINAPI domdoc_createNode(
1872 IXMLDOMDocument3 *iface,
1876 IXMLDOMNode** node )
1878 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1879 DOMNodeType node_type;
1881 xmlChar *xml_name, *href;
1884 TRACE("(%p)->(%s %s %p)\n", This, debugstr_w(name), debugstr_w(namespaceURI), node);
1886 if(!node) return E_INVALIDARG;
1888 hr = get_node_type(Type, &node_type);
1889 if(FAILED(hr)) return hr;
1891 if(namespaceURI && namespaceURI[0] && node_type != NODE_ELEMENT)
1892 FIXME("nodes with namespaces currently not supported.\n");
1894 TRACE("node_type %d\n", node_type);
1896 /* exit earlier for types that need name */
1900 case NODE_ATTRIBUTE:
1901 case NODE_ENTITY_REFERENCE:
1902 case NODE_PROCESSING_INSTRUCTION:
1903 if (!name || *name == 0) return E_FAIL;
1908 xml_name = xmlChar_from_wchar(name);
1909 /* prevent empty href to be allocated */
1910 href = namespaceURI ? xmlChar_from_wchar(namespaceURI) : NULL;
1916 xmlChar *local, *prefix;
1918 local = xmlSplitQName2(xml_name, &prefix);
1920 xmlnode = xmlNewDocNode(get_doc(This), NULL, local ? local : xml_name, NULL);
1922 /* allow to create default namespace xmlns= */
1923 if (local || (href && *href))
1925 xmlNsPtr ns = xmlNewNs(xmlnode, href, prefix);
1926 xmlSetNs(xmlnode, ns);
1934 case NODE_ATTRIBUTE:
1935 xmlnode = (xmlNodePtr)xmlNewDocProp(get_doc(This), xml_name, NULL);
1938 xmlnode = (xmlNodePtr)xmlNewDocText(get_doc(This), NULL);
1940 case NODE_CDATA_SECTION:
1941 xmlnode = xmlNewCDataBlock(get_doc(This), NULL, 0);
1943 case NODE_ENTITY_REFERENCE:
1944 xmlnode = xmlNewReference(get_doc(This), xml_name);
1946 case NODE_PROCESSING_INSTRUCTION:
1947 #ifdef HAVE_XMLNEWDOCPI
1948 xmlnode = xmlNewDocPI(get_doc(This), xml_name, NULL);
1950 FIXME("xmlNewDocPI() not supported, use libxml2 2.6.15 or greater\n");
1955 xmlnode = xmlNewDocComment(get_doc(This), NULL);
1957 case NODE_DOCUMENT_FRAGMENT:
1958 xmlnode = xmlNewDocFragment(get_doc(This));
1960 /* unsupported types */
1962 case NODE_DOCUMENT_TYPE:
1965 heap_free(xml_name);
1966 return E_INVALIDARG;
1968 FIXME("unhandled node type %d\n", node_type);
1973 *node = create_node(xmlnode);
1974 heap_free(xml_name);
1979 TRACE("created node (%d, %p, %p)\n", node_type, *node, xmlnode);
1980 xmldoc_add_orphan(xmlnode->doc, xmlnode);
1987 static HRESULT WINAPI domdoc_nodeFromID(
1988 IXMLDOMDocument3 *iface,
1990 IXMLDOMNode** node )
1992 domdoc *This = impl_from_IXMLDOMDocument3(iface);
1993 FIXME("(%p)->(%s %p)\n", This, debugstr_w(idString), node);
1997 static HRESULT domdoc_onDataAvailable(void *obj, char *ptr, DWORD len)
2002 xmldoc = doparse(This, ptr, len, NULL);
2004 xmldoc->_private = create_priv();
2005 return attach_xmldoc(This, xmldoc);
2011 static HRESULT doread( domdoc *This, LPWSTR filename )
2016 hr = bind_url(filename, domdoc_onDataAvailable, This, &bsc);
2021 detach_bsc(This->bsc);
2027 static HRESULT WINAPI domdoc_load(
2028 IXMLDOMDocument3 *iface,
2030 VARIANT_BOOL* isSuccessful )
2032 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2033 LPWSTR filename = NULL;
2034 HRESULT hr = S_FALSE;
2035 IXMLDOMDocument3 *pNewDoc = NULL;
2036 IStream *pStream = NULL;
2039 TRACE("(%p)->type %d\n", This, V_VT(&xmlSource) );
2041 *isSuccessful = VARIANT_FALSE;
2043 assert( &This->node );
2045 switch( V_VT(&xmlSource) )
2048 filename = V_BSTR(&xmlSource);
2051 hr = IUnknown_QueryInterface(V_UNKNOWN(&xmlSource), &IID_IXMLDOMDocument3, (void**)&pNewDoc);
2056 domdoc *newDoc = impl_from_IXMLDOMDocument3( pNewDoc );
2057 xmldoc = xmlCopyDoc(get_doc(newDoc), 1);
2058 hr = attach_xmldoc(This, xmldoc);
2061 *isSuccessful = VARIANT_TRUE;
2066 hr = IUnknown_QueryInterface(V_UNKNOWN(&xmlSource), &IID_IStream, (void**)&pStream);
2069 IPersistStream *pDocStream;
2070 hr = IUnknown_QueryInterface(iface, &IID_IPersistStream, (void**)&pDocStream);
2073 hr = IPersistStream_Load(pDocStream, pStream);
2074 IStream_Release(pStream);
2077 *isSuccessful = VARIANT_TRUE;
2079 TRACE("Using IStream to load Document\n");
2084 ERR("xmldoc_IPersistStream_Load failed (%d)\n", hr);
2089 ERR("QueryInterface IID_IPersistStream failed (%d)\n", hr);
2094 /* ISequentialStream */
2095 FIXME("Unknown type not supported (%d) (%p)(%p)\n", hr, pNewDoc, V_UNKNOWN(&xmlSource)->lpVtbl);
2099 FIXME("VT type not supported (%d)\n", V_VT(&xmlSource));
2102 TRACE("filename (%s)\n", debugstr_w(filename));
2106 hr = doread( This, filename );
2109 This->error = E_FAIL;
2112 hr = This->error = S_OK;
2113 *isSuccessful = VARIANT_TRUE;
2117 if(!filename || FAILED(hr)) {
2118 xmldoc = xmlNewDoc(NULL);
2119 xmldoc->_private = create_priv();
2120 hr = attach_xmldoc(This, xmldoc);
2125 TRACE("ret (%d)\n", hr);
2131 static HRESULT WINAPI domdoc_get_readyState(
2132 IXMLDOMDocument3 *iface,
2135 domdoc *This = impl_from_IXMLDOMDocument3(iface);
2136 FIXME("stub! (%p)->(%p)\n", This, value);
2139 return E_INVALIDARG;
2141 *value = READYSTATE_COMPLETE;
2146 static HRESULT WINAPI domdoc_get_parseError(
2147 IXMLDOMDocument3 *iface,
2148 IXMLDOMParseError** errorObj )
2150 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2151 static const WCHAR err[] = {'e','r','r','o','r',0};
2152 BSTR error_string = NULL;
2154 FIXME("(%p)->(%p): creating a dummy parseError\n", iface, errorObj);
2157 error_string = SysAllocString(err);
2159 *errorObj = create_parseError(This->error, NULL, error_string, NULL, 0, 0, 0);
2160 if(!*errorObj) return E_OUTOFMEMORY;
2165 static HRESULT WINAPI domdoc_get_url(
2166 IXMLDOMDocument3 *iface,
2169 domdoc *This = impl_from_IXMLDOMDocument3(iface);
2170 FIXME("(%p)->(%p)\n", This, urlString);
2175 static HRESULT WINAPI domdoc_get_async(
2176 IXMLDOMDocument3 *iface,
2177 VARIANT_BOOL* isAsync )
2179 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2181 TRACE("(%p)->(%p: %d)\n", This, isAsync, This->async);
2182 *isAsync = This->async;
2187 static HRESULT WINAPI domdoc_put_async(
2188 IXMLDOMDocument3 *iface,
2189 VARIANT_BOOL isAsync )
2191 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2193 TRACE("(%p)->(%d)\n", This, isAsync);
2194 This->async = isAsync;
2199 static HRESULT WINAPI domdoc_abort(
2200 IXMLDOMDocument3 *iface )
2202 domdoc *This = impl_from_IXMLDOMDocument3(iface);
2203 FIXME("%p\n", This);
2208 static BOOL bstr_to_utf8( BSTR bstr, char **pstr, int *plen )
2213 len = WideCharToMultiByte( CP_UTF8, 0, bstr, -1, NULL, 0, NULL, NULL );
2214 str = heap_alloc( len );
2217 WideCharToMultiByte( CP_UTF8, 0, bstr, -1, str, len, NULL, NULL );
2223 /* don't rely on data to be in BSTR format, treat it as WCHAR string */
2224 static HRESULT WINAPI domdoc_loadXML(
2225 IXMLDOMDocument3 *iface,
2227 VARIANT_BOOL* isSuccessful )
2229 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2230 static const xmlChar encoding[] = "UTF-8";
2231 xmlDocPtr xmldoc = NULL;
2232 HRESULT hr = S_FALSE, hr2;
2236 TRACE("(%p)->(%s %p)\n", This, debugstr_w( bstrXML ), isSuccessful );
2238 assert ( &This->node );
2242 *isSuccessful = VARIANT_FALSE;
2244 if ( bstrXML && bstr_to_utf8( bstrXML, &str, &len ) )
2246 xmldoc = doparse(This, str, len, encoding);
2250 This->error = E_FAIL;
2251 TRACE("failed to parse document\n");
2255 hr = This->error = S_OK;
2256 *isSuccessful = VARIANT_TRUE;
2257 TRACE("parsed document %p\n", xmldoc);
2262 xmldoc = xmlNewDoc(NULL);
2264 xmldoc->_private = create_priv();
2266 hr2 = attach_xmldoc(This, xmldoc);
2273 static int XMLCALL domdoc_save_writecallback(void *ctx, const char *buffer, int len)
2277 if(!WriteFile(ctx, buffer, len, &written, NULL))
2279 WARN("write error\n");
2286 static int XMLCALL domdoc_save_closecallback(void *ctx)
2288 return CloseHandle(ctx) ? 0 : -1;
2291 static int XMLCALL domdoc_stream_save_writecallback(void *ctx, const char *buffer, int len)
2296 hr = IStream_Write((IStream*)ctx, buffer, len, &written);
2299 WARN("stream write error: 0x%08x\n", hr);
2306 static int XMLCALL domdoc_stream_save_closecallback(void *ctx)
2308 IStream_Release((IStream*)ctx);
2312 static HRESULT WINAPI domdoc_save(
2313 IXMLDOMDocument3 *iface,
2314 VARIANT destination )
2316 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2317 xmlSaveCtxtPtr ctx = NULL;
2321 TRACE("(%p)->(var(vt %d, %s))\n", This, V_VT(&destination),
2322 V_VT(&destination) == VT_BSTR ? debugstr_w(V_BSTR(&destination)) : NULL);
2324 if(V_VT(&destination) != VT_BSTR && V_VT(&destination) != VT_UNKNOWN)
2326 FIXME("Unhandled vt %d\n", V_VT(&destination));
2330 if(V_VT(&destination) == VT_UNKNOWN)
2332 IUnknown *pUnk = V_UNKNOWN(&destination);
2333 IXMLDOMDocument2 *document;
2336 ret = IUnknown_QueryInterface(pUnk, &IID_IXMLDOMDocument3, (void**)&document);
2339 VARIANT_BOOL success;
2342 ret = IXMLDOMDocument3_get_xml(iface, &xml);
2345 ret = IXMLDOMDocument3_loadXML(document, xml, &success);
2349 IXMLDOMDocument3_Release(document);
2353 ret = IUnknown_QueryInterface(pUnk, &IID_IStream, (void**)&stream);
2356 ctx = xmlSaveToIO(domdoc_stream_save_writecallback,
2357 domdoc_stream_save_closecallback, stream, NULL, XML_SAVE_NO_DECL);
2361 IStream_Release(stream);
2368 /* save with file path */
2369 HANDLE handle = CreateFileW( V_BSTR(&destination), GENERIC_WRITE, 0,
2370 NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL );
2371 if( handle == INVALID_HANDLE_VALUE )
2373 WARN("failed to create file\n");
2377 /* disable top XML declaration */
2378 ctx = xmlSaveToIO(domdoc_save_writecallback, domdoc_save_closecallback,
2379 handle, NULL, XML_SAVE_NO_DECL);
2382 CloseHandle(handle);
2387 xmldecl = xmldoc_unlink_xmldecl(get_doc(This));
2388 if (xmlSaveDoc(ctx, get_doc(This)) == -1) ret = S_FALSE;
2389 xmldoc_link_xmldecl(get_doc(This), xmldecl);
2391 /* will release resources through close callback */
2397 static HRESULT WINAPI domdoc_get_validateOnParse(
2398 IXMLDOMDocument3 *iface,
2399 VARIANT_BOOL* isValidating )
2401 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2402 TRACE("(%p)->(%p: %d)\n", This, isValidating, This->validating);
2403 *isValidating = This->validating;
2408 static HRESULT WINAPI domdoc_put_validateOnParse(
2409 IXMLDOMDocument3 *iface,
2410 VARIANT_BOOL isValidating )
2412 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2413 TRACE("(%p)->(%d)\n", This, isValidating);
2414 This->validating = isValidating;
2419 static HRESULT WINAPI domdoc_get_resolveExternals(
2420 IXMLDOMDocument3 *iface,
2421 VARIANT_BOOL* isResolving )
2423 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2424 TRACE("(%p)->(%p: %d)\n", This, isResolving, This->resolving);
2425 *isResolving = This->resolving;
2430 static HRESULT WINAPI domdoc_put_resolveExternals(
2431 IXMLDOMDocument3 *iface,
2432 VARIANT_BOOL isResolving )
2434 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2435 TRACE("(%p)->(%d)\n", This, isResolving);
2436 This->resolving = isResolving;
2441 static HRESULT WINAPI domdoc_get_preserveWhiteSpace(
2442 IXMLDOMDocument3 *iface,
2443 VARIANT_BOOL* isPreserving )
2445 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2446 TRACE("(%p)->(%p: %d)\n", This, isPreserving, This->properties->preserving);
2447 *isPreserving = This->properties->preserving;
2452 static HRESULT WINAPI domdoc_put_preserveWhiteSpace(
2453 IXMLDOMDocument3 *iface,
2454 VARIANT_BOOL isPreserving )
2456 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2457 TRACE("(%p)->(%d)\n", This, isPreserving);
2458 This->properties->preserving = isPreserving;
2463 static HRESULT WINAPI domdoc_put_onReadyStateChange(
2464 IXMLDOMDocument3 *iface,
2465 VARIANT readyStateChangeSink )
2467 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2468 FIXME("%p\n", This);
2473 static HRESULT WINAPI domdoc_put_onDataAvailable(
2474 IXMLDOMDocument3 *iface,
2475 VARIANT onDataAvailableSink )
2477 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2478 FIXME("%p\n", This);
2482 static HRESULT WINAPI domdoc_put_onTransformNode(
2483 IXMLDOMDocument3 *iface,
2484 VARIANT onTransformNodeSink )
2486 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2487 FIXME("%p\n", This);
2491 static HRESULT WINAPI domdoc_get_namespaces(
2492 IXMLDOMDocument3* iface,
2493 IXMLDOMSchemaCollection** schemaCollection )
2495 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2496 FIXME("(%p)->(%p)\n", This, schemaCollection);
2500 static HRESULT WINAPI domdoc_get_schemas(
2501 IXMLDOMDocument3* iface,
2504 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2505 HRESULT hr = S_FALSE;
2506 IXMLDOMSchemaCollection2* cur_schema = This->properties->schemaCache;
2508 TRACE("(%p)->(%p)\n", This, var1);
2510 VariantInit(var1); /* Test shows we don't call VariantClear here */
2511 V_VT(var1) = VT_NULL;
2515 hr = IXMLDOMSchemaCollection2_QueryInterface(cur_schema, &IID_IDispatch, (void**)&V_DISPATCH(var1));
2517 V_VT(var1) = VT_DISPATCH;
2522 static HRESULT WINAPI domdoc_putref_schemas(
2523 IXMLDOMDocument3* iface,
2526 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2527 HRESULT hr = E_FAIL;
2528 IXMLDOMSchemaCollection2* new_schema = NULL;
2530 FIXME("(%p): semi-stub\n", This);
2534 hr = IUnknown_QueryInterface(V_UNKNOWN(&var1), &IID_IXMLDOMSchemaCollection, (void**)&new_schema);
2538 hr = IDispatch_QueryInterface(V_DISPATCH(&var1), &IID_IXMLDOMSchemaCollection, (void**)&new_schema);
2547 WARN("Can't get schema from vt %x\n", V_VT(&var1));
2552 IXMLDOMSchemaCollection2* old_schema = InterlockedExchangePointer((void**)&This->properties->schemaCache, new_schema);
2553 if(old_schema) IXMLDOMSchemaCollection2_Release(old_schema);
2559 static inline BOOL is_wellformed(xmlDocPtr doc)
2561 #ifdef HAVE_XMLDOC_PROPERTIES
2562 return doc->properties & XML_DOC_WELLFORMED;
2564 /* Not a full check, but catches the worst violations */
2568 for (child = doc->children; child != NULL; child = child->next)
2570 switch (child->type)
2572 case XML_ELEMENT_NODE:
2577 case XML_CDATA_SECTION_NODE:
2589 static void LIBXML2_LOG_CALLBACK validate_error(void* ctx, char const* msg, ...)
2593 LIBXML2_CALLBACK_ERR(domdoc_validateNode, msg, ap);
2597 static void LIBXML2_LOG_CALLBACK validate_warning(void* ctx, char const* msg, ...)
2601 LIBXML2_CALLBACK_WARN(domdoc_validateNode, msg, ap);
2605 static HRESULT WINAPI domdoc_validateNode(
2606 IXMLDOMDocument3* iface,
2608 IXMLDOMParseError** err)
2610 domdoc* This = impl_from_IXMLDOMDocument3(iface);
2611 LONG state, err_code = 0;
2615 TRACE("(%p)->(%p, %p)\n", This, node, err);
2616 domdoc_get_readyState(iface, &state);
2617 if (state != READYSTATE_COMPLETE)
2620 *err = create_parseError(err_code, NULL, NULL, NULL, 0, 0, 0);
2627 *err = create_parseError(err_code, NULL, NULL, NULL, 0, 0, 0);
2631 if (!get_node_obj(node)->node || get_node_obj(node)->node->doc != get_doc(This))
2634 *err = create_parseError(err_code, NULL, NULL, NULL, 0, 0, 0);
2638 if (!is_wellformed(get_doc(This)))
2640 ERR("doc not well-formed");
2642 *err = create_parseError(E_XML_NOTWF, NULL, NULL, NULL, 0, 0, 0);
2646 /* DTD validation */
2647 if (get_doc(This)->intSubset || get_doc(This)->extSubset)
2649 xmlValidCtxtPtr vctx = xmlNewValidCtxt();
2650 vctx->error = validate_error;
2651 vctx->warning = validate_warning;
2654 if (!((node == (IXMLDOMNode*)iface)?
2655 xmlValidateDocument(vctx, get_doc(This)) :
2656 xmlValidateElement(vctx, get_doc(This), get_node_obj(node)->node)))
2658 /* TODO: get a real error code here */
2659 TRACE("DTD validation failed\n");
2660 err_code = E_XML_INVALID;
2663 xmlFreeValidCtxt(vctx);
2666 /* Schema validation */
2667 if (hr == S_OK && This->properties->schemaCache != NULL)
2670 hr = SchemaCache_validate_tree(This->properties->schemaCache, get_node_obj(node)->node);
2674 /* TODO: get a real error code here */
2677 TRACE("schema validation succeeded\n");
2681 ERR("schema validation failed\n");
2682 err_code = E_XML_INVALID;
2687 /* not really OK, just didn't find a schema for the ns */
2694 ERR("no DTD or schema found\n");
2695 err_code = E_XML_NODTD;
2700 *err = create_parseError(err_code, NULL, NULL, NULL, 0, 0, 0);
2705 static HRESULT WINAPI domdoc_validate(
2706 IXMLDOMDocument3* iface,
2707 IXMLDOMParseError** err)
2709 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2710 TRACE("(%p)->(%p)\n", This, err);
2711 return domdoc_validateNode(iface, (IXMLDOMNode*)iface, err);
2714 static HRESULT WINAPI domdoc_setProperty(
2715 IXMLDOMDocument3* iface,
2719 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2721 TRACE("(%p)->(%s)\n", This, debugstr_w(p));
2723 if (lstrcmpiW(p, PropertySelectionLanguageW) == 0)
2729 V_VT(&varStr) = VT_EMPTY;
2730 if (V_VT(&var) != VT_BSTR)
2732 if (FAILED(hr = VariantChangeType(&varStr, &var, 0, VT_BSTR)))
2734 bstr = V_BSTR(&varStr);
2737 bstr = V_BSTR(&var);
2740 if (lstrcmpiW(bstr, PropValueXPathW) == 0)
2741 This->properties->XPath = TRUE;
2742 else if (lstrcmpiW(bstr, PropValueXSLPatternW) == 0)
2743 This->properties->XPath = FALSE;
2747 VariantClear(&varStr);
2750 else if (lstrcmpiW(p, PropertySelectionNamespacesW) == 0)
2755 xmlChar *pTokBegin, *pTokEnd, *pTokInner;
2756 xmlChar *nsStr = (xmlChar*)This->properties->selectNsStr;
2757 xmlXPathContextPtr ctx;
2758 struct list *pNsList;
2759 select_ns_entry* pNsEntry = NULL;
2761 V_VT(&varStr) = VT_EMPTY;
2762 if (V_VT(&var) != VT_BSTR)
2764 if (FAILED(hr = VariantChangeType(&varStr, &var, 0, VT_BSTR)))
2766 bstr = V_BSTR(&varStr);
2769 bstr = V_BSTR(&var);
2773 pNsList = &(This->properties->selectNsList);
2774 clear_selectNsList(pNsList);
2776 nsStr = xmlChar_from_wchar(bstr);
2779 TRACE("Setting SelectionNamespaces property to: %s\n", nsStr);
2781 This->properties->selectNsStr = nsStr;
2782 This->properties->selectNsStr_len = xmlStrlen(nsStr);
2785 ctx = xmlXPathNewContext(This->node.node->doc);
2788 for (; *pTokBegin; pTokBegin = pTokEnd)
2790 if (pNsEntry != NULL)
2791 memset(pNsEntry, 0, sizeof(select_ns_entry));
2793 pNsEntry = heap_alloc_zero(sizeof(select_ns_entry));
2795 while (*pTokBegin == ' ')
2797 pTokEnd = pTokBegin;
2798 while (*pTokEnd != ' ' && *pTokEnd != 0)
2801 if (xmlStrncmp(pTokBegin, (xmlChar const*)"xmlns", 5) != 0)
2804 WARN("Syntax error in xmlns string: %s\n\tat token: %s\n",
2805 wine_dbgstr_w(bstr), wine_dbgstr_an((const char*)pTokBegin, pTokEnd-pTokBegin));
2810 if (*pTokBegin == '=')
2812 /*valid for XSLPattern?*/
2813 FIXME("Setting default xmlns not supported - skipping.\n");
2814 pTokBegin = pTokEnd;
2817 else if (*pTokBegin == ':')
2819 pNsEntry->prefix = ++pTokBegin;
2820 for (pTokInner = pTokBegin; pTokInner != pTokEnd && *pTokInner != '='; ++pTokInner)
2823 if (pTokInner == pTokEnd)
2826 WARN("Syntax error in xmlns string: %s\n\tat token: %s\n",
2827 wine_dbgstr_w(bstr), wine_dbgstr_an((const char*)pTokBegin, pTokEnd-pTokBegin));
2831 pNsEntry->prefix_end = *pTokInner;
2835 if (pTokEnd-pTokInner > 1 &&
2836 ((*pTokInner == '\'' && *(pTokEnd-1) == '\'') ||
2837 (*pTokInner == '"' && *(pTokEnd-1) == '"')))
2839 pNsEntry->href = ++pTokInner;
2840 pNsEntry->href_end = *(pTokEnd-1);
2842 list_add_tail(pNsList, &pNsEntry->entry);
2843 /*let libxml figure out if they're valid from here ;)*/
2844 if (xmlXPathRegisterNs(ctx, pNsEntry->prefix, pNsEntry->href) != 0)
2853 WARN("Syntax error in xmlns string: %s\n\tat token: %s\n",
2854 wine_dbgstr_w(bstr), wine_dbgstr_an((const char*)pTokInner, pTokEnd-pTokInner));
2855 list_add_tail(pNsList, &pNsEntry->entry);
2868 heap_free(pNsEntry);
2869 xmlXPathFreeContext(ctx);
2872 VariantClear(&varStr);
2875 else if (lstrcmpiW(p, PropertyProhibitDTDW) == 0 ||
2876 lstrcmpiW(p, PropertyNewParserW) == 0)
2879 FIXME("Ignoring property %s, value %d\n", debugstr_w(p), V_BOOL(&var));
2883 FIXME("Unknown property %s\n", wine_dbgstr_w(p));
2887 static HRESULT WINAPI domdoc_getProperty(
2888 IXMLDOMDocument3* iface,
2892 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2894 TRACE("(%p)->(%p)\n", This, debugstr_w(p));
2897 return E_INVALIDARG;
2899 if (lstrcmpiW(p, PropertySelectionLanguageW) == 0)
2901 V_VT(var) = VT_BSTR;
2902 V_BSTR(var) = This->properties->XPath ?
2903 SysAllocString(PropValueXPathW) :
2904 SysAllocString(PropValueXSLPatternW);
2905 return V_BSTR(var) ? S_OK : E_OUTOFMEMORY;
2907 else if (lstrcmpiW(p, PropertySelectionNamespacesW) == 0)
2910 BSTR rebuiltStr, cur;
2911 const xmlChar *nsStr;
2912 struct list *pNsList;
2913 select_ns_entry* pNsEntry;
2915 V_VT(var) = VT_BSTR;
2916 nsStr = This->properties->selectNsStr;
2917 pNsList = &This->properties->selectNsList;
2918 lenA = This->properties->selectNsStr_len;
2919 lenW = MultiByteToWideChar(CP_UTF8, 0, (LPCSTR)nsStr, lenA+1, NULL, 0);
2920 rebuiltStr = heap_alloc(lenW*sizeof(WCHAR));
2921 MultiByteToWideChar(CP_UTF8, 0, (LPCSTR)nsStr, lenA+1, rebuiltStr, lenW);
2923 /* this is fine because all of the chars that end tokens are ASCII*/
2924 LIST_FOR_EACH_ENTRY(pNsEntry, pNsList, select_ns_entry, entry)
2926 while (*cur != 0) ++cur;
2927 if (pNsEntry->prefix_end)
2929 *cur = pNsEntry->prefix_end;
2930 while (*cur != 0) ++cur;
2933 if (pNsEntry->href_end)
2935 *cur = pNsEntry->href_end;
2938 V_BSTR(var) = SysAllocString(rebuiltStr);
2939 heap_free(rebuiltStr);
2943 FIXME("Unknown property %s\n", wine_dbgstr_w(p));
2947 static HRESULT WINAPI domdoc_importNode(
2948 IXMLDOMDocument3* iface,
2951 IXMLDOMNode** clone)
2953 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2954 FIXME("(%p)->(%p %d %p): stub\n", This, node, deep, clone);
2958 static const struct IXMLDOMDocument3Vtbl domdoc_vtbl =
2960 domdoc_QueryInterface,
2963 domdoc_GetTypeInfoCount,
2965 domdoc_GetIDsOfNames,
2967 domdoc_get_nodeName,
2968 domdoc_get_nodeValue,
2969 domdoc_put_nodeValue,
2970 domdoc_get_nodeType,
2971 domdoc_get_parentNode,
2972 domdoc_get_childNodes,
2973 domdoc_get_firstChild,
2974 domdoc_get_lastChild,
2975 domdoc_get_previousSibling,
2976 domdoc_get_nextSibling,
2977 domdoc_get_attributes,
2978 domdoc_insertBefore,
2979 domdoc_replaceChild,
2982 domdoc_hasChildNodes,
2983 domdoc_get_ownerDocument,
2985 domdoc_get_nodeTypeString,
2988 domdoc_get_specified,
2989 domdoc_get_definition,
2990 domdoc_get_nodeTypedValue,
2991 domdoc_put_nodeTypedValue,
2992 domdoc_get_dataType,
2993 domdoc_put_dataType,
2995 domdoc_transformNode,
2997 domdoc_selectSingleNode,
2999 domdoc_get_namespaceURI,
3001 domdoc_get_baseName,
3002 domdoc_transformNodeToObject,
3004 domdoc_get_implementation,
3005 domdoc_get_documentElement,
3006 domdoc_put_documentElement,
3007 domdoc_createElement,
3008 domdoc_createDocumentFragment,
3009 domdoc_createTextNode,
3010 domdoc_createComment,
3011 domdoc_createCDATASection,
3012 domdoc_createProcessingInstruction,
3013 domdoc_createAttribute,
3014 domdoc_createEntityReference,
3015 domdoc_getElementsByTagName,
3019 domdoc_get_readyState,
3020 domdoc_get_parseError,
3027 domdoc_get_validateOnParse,
3028 domdoc_put_validateOnParse,
3029 domdoc_get_resolveExternals,
3030 domdoc_put_resolveExternals,
3031 domdoc_get_preserveWhiteSpace,
3032 domdoc_put_preserveWhiteSpace,
3033 domdoc_put_onReadyStateChange,
3034 domdoc_put_onDataAvailable,
3035 domdoc_put_onTransformNode,
3036 domdoc_get_namespaces,
3038 domdoc_putref_schemas,
3042 domdoc_validateNode,
3046 /* IConnectionPointContainer */
3047 static HRESULT WINAPI ConnectionPointContainer_QueryInterface(IConnectionPointContainer *iface,
3048 REFIID riid, void **ppv)
3050 domdoc *This = impl_from_IConnectionPointContainer(iface);
3051 return IXMLDOMDocument3_QueryInterface((IXMLDOMDocument3*)This, riid, ppv);
3054 static ULONG WINAPI ConnectionPointContainer_AddRef(IConnectionPointContainer *iface)
3056 domdoc *This = impl_from_IConnectionPointContainer(iface);
3057 return IXMLDOMDocument3_AddRef((IXMLDOMDocument3*)This);
3060 static ULONG WINAPI ConnectionPointContainer_Release(IConnectionPointContainer *iface)
3062 domdoc *This = impl_from_IConnectionPointContainer(iface);
3063 return IXMLDOMDocument3_Release((IXMLDOMDocument3*)This);
3066 static HRESULT WINAPI ConnectionPointContainer_EnumConnectionPoints(IConnectionPointContainer *iface,
3067 IEnumConnectionPoints **ppEnum)
3069 domdoc *This = impl_from_IConnectionPointContainer(iface);
3070 FIXME("(%p)->(%p): stub\n", This, ppEnum);
3074 static HRESULT WINAPI ConnectionPointContainer_FindConnectionPoint(IConnectionPointContainer *iface,
3075 REFIID riid, IConnectionPoint **cp)
3077 domdoc *This = impl_from_IConnectionPointContainer(iface);
3078 ConnectionPoint *iter;
3080 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), cp);
3084 for(iter = This->cp_list; iter; iter = iter->next)
3086 if (IsEqualGUID(iter->iid, riid))
3087 *cp = (IConnectionPoint*)&iter->lpVtblConnectionPoint;
3092 IConnectionPoint_AddRef(*cp);
3096 FIXME("unsupported riid %s\n", debugstr_guid(riid));
3097 return CONNECT_E_NOCONNECTION;
3101 static const struct IConnectionPointContainerVtbl ConnectionPointContainerVtbl =
3103 ConnectionPointContainer_QueryInterface,
3104 ConnectionPointContainer_AddRef,
3105 ConnectionPointContainer_Release,
3106 ConnectionPointContainer_EnumConnectionPoints,
3107 ConnectionPointContainer_FindConnectionPoint
3110 /* IConnectionPoint */
3111 static HRESULT WINAPI ConnectionPoint_QueryInterface(IConnectionPoint *iface,
3112 REFIID riid, void **ppv)
3114 ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3116 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv );
3120 if (IsEqualGUID(&IID_IUnknown, riid) ||
3121 IsEqualGUID(&IID_IConnectionPoint, riid))
3128 IConnectionPoint_AddRef(iface);
3132 WARN("Unsupported interface %s\n", debugstr_guid(riid));
3133 return E_NOINTERFACE;
3136 static ULONG WINAPI ConnectionPoint_AddRef(IConnectionPoint *iface)
3138 ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3139 return IConnectionPointContainer_AddRef(This->container);
3142 static ULONG WINAPI ConnectionPoint_Release(IConnectionPoint *iface)
3144 ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3145 return IConnectionPointContainer_Release(This->container);
3148 static HRESULT WINAPI ConnectionPoint_GetConnectionInterface(IConnectionPoint *iface, IID *iid)
3150 ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3152 TRACE("(%p)->(%p)\n", This, iid);
3154 if (!iid) return E_POINTER;
3160 static HRESULT WINAPI ConnectionPoint_GetConnectionPointContainer(IConnectionPoint *iface,
3161 IConnectionPointContainer **container)
3163 ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3165 TRACE("(%p)->(%p)\n", This, container);
3167 if (!container) return E_POINTER;
3169 *container = This->container;
3170 IConnectionPointContainer_AddRef(*container);
3174 static HRESULT WINAPI ConnectionPoint_Advise(IConnectionPoint *iface, IUnknown *pUnkSink,
3177 ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3178 FIXME("(%p)->(%p %p): stub\n", This, pUnkSink, pdwCookie);
3182 static HRESULT WINAPI ConnectionPoint_Unadvise(IConnectionPoint *iface, DWORD cookie)
3184 ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3186 TRACE("(%p)->(%d)\n", This, cookie);
3188 if (cookie == 0 || cookie > This->sinks_size || !This->sinks[cookie-1].unk)
3189 return CONNECT_E_NOCONNECTION;
3191 IUnknown_Release(This->sinks[cookie-1].unk);
3192 This->sinks[cookie-1].unk = NULL;
3197 static HRESULT WINAPI ConnectionPoint_EnumConnections(IConnectionPoint *iface,
3198 IEnumConnections **ppEnum)
3200 ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3201 FIXME("(%p)->(%p): stub\n", This, ppEnum);
3205 static const IConnectionPointVtbl ConnectionPointVtbl =
3207 ConnectionPoint_QueryInterface,
3208 ConnectionPoint_AddRef,
3209 ConnectionPoint_Release,
3210 ConnectionPoint_GetConnectionInterface,
3211 ConnectionPoint_GetConnectionPointContainer,
3212 ConnectionPoint_Advise,
3213 ConnectionPoint_Unadvise,
3214 ConnectionPoint_EnumConnections
3217 void ConnectionPoint_Init(ConnectionPoint *cp, struct domdoc *doc, REFIID riid)
3219 cp->lpVtblConnectionPoint = &ConnectionPointVtbl;
3225 cp->next = doc->cp_list;
3228 cp->container = (IConnectionPointContainer*)&doc->lpVtblConnectionPointContainer;
3231 /* domdoc implementation of IObjectWithSite */
3232 static HRESULT WINAPI
3233 domdoc_ObjectWithSite_QueryInterface( IObjectWithSite* iface, REFIID riid, void** ppvObject )
3235 domdoc *This = impl_from_IObjectWithSite(iface);
3236 return IXMLDOMDocument3_QueryInterface( (IXMLDOMDocument3 *)This, riid, ppvObject );
3239 static ULONG WINAPI domdoc_ObjectWithSite_AddRef( IObjectWithSite* iface )
3241 domdoc *This = impl_from_IObjectWithSite(iface);
3242 return IXMLDOMDocument3_AddRef((IXMLDOMDocument3 *)This);
3245 static ULONG WINAPI domdoc_ObjectWithSite_Release( IObjectWithSite* iface )
3247 domdoc *This = impl_from_IObjectWithSite(iface);
3248 return IXMLDOMDocument3_Release((IXMLDOMDocument3 *)This);
3251 static HRESULT WINAPI domdoc_ObjectWithSite_GetSite( IObjectWithSite *iface, REFIID iid, void **ppvSite )
3253 domdoc *This = impl_from_IObjectWithSite(iface);
3255 TRACE("(%p)->(%s %p)\n", This, debugstr_guid( iid ), ppvSite );
3260 return IUnknown_QueryInterface( This->site, iid, ppvSite );
3263 static HRESULT WINAPI domdoc_ObjectWithSite_SetSite( IObjectWithSite *iface, IUnknown *punk )
3265 domdoc *This = impl_from_IObjectWithSite(iface);
3267 TRACE("(%p)->(%p)\n", iface, punk);
3273 IUnknown_Release( This->site );
3280 IUnknown_AddRef( punk );
3283 IUnknown_Release( This->site );
3290 static const IObjectWithSiteVtbl domdocObjectSite =
3292 domdoc_ObjectWithSite_QueryInterface,
3293 domdoc_ObjectWithSite_AddRef,
3294 domdoc_ObjectWithSite_Release,
3295 domdoc_ObjectWithSite_SetSite,
3296 domdoc_ObjectWithSite_GetSite
3299 static HRESULT WINAPI domdoc_Safety_QueryInterface(IObjectSafety *iface, REFIID riid, void **ppv)
3301 domdoc *This = impl_from_IObjectSafety(iface);
3302 return IXMLDOMDocument3_QueryInterface( (IXMLDOMDocument3 *)This, riid, ppv );
3305 static ULONG WINAPI domdoc_Safety_AddRef(IObjectSafety *iface)
3307 domdoc *This = impl_from_IObjectSafety(iface);
3308 return IXMLDOMDocument3_AddRef((IXMLDOMDocument3 *)This);
3311 static ULONG WINAPI domdoc_Safety_Release(IObjectSafety *iface)
3313 domdoc *This = impl_from_IObjectSafety(iface);
3314 return IXMLDOMDocument3_Release((IXMLDOMDocument3 *)This);
3317 #define SAFETY_SUPPORTED_OPTIONS (INTERFACESAFE_FOR_UNTRUSTED_CALLER|INTERFACESAFE_FOR_UNTRUSTED_DATA|INTERFACE_USES_SECURITY_MANAGER)
3319 static HRESULT WINAPI domdoc_Safety_GetInterfaceSafetyOptions(IObjectSafety *iface, REFIID riid,
3320 DWORD *supported, DWORD *enabled)
3322 domdoc *This = impl_from_IObjectSafety(iface);
3324 TRACE("(%p)->(%s %p %p)\n", This, debugstr_guid(riid), supported, enabled);
3326 if(!supported || !enabled) return E_POINTER;
3328 *supported = SAFETY_SUPPORTED_OPTIONS;
3329 *enabled = This->safeopt;
3334 static HRESULT WINAPI domdoc_Safety_SetInterfaceSafetyOptions(IObjectSafety *iface, REFIID riid,
3335 DWORD mask, DWORD enabled)
3337 domdoc *This = impl_from_IObjectSafety(iface);
3338 TRACE("(%p)->(%s %x %x)\n", This, debugstr_guid(riid), mask, enabled);
3340 if ((mask & ~SAFETY_SUPPORTED_OPTIONS) != 0)
3343 This->safeopt = enabled & mask & SAFETY_SUPPORTED_OPTIONS;
3347 #undef SAFETY_SUPPORTED_OPTIONS
3349 static const IObjectSafetyVtbl domdocObjectSafetyVtbl = {
3350 domdoc_Safety_QueryInterface,
3351 domdoc_Safety_AddRef,
3352 domdoc_Safety_Release,
3353 domdoc_Safety_GetInterfaceSafetyOptions,
3354 domdoc_Safety_SetInterfaceSafetyOptions
3357 static const tid_t domdoc_iface_tids[] = {
3359 IXMLDOMDocument_tid,
3360 IXMLDOMDocument2_tid,
3363 static dispex_static_data_t domdoc_dispex = {
3365 IXMLDOMDocument2_tid,
3370 HRESULT DOMDocument_create_from_xmldoc(xmlDocPtr xmldoc, IXMLDOMDocument3 **document)
3374 doc = heap_alloc( sizeof (*doc) );
3376 return E_OUTOFMEMORY;
3378 doc->lpVtbl = &domdoc_vtbl;
3379 doc->lpvtblIPersistStreamInit = &xmldoc_IPersistStreamInit_VTable;
3380 doc->lpvtblIObjectWithSite = &domdocObjectSite;
3381 doc->lpvtblIObjectSafety = &domdocObjectSafetyVtbl;
3382 doc->lpvtblISupportErrorInfo = &support_error_vtbl;
3383 doc->lpVtblConnectionPointContainer = &ConnectionPointContainerVtbl;
3385 doc->async = VARIANT_TRUE;
3386 doc->validating = 0;
3388 doc->properties = properties_from_xmlDocPtr(xmldoc);
3394 doc->cp_list = NULL;
3396 /* events connection points */
3397 ConnectionPoint_Init(&doc->cp_dispatch, doc, &IID_IDispatch);
3398 ConnectionPoint_Init(&doc->cp_propnotif, doc, &IID_IPropertyNotifySink);
3399 ConnectionPoint_Init(&doc->cp_domdocevents, doc, &DIID_XMLDOMDocumentEvents);
3401 init_xmlnode(&doc->node, (xmlNodePtr)xmldoc, (IXMLDOMNode*)&doc->lpVtbl, &domdoc_dispex);
3403 *document = (IXMLDOMDocument3*)&doc->lpVtbl;
3405 TRACE("returning iface %p\n", *document);
3409 HRESULT DOMDocument_create(const GUID *clsid, IUnknown *pUnkOuter, void **ppObj)
3414 TRACE("(%s, %p, %p)\n", debugstr_guid(clsid), pUnkOuter, ppObj);
3416 xmldoc = xmlNewDoc(NULL);
3418 return E_OUTOFMEMORY;
3420 xmldoc->_private = create_priv();
3421 priv_from_xmlDocPtr(xmldoc)->properties = create_properties(clsid);
3423 hr = DOMDocument_create_from_xmldoc(xmldoc, (IXMLDOMDocument3**)ppObj);
3426 free_properties(properties_from_xmlDocPtr(xmldoc));
3427 heap_free(xmldoc->_private);
3435 IUnknown* create_domdoc( xmlNodePtr document )
3440 TRACE("(%p)\n", document);
3442 hr = DOMDocument_create_from_xmldoc((xmlDocPtr)document, (IXMLDOMDocument3**)&pObj);
3451 HRESULT DOMDocument_create(const GUID *clsid, IUnknown *pUnkOuter, void **ppObj)
3453 MESSAGE("This program tried to use a DOMDocument object, but\n"
3454 "libxml2 support was not present at compile time.\n");