jscript: Add missing port.h include for isnan.
[wine/multimedia.git] / dlls / msxml3 / domdoc.c
blob6805c75f79904d69fcb8c01a61b2ccd3aebbcd96
1 /*
2 * DOM Document implementation
4 * Copyright 2005 Mike McCormack
5 * Copyright 2010-2011 Adam Martinson for CodeWeavers
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
22 #define COBJMACROS
23 #define NONAMELESSUNION
25 #include "config.h"
27 #include <stdarg.h>
28 #include <assert.h>
29 #ifdef HAVE_LIBXML2
30 # include <libxml/parser.h>
31 # include <libxml/xmlerror.h>
32 # include <libxml/xpathInternals.h>
33 # include <libxml/xmlsave.h>
34 # include <libxml/SAX2.h>
35 # include <libxml/parserInternals.h>
36 #endif
38 #include "windef.h"
39 #include "winbase.h"
40 #include "winuser.h"
41 #include "winnls.h"
42 #include "ole2.h"
43 #include "olectl.h"
44 #include "msxml6.h"
45 #include "wininet.h"
46 #include "winreg.h"
47 #include "shlwapi.h"
48 #include "ocidl.h"
49 #include "objsafe.h"
51 #include "wine/debug.h"
52 #include "wine/list.h"
54 #include "msxml_private.h"
56 WINE_DEFAULT_DEBUG_CHANNEL(msxml);
58 #ifdef HAVE_LIBXML2
60 /* not defined in older versions */
61 #define XML_SAVE_FORMAT 1
62 #define XML_SAVE_NO_DECL 2
63 #define XML_SAVE_NO_EMPTY 4
64 #define XML_SAVE_NO_XHTML 8
65 #define XML_SAVE_XHTML 16
66 #define XML_SAVE_AS_XML 32
67 #define XML_SAVE_AS_HTML 64
69 static const WCHAR PropertySelectionLanguageW[] = {'S','e','l','e','c','t','i','o','n','L','a','n','g','u','a','g','e',0};
70 static const WCHAR PropertySelectionNamespacesW[] = {'S','e','l','e','c','t','i','o','n','N','a','m','e','s','p','a','c','e','s',0};
71 static const WCHAR PropertyProhibitDTDW[] = {'P','r','o','h','i','b','i','t','D','T','D',0};
72 static const WCHAR PropertyNewParserW[] = {'N','e','w','P','a','r','s','e','r',0};
73 static const WCHAR PropValueXPathW[] = {'X','P','a','t','h',0};
74 static const WCHAR PropValueXSLPatternW[] = {'X','S','L','P','a','t','t','e','r','n',0};
75 static const WCHAR PropertyResolveExternalsW[] = {'R','e','s','o','l','v','e','E','x','t','e','r','n','a','l','s',0};
77 /* Anything that passes the test_get_ownerDocument()
78 * tests can go here (data shared between all instances).
79 * We need to preserve this when reloading a document,
80 * and also need access to it from the libxml backend. */
81 typedef struct {
82 MSXML_VERSION version;
83 VARIANT_BOOL preserving;
84 IXMLDOMSchemaCollection2* schemaCache;
85 struct list selectNsList;
86 xmlChar const* selectNsStr;
87 LONG selectNsStr_len;
88 BOOL XPath;
89 } domdoc_properties;
91 typedef struct ConnectionPoint ConnectionPoint;
92 typedef struct domdoc domdoc;
94 struct ConnectionPoint
96 IConnectionPoint IConnectionPoint_iface;
97 const IID *iid;
99 ConnectionPoint *next;
100 IConnectionPointContainer *container;
101 domdoc *doc;
103 union
105 IUnknown *unk;
106 IDispatch *disp;
107 IPropertyNotifySink *propnotif;
108 } *sinks;
109 DWORD sinks_size;
112 typedef enum {
113 EVENTID_READYSTATECHANGE = 0,
114 EVENTID_DATAAVAILABLE,
115 EVENTID_TRANSFORMNODE,
116 EVENTID_LAST
117 } eventid_t;
119 struct domdoc
121 xmlnode node;
122 IXMLDOMDocument3 IXMLDOMDocument3_iface;
123 IPersistStreamInit IPersistStreamInit_iface;
124 IObjectWithSite IObjectWithSite_iface;
125 IObjectSafety IObjectSafety_iface;
126 IConnectionPointContainer IConnectionPointContainer_iface;
127 LONG ref;
128 VARIANT_BOOL async;
129 VARIANT_BOOL validating;
130 VARIANT_BOOL resolving;
131 domdoc_properties* properties;
132 bsc_t *bsc;
133 HRESULT error;
135 /* IPersistStream */
136 IStream *stream;
138 /* IObjectWithSite*/
139 IUnknown *site;
141 /* IObjectSafety */
142 DWORD safeopt;
144 /* connection list */
145 ConnectionPoint *cp_list;
146 ConnectionPoint cp_domdocevents;
147 ConnectionPoint cp_propnotif;
148 ConnectionPoint cp_dispatch;
150 /* events */
151 IDispatch *events[EVENTID_LAST];
153 IXMLDOMSchemaCollection2 *namespaces;
156 static HRESULT set_doc_event(domdoc *doc, eventid_t eid, const VARIANT *v)
158 IDispatch *disp;
160 switch (V_VT(v))
162 case VT_UNKNOWN:
163 if (V_UNKNOWN(v))
164 IUnknown_QueryInterface(V_UNKNOWN(v), &IID_IDispatch, (void**)&disp);
165 else
166 disp = NULL;
167 break;
168 case VT_DISPATCH:
169 disp = V_DISPATCH(v);
170 if (disp) IDispatch_AddRef(disp);
171 break;
172 default:
173 return DISP_E_TYPEMISMATCH;
176 if (doc->events[eid]) IDispatch_Release(doc->events[eid]);
177 doc->events[eid] = disp;
179 return S_OK;
182 static inline ConnectionPoint *impl_from_IConnectionPoint(IConnectionPoint *iface)
184 return CONTAINING_RECORD(iface, ConnectionPoint, IConnectionPoint_iface);
188 In native windows, the whole lifetime management of XMLDOMNodes is
189 managed automatically using reference counts. Wine emulates that by
190 maintaining a reference count to the document that is increased for
191 each IXMLDOMNode pointer passed out for this document. If all these
192 pointers are gone, the document is unreachable and gets freed, that
193 is, all nodes in the tree of the document get freed.
195 You are able to create nodes that are associated to a document (in
196 fact, in msxml's XMLDOM model, all nodes are associated to a document),
197 but not in the tree of that document, for example using the createFoo
198 functions from IXMLDOMDocument. These nodes do not get cleaned up
199 by libxml, so we have to do it ourselves.
201 To catch these nodes, a list of "orphan nodes" is introduced.
202 It contains pointers to all roots of node trees that are
203 associated with the document without being part of the document
204 tree. All nodes with parent==NULL (except for the document root nodes)
205 should be in the orphan node list of their document. All orphan nodes
206 get freed together with the document itself.
209 typedef struct _xmldoc_priv {
210 LONG refs;
211 struct list orphans;
212 domdoc_properties* properties;
213 } xmldoc_priv;
215 typedef struct _orphan_entry {
216 struct list entry;
217 xmlNode * node;
218 } orphan_entry;
220 typedef struct _select_ns_entry {
221 struct list entry;
222 xmlChar const* prefix;
223 xmlChar prefix_end;
224 xmlChar const* href;
225 xmlChar href_end;
226 } select_ns_entry;
228 static inline xmldoc_priv * priv_from_xmlDocPtr(const xmlDocPtr doc)
230 return doc->_private;
233 static inline domdoc_properties * properties_from_xmlDocPtr(xmlDocPtr doc)
235 return priv_from_xmlDocPtr(doc)->properties;
238 BOOL is_xpathmode(const xmlDocPtr doc)
240 return properties_from_xmlDocPtr(doc)->XPath;
243 void set_xpathmode(xmlDocPtr doc, BOOL xpath)
245 properties_from_xmlDocPtr(doc)->XPath = xpath;
248 int registerNamespaces(xmlXPathContextPtr ctxt)
250 int n = 0;
251 const select_ns_entry* ns = NULL;
252 const struct list* pNsList = &properties_from_xmlDocPtr(ctxt->doc)->selectNsList;
254 TRACE("(%p)\n", ctxt);
256 LIST_FOR_EACH_ENTRY( ns, pNsList, select_ns_entry, entry )
258 xmlXPathRegisterNs(ctxt, ns->prefix, ns->href);
259 ++n;
262 return n;
265 static inline void clear_selectNsList(struct list* pNsList)
267 select_ns_entry *ns, *ns2;
268 LIST_FOR_EACH_ENTRY_SAFE( ns, ns2, pNsList, select_ns_entry, entry )
270 heap_free( ns );
272 list_init(pNsList);
275 static xmldoc_priv * create_priv(void)
277 xmldoc_priv *priv;
278 priv = heap_alloc( sizeof (*priv) );
280 if (priv)
282 priv->refs = 0;
283 list_init( &priv->orphans );
284 priv->properties = NULL;
287 return priv;
290 static domdoc_properties *create_properties(MSXML_VERSION version)
292 domdoc_properties *properties = heap_alloc(sizeof(domdoc_properties));
294 list_init(&properties->selectNsList);
295 properties->preserving = VARIANT_FALSE;
296 properties->schemaCache = NULL;
297 properties->selectNsStr = heap_alloc_zero(sizeof(xmlChar));
298 properties->selectNsStr_len = 0;
300 /* properties that are dependent on object versions */
301 properties->version = version;
302 properties->XPath = (version == MSXML4 || version == MSXML6);
304 return properties;
307 static domdoc_properties* copy_properties(domdoc_properties const* properties)
309 domdoc_properties* pcopy = heap_alloc(sizeof(domdoc_properties));
310 select_ns_entry const* ns = NULL;
311 select_ns_entry* new_ns = NULL;
312 int len = (properties->selectNsStr_len+1)*sizeof(xmlChar);
313 ptrdiff_t offset;
315 if (pcopy)
317 pcopy->version = properties->version;
318 pcopy->preserving = properties->preserving;
319 pcopy->schemaCache = properties->schemaCache;
320 if (pcopy->schemaCache)
321 IXMLDOMSchemaCollection2_AddRef(pcopy->schemaCache);
322 pcopy->XPath = properties->XPath;
323 pcopy->selectNsStr_len = properties->selectNsStr_len;
324 list_init( &pcopy->selectNsList );
325 pcopy->selectNsStr = heap_alloc(len);
326 memcpy((xmlChar*)pcopy->selectNsStr, properties->selectNsStr, len);
327 offset = pcopy->selectNsStr - properties->selectNsStr;
329 LIST_FOR_EACH_ENTRY( ns, (&properties->selectNsList), select_ns_entry, entry )
331 new_ns = heap_alloc(sizeof(select_ns_entry));
332 memcpy(new_ns, ns, sizeof(select_ns_entry));
333 new_ns->href += offset;
334 new_ns->prefix += offset;
335 list_add_tail(&pcopy->selectNsList, &new_ns->entry);
340 return pcopy;
343 static void free_properties(domdoc_properties* properties)
345 if (properties)
347 if (properties->schemaCache)
348 IXMLDOMSchemaCollection2_Release(properties->schemaCache);
349 clear_selectNsList(&properties->selectNsList);
350 heap_free((xmlChar*)properties->selectNsStr);
351 heap_free(properties);
355 static void release_namespaces(domdoc *This)
357 if (This->namespaces)
359 IXMLDOMSchemaCollection2_Release(This->namespaces);
360 This->namespaces = NULL;
364 /* links a "<?xml" node as a first child */
365 void xmldoc_link_xmldecl(xmlDocPtr doc, xmlNodePtr node)
367 assert(doc != NULL);
368 if (doc->standalone != -1) xmlAddPrevSibling( doc->children, node );
371 /* unlinks a first "<?xml" child if it was created */
372 xmlNodePtr xmldoc_unlink_xmldecl(xmlDocPtr doc)
374 xmlNodePtr node;
376 assert(doc != NULL);
378 if (doc->standalone != -1)
380 node = doc->children;
381 xmlUnlinkNode( node );
383 else
384 node = NULL;
386 return node;
389 BOOL is_preserving_whitespace(xmlNodePtr node)
391 domdoc_properties* properties = NULL;
392 /* during parsing the xmlDoc._private stuff is not there */
393 if (priv_from_xmlDocPtr(node->doc))
394 properties = properties_from_xmlDocPtr(node->doc);
395 return ((properties && properties->preserving == VARIANT_TRUE) ||
396 xmlNodeGetSpacePreserve(node) == 1);
399 static inline BOOL strn_isspace(xmlChar const* str, int len)
401 for (; str && len > 0 && *str; ++str, --len)
402 if (!isspace(*str))
403 break;
405 return len == 0;
408 static void sax_characters(void *ctx, const xmlChar *ch, int len)
410 xmlParserCtxtPtr ctxt;
411 const domdoc *This;
413 ctxt = (xmlParserCtxtPtr) ctx;
414 This = (const domdoc*) ctxt->_private;
416 if (ctxt->node)
418 /* during domdoc_loadXML() the xmlDocPtr->_private data is not available */
419 if (!This->properties->preserving &&
420 !is_preserving_whitespace(ctxt->node) &&
421 strn_isspace(ch, len))
422 return;
425 xmlSAX2Characters(ctxt, ch, len);
428 static void LIBXML2_LOG_CALLBACK sax_error(void* ctx, char const* msg, ...)
430 va_list ap;
431 va_start(ap, msg);
432 LIBXML2_CALLBACK_ERR(doparse, msg, ap);
433 va_end(ap);
436 static void LIBXML2_LOG_CALLBACK sax_warning(void* ctx, char const* msg, ...)
438 va_list ap;
439 va_start(ap, msg);
440 LIBXML2_CALLBACK_WARN(doparse, msg, ap);
441 va_end(ap);
444 static void sax_serror(void* ctx, xmlErrorPtr err)
446 LIBXML2_CALLBACK_SERROR(doparse, err);
449 static xmlDocPtr doparse(domdoc* This, char const* ptr, int len, xmlCharEncoding encoding)
451 xmlDocPtr doc = NULL;
452 xmlParserCtxtPtr pctx;
453 static xmlSAXHandler sax_handler = {
454 xmlSAX2InternalSubset, /* internalSubset */
455 xmlSAX2IsStandalone, /* isStandalone */
456 xmlSAX2HasInternalSubset, /* hasInternalSubset */
457 xmlSAX2HasExternalSubset, /* hasExternalSubset */
458 xmlSAX2ResolveEntity, /* resolveEntity */
459 xmlSAX2GetEntity, /* getEntity */
460 xmlSAX2EntityDecl, /* entityDecl */
461 xmlSAX2NotationDecl, /* notationDecl */
462 xmlSAX2AttributeDecl, /* attributeDecl */
463 xmlSAX2ElementDecl, /* elementDecl */
464 xmlSAX2UnparsedEntityDecl, /* unparsedEntityDecl */
465 xmlSAX2SetDocumentLocator, /* setDocumentLocator */
466 xmlSAX2StartDocument, /* startDocument */
467 xmlSAX2EndDocument, /* endDocument */
468 xmlSAX2StartElement, /* startElement */
469 xmlSAX2EndElement, /* endElement */
470 xmlSAX2Reference, /* reference */
471 sax_characters, /* characters */
472 sax_characters, /* ignorableWhitespace */
473 xmlSAX2ProcessingInstruction, /* processingInstruction */
474 xmlSAX2Comment, /* comment */
475 sax_warning, /* warning */
476 sax_error, /* error */
477 sax_error, /* fatalError */
478 xmlSAX2GetParameterEntity, /* getParameterEntity */
479 xmlSAX2CDataBlock, /* cdataBlock */
480 xmlSAX2ExternalSubset, /* externalSubset */
481 0, /* initialized */
482 NULL, /* _private */
483 xmlSAX2StartElementNs, /* startElementNs */
484 xmlSAX2EndElementNs, /* endElementNs */
485 sax_serror /* serror */
487 xmlInitParser();
489 pctx = xmlCreateMemoryParserCtxt(ptr, len);
490 if (!pctx)
492 ERR("Failed to create parser context\n");
493 return NULL;
496 if (pctx->sax) xmlFree(pctx->sax);
497 pctx->sax = &sax_handler;
498 pctx->_private = This;
499 pctx->recovery = 0;
501 if (encoding != XML_CHAR_ENCODING_NONE)
502 xmlSwitchEncoding(pctx, encoding);
504 xmlParseDocument(pctx);
506 if (pctx->wellFormed)
508 doc = pctx->myDoc;
510 else
512 xmlFreeDoc(pctx->myDoc);
513 pctx->myDoc = NULL;
515 pctx->sax = NULL;
516 xmlFreeParserCtxt(pctx);
518 /* TODO: put this in one of the SAX callbacks */
519 /* create first child as a <?xml...?> */
520 if (doc && doc->standalone != -1)
522 xmlNodePtr node;
523 char buff[30];
524 xmlChar *xmlbuff = (xmlChar*)buff;
526 node = xmlNewDocPI( doc, (xmlChar*)"xml", NULL );
528 /* version attribute can't be omitted */
529 sprintf(buff, "version=\"%s\"", doc->version ? (char*)doc->version : "1.0");
530 xmlNodeAddContent( node, xmlbuff );
532 if (doc->encoding)
534 sprintf(buff, " encoding=\"%s\"", doc->encoding);
535 xmlNodeAddContent( node, xmlbuff );
538 if (doc->standalone != -2)
540 sprintf(buff, " standalone=\"%s\"", doc->standalone == 0 ? "no" : "yes");
541 xmlNodeAddContent( node, xmlbuff );
544 xmldoc_link_xmldecl( doc, node );
547 return doc;
550 void xmldoc_init(xmlDocPtr doc, MSXML_VERSION version)
552 doc->_private = create_priv();
553 priv_from_xmlDocPtr(doc)->properties = create_properties(version);
556 LONG xmldoc_add_ref(xmlDocPtr doc)
558 LONG ref = InterlockedIncrement(&priv_from_xmlDocPtr(doc)->refs);
559 TRACE("(%p)->(%d)\n", doc, ref);
560 return ref;
563 LONG xmldoc_release(xmlDocPtr doc)
565 xmldoc_priv *priv = priv_from_xmlDocPtr(doc);
566 LONG ref = InterlockedDecrement(&priv->refs);
567 TRACE("(%p)->(%d)\n", doc, ref);
568 if(ref == 0)
570 orphan_entry *orphan, *orphan2;
571 TRACE("freeing docptr %p\n", doc);
573 LIST_FOR_EACH_ENTRY_SAFE( orphan, orphan2, &priv->orphans, orphan_entry, entry )
575 xmlFreeNode( orphan->node );
576 heap_free( orphan );
578 free_properties(priv->properties);
579 heap_free(doc->_private);
581 xmlFreeDoc(doc);
584 return ref;
587 HRESULT xmldoc_add_orphan(xmlDocPtr doc, xmlNodePtr node)
589 xmldoc_priv *priv = priv_from_xmlDocPtr(doc);
590 orphan_entry *entry;
592 entry = heap_alloc( sizeof (*entry) );
593 if(!entry)
594 return E_OUTOFMEMORY;
596 entry->node = node;
597 list_add_head( &priv->orphans, &entry->entry );
598 return S_OK;
601 HRESULT xmldoc_remove_orphan(xmlDocPtr doc, xmlNodePtr node)
603 xmldoc_priv *priv = priv_from_xmlDocPtr(doc);
604 orphan_entry *entry, *entry2;
606 LIST_FOR_EACH_ENTRY_SAFE( entry, entry2, &priv->orphans, orphan_entry, entry )
608 if( entry->node == node )
610 list_remove( &entry->entry );
611 heap_free( entry );
612 return S_OK;
616 return S_FALSE;
619 static inline xmlDocPtr get_doc( domdoc *This )
621 return (xmlDocPtr)This->node.node;
624 static HRESULT attach_xmldoc(domdoc *This, xmlDocPtr xml )
626 release_namespaces(This);
628 if(This->node.node)
630 priv_from_xmlDocPtr(get_doc(This))->properties = NULL;
631 if (xmldoc_release(get_doc(This)) != 0)
632 priv_from_xmlDocPtr(get_doc(This))->properties =
633 copy_properties(This->properties);
636 This->node.node = (xmlNodePtr) xml;
638 if(This->node.node)
640 xmldoc_add_ref(get_doc(This));
641 priv_from_xmlDocPtr(get_doc(This))->properties = This->properties;
644 return S_OK;
647 static inline domdoc *impl_from_IXMLDOMDocument3( IXMLDOMDocument3 *iface )
649 return CONTAINING_RECORD(iface, domdoc, IXMLDOMDocument3_iface);
652 static inline domdoc *impl_from_IPersistStreamInit(IPersistStreamInit *iface)
654 return CONTAINING_RECORD(iface, domdoc, IPersistStreamInit_iface);
657 static inline domdoc *impl_from_IObjectWithSite(IObjectWithSite *iface)
659 return CONTAINING_RECORD(iface, domdoc, IObjectWithSite_iface);
662 static inline domdoc *impl_from_IObjectSafety(IObjectSafety *iface)
664 return CONTAINING_RECORD(iface, domdoc, IObjectSafety_iface);
667 static inline domdoc *impl_from_IConnectionPointContainer(IConnectionPointContainer *iface)
669 return CONTAINING_RECORD(iface, domdoc, IConnectionPointContainer_iface);
672 /************************************************************************
673 * domdoc implementation of IPersistStream.
675 static HRESULT WINAPI PersistStreamInit_QueryInterface(
676 IPersistStreamInit *iface, REFIID riid, void **ppvObj)
678 domdoc* This = impl_from_IPersistStreamInit(iface);
679 return IXMLDOMDocument3_QueryInterface(&This->IXMLDOMDocument3_iface, riid, ppvObj);
682 static ULONG WINAPI PersistStreamInit_AddRef(
683 IPersistStreamInit *iface)
685 domdoc* This = impl_from_IPersistStreamInit(iface);
686 return IXMLDOMDocument3_AddRef(&This->IXMLDOMDocument3_iface);
689 static ULONG WINAPI PersistStreamInit_Release(
690 IPersistStreamInit *iface)
692 domdoc* This = impl_from_IPersistStreamInit(iface);
693 return IXMLDOMDocument3_Release(&This->IXMLDOMDocument3_iface);
696 static HRESULT WINAPI PersistStreamInit_GetClassID(
697 IPersistStreamInit *iface, CLSID *classid)
699 domdoc* This = impl_from_IPersistStreamInit(iface);
700 TRACE("(%p)->(%p)\n", This, classid);
702 if(!classid)
703 return E_POINTER;
705 *classid = *DOMDocument_version(This->properties->version);
707 return S_OK;
710 static HRESULT WINAPI PersistStreamInit_IsDirty(
711 IPersistStreamInit *iface)
713 domdoc *This = impl_from_IPersistStreamInit(iface);
714 FIXME("(%p): stub!\n", This);
715 return S_FALSE;
718 static HRESULT WINAPI PersistStreamInit_Load(
719 IPersistStreamInit *iface, LPSTREAM pStm)
721 domdoc *This = impl_from_IPersistStreamInit(iface);
722 HRESULT hr;
723 HGLOBAL hglobal;
724 DWORD read, written, len;
725 BYTE buf[4096];
726 char *ptr;
727 xmlDocPtr xmldoc = NULL;
729 TRACE("(%p)->(%p)\n", This, pStm);
731 if (!pStm)
732 return E_INVALIDARG;
734 hr = CreateStreamOnHGlobal(NULL, TRUE, &This->stream);
735 if (FAILED(hr))
736 return hr;
740 IStream_Read(pStm, buf, sizeof(buf), &read);
741 hr = IStream_Write(This->stream, buf, read, &written);
742 } while(SUCCEEDED(hr) && written != 0 && read != 0);
744 if (FAILED(hr))
746 ERR("Failed to copy stream\n");
747 return hr;
750 hr = GetHGlobalFromStream(This->stream, &hglobal);
751 if (FAILED(hr))
752 return hr;
754 len = GlobalSize(hglobal);
755 ptr = GlobalLock(hglobal);
756 if (len != 0)
757 xmldoc = doparse(This, ptr, len, XML_CHAR_ENCODING_NONE);
758 GlobalUnlock(hglobal);
760 if (!xmldoc)
762 ERR("Failed to parse xml\n");
763 return E_FAIL;
766 xmldoc->_private = create_priv();
768 return attach_xmldoc(This, xmldoc);
771 static HRESULT WINAPI PersistStreamInit_Save(
772 IPersistStreamInit *iface, IStream *stream, BOOL clr_dirty)
774 domdoc *This = impl_from_IPersistStreamInit(iface);
775 BSTR xmlString;
776 HRESULT hr;
778 TRACE("(%p)->(%p %d)\n", This, stream, clr_dirty);
780 hr = IXMLDOMDocument3_get_xml(&This->IXMLDOMDocument3_iface, &xmlString);
781 if(hr == S_OK)
783 DWORD len = SysStringLen(xmlString) * sizeof(WCHAR);
785 hr = IStream_Write( stream, xmlString, len, NULL );
786 SysFreeString(xmlString);
789 TRACE("ret 0x%08x\n", hr);
791 return hr;
794 static HRESULT WINAPI PersistStreamInit_GetSizeMax(
795 IPersistStreamInit *iface, ULARGE_INTEGER *pcbSize)
797 domdoc *This = impl_from_IPersistStreamInit(iface);
798 TRACE("(%p)->(%p): stub!\n", This, pcbSize);
799 return E_NOTIMPL;
802 static HRESULT WINAPI PersistStreamInit_InitNew(
803 IPersistStreamInit *iface)
805 domdoc *This = impl_from_IPersistStreamInit(iface);
806 TRACE("(%p)\n", This);
807 return S_OK;
810 static const IPersistStreamInitVtbl xmldoc_IPersistStreamInit_VTable =
812 PersistStreamInit_QueryInterface,
813 PersistStreamInit_AddRef,
814 PersistStreamInit_Release,
815 PersistStreamInit_GetClassID,
816 PersistStreamInit_IsDirty,
817 PersistStreamInit_Load,
818 PersistStreamInit_Save,
819 PersistStreamInit_GetSizeMax,
820 PersistStreamInit_InitNew
823 /* IXMLDOMDocument3 interface */
825 static const tid_t domdoc_se_tids[] = {
826 IXMLDOMNode_tid,
827 IXMLDOMDocument_tid,
828 IXMLDOMDocument2_tid,
829 IXMLDOMDocument3_tid,
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 );
839 *ppvObject = NULL;
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 ))
848 *ppvObject = iface;
850 else if (IsEqualGUID(&IID_IPersistStream, riid) ||
851 IsEqualGUID(&IID_IPersistStreamInit, riid))
853 *ppvObject = &This->IPersistStreamInit_iface;
855 else if (IsEqualGUID(&IID_IObjectWithSite, riid))
857 *ppvObject = &This->IObjectWithSite_iface;
859 else if (IsEqualGUID(&IID_IObjectSafety, riid))
861 *ppvObject = &This->IObjectSafety_iface;
863 else if( IsEqualGUID( riid, &IID_ISupportErrorInfo ))
865 return node_create_supporterrorinfo(domdoc_se_tids, ppvObject);
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->IConnectionPointContainer_iface;
875 else
877 TRACE("interface %s not implemented\n", debugstr_guid(riid));
878 return E_NOINTERFACE;
881 IUnknown_AddRef((IUnknown*)*ppvObject);
883 return S_OK;
886 static ULONG WINAPI domdoc_AddRef( IXMLDOMDocument3 *iface )
888 domdoc *This = impl_from_IXMLDOMDocument3( iface );
889 ULONG ref = InterlockedIncrement( &This->ref );
890 TRACE("(%p)->(%d)\n", This, ref );
891 return ref;
894 static ULONG WINAPI domdoc_Release( IXMLDOMDocument3 *iface )
896 domdoc *This = impl_from_IXMLDOMDocument3( iface );
897 LONG ref = InterlockedDecrement( &This->ref );
899 TRACE("(%p)->(%d)\n", This, ref );
901 if ( ref == 0 )
903 int eid;
905 if(This->bsc)
906 detach_bsc(This->bsc);
908 if (This->site)
909 IUnknown_Release( This->site );
910 destroy_xmlnode(&This->node);
911 if (This->stream)
912 IStream_Release(This->stream);
914 for (eid = 0; eid < EVENTID_LAST; eid++)
915 if (This->events[eid]) IDispatch_Release(This->events[eid]);
917 release_namespaces(This);
918 heap_free(This);
921 return ref;
924 static HRESULT WINAPI domdoc_GetTypeInfoCount( IXMLDOMDocument3 *iface, UINT* pctinfo )
926 domdoc *This = impl_from_IXMLDOMDocument3( iface );
927 return IDispatchEx_GetTypeInfoCount(&This->node.dispex.IDispatchEx_iface, pctinfo);
930 static HRESULT WINAPI domdoc_GetTypeInfo(
931 IXMLDOMDocument3 *iface,
932 UINT iTInfo, LCID lcid, ITypeInfo** ppTInfo )
934 domdoc *This = impl_from_IXMLDOMDocument3( iface );
935 return IDispatchEx_GetTypeInfo(&This->node.dispex.IDispatchEx_iface, iTInfo, lcid, ppTInfo);
938 static HRESULT WINAPI domdoc_GetIDsOfNames(
939 IXMLDOMDocument3 *iface,
940 REFIID riid,
941 LPOLESTR* rgszNames,
942 UINT cNames,
943 LCID lcid,
944 DISPID* rgDispId)
946 domdoc *This = impl_from_IXMLDOMDocument3( iface );
947 return IDispatchEx_GetIDsOfNames(&This->node.dispex.IDispatchEx_iface,
948 riid, rgszNames, cNames, lcid, rgDispId);
951 static HRESULT WINAPI domdoc_Invoke(
952 IXMLDOMDocument3 *iface,
953 DISPID dispIdMember,
954 REFIID riid,
955 LCID lcid,
956 WORD wFlags,
957 DISPPARAMS* pDispParams,
958 VARIANT* pVarResult,
959 EXCEPINFO* pExcepInfo,
960 UINT* puArgErr)
962 domdoc *This = impl_from_IXMLDOMDocument3( iface );
963 return IDispatchEx_Invoke(&This->node.dispex.IDispatchEx_iface,
964 dispIdMember, riid, lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
967 static HRESULT WINAPI domdoc_get_nodeName(
968 IXMLDOMDocument3 *iface,
969 BSTR* name )
971 domdoc *This = impl_from_IXMLDOMDocument3( iface );
973 static const WCHAR documentW[] = {'#','d','o','c','u','m','e','n','t',0};
975 TRACE("(%p)->(%p)\n", This, name);
977 return return_bstr(documentW, name);
981 static HRESULT WINAPI domdoc_get_nodeValue(
982 IXMLDOMDocument3 *iface,
983 VARIANT* value )
985 domdoc *This = impl_from_IXMLDOMDocument3( iface );
987 TRACE("(%p)->(%p)\n", This, value);
989 if(!value)
990 return E_INVALIDARG;
992 V_VT(value) = VT_NULL;
993 V_BSTR(value) = NULL; /* tests show that we should do this */
994 return S_FALSE;
998 static HRESULT WINAPI domdoc_put_nodeValue(
999 IXMLDOMDocument3 *iface,
1000 VARIANT value)
1002 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1003 TRACE("(%p)->(%s)\n", This, debugstr_variant(&value));
1004 return E_FAIL;
1008 static HRESULT WINAPI domdoc_get_nodeType(
1009 IXMLDOMDocument3 *iface,
1010 DOMNodeType* type )
1012 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1014 TRACE("(%p)->(%p)\n", This, type);
1016 *type = NODE_DOCUMENT;
1017 return S_OK;
1021 static HRESULT WINAPI domdoc_get_parentNode(
1022 IXMLDOMDocument3 *iface,
1023 IXMLDOMNode** parent )
1025 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1027 TRACE("(%p)->(%p)\n", This, parent);
1029 return node_get_parent(&This->node, parent);
1033 static HRESULT WINAPI domdoc_get_childNodes(
1034 IXMLDOMDocument3 *iface,
1035 IXMLDOMNodeList** childList )
1037 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1039 TRACE("(%p)->(%p)\n", This, childList);
1041 return node_get_child_nodes(&This->node, childList);
1045 static HRESULT WINAPI domdoc_get_firstChild(
1046 IXMLDOMDocument3 *iface,
1047 IXMLDOMNode** firstChild )
1049 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1051 TRACE("(%p)->(%p)\n", This, firstChild);
1053 return node_get_first_child(&This->node, firstChild);
1057 static HRESULT WINAPI domdoc_get_lastChild(
1058 IXMLDOMDocument3 *iface,
1059 IXMLDOMNode** lastChild )
1061 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1063 TRACE("(%p)->(%p)\n", This, lastChild);
1065 return node_get_last_child(&This->node, lastChild);
1069 static HRESULT WINAPI domdoc_get_previousSibling(
1070 IXMLDOMDocument3 *iface,
1071 IXMLDOMNode** previousSibling )
1073 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1075 TRACE("(%p)->(%p)\n", This, previousSibling);
1077 return return_null_node(previousSibling);
1081 static HRESULT WINAPI domdoc_get_nextSibling(
1082 IXMLDOMDocument3 *iface,
1083 IXMLDOMNode** nextSibling )
1085 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1087 TRACE("(%p)->(%p)\n", This, nextSibling);
1089 return return_null_node(nextSibling);
1093 static HRESULT WINAPI domdoc_get_attributes(
1094 IXMLDOMDocument3 *iface,
1095 IXMLDOMNamedNodeMap** attributeMap )
1097 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1099 TRACE("(%p)->(%p)\n", This, attributeMap);
1101 return return_null_ptr((void**)attributeMap);
1105 static HRESULT WINAPI domdoc_insertBefore(
1106 IXMLDOMDocument3 *iface,
1107 IXMLDOMNode* newChild,
1108 VARIANT refChild,
1109 IXMLDOMNode** outNewChild )
1111 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1113 TRACE("(%p)->(%p %s %p)\n", This, newChild, debugstr_variant(&refChild), outNewChild);
1115 return node_insert_before(&This->node, newChild, &refChild, outNewChild);
1119 static HRESULT WINAPI domdoc_replaceChild(
1120 IXMLDOMDocument3 *iface,
1121 IXMLDOMNode* newChild,
1122 IXMLDOMNode* oldChild,
1123 IXMLDOMNode** outOldChild)
1125 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1127 TRACE("(%p)->(%p %p %p)\n", This, newChild, oldChild, outOldChild);
1129 return node_replace_child(&This->node, newChild, oldChild, outOldChild);
1133 static HRESULT WINAPI domdoc_removeChild(
1134 IXMLDOMDocument3 *iface,
1135 IXMLDOMNode *child,
1136 IXMLDOMNode **oldChild)
1138 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1139 TRACE("(%p)->(%p %p)\n", This, child, oldChild);
1140 return node_remove_child(&This->node, child, oldChild);
1144 static HRESULT WINAPI domdoc_appendChild(
1145 IXMLDOMDocument3 *iface,
1146 IXMLDOMNode *child,
1147 IXMLDOMNode **outChild)
1149 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1150 TRACE("(%p)->(%p %p)\n", This, child, outChild);
1151 return node_append_child(&This->node, child, outChild);
1155 static HRESULT WINAPI domdoc_hasChildNodes(
1156 IXMLDOMDocument3 *iface,
1157 VARIANT_BOOL *ret)
1159 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1160 TRACE("(%p)->(%p)\n", This, ret);
1161 return node_has_childnodes(&This->node, ret);
1165 static HRESULT WINAPI domdoc_get_ownerDocument(
1166 IXMLDOMDocument3 *iface,
1167 IXMLDOMDocument **doc)
1169 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1170 TRACE("(%p)->(%p)\n", This, doc);
1171 return node_get_owner_doc(&This->node, doc);
1175 static HRESULT WINAPI domdoc_cloneNode(
1176 IXMLDOMDocument3 *iface,
1177 VARIANT_BOOL deep,
1178 IXMLDOMNode** outNode)
1180 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1181 TRACE("(%p)->(%d %p)\n", This, deep, outNode);
1182 return node_clone( &This->node, deep, outNode );
1186 static HRESULT WINAPI domdoc_get_nodeTypeString(
1187 IXMLDOMDocument3 *iface,
1188 BSTR *p)
1190 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1191 static const WCHAR documentW[] = {'d','o','c','u','m','e','n','t',0};
1193 TRACE("(%p)->(%p)\n", This, p);
1195 return return_bstr(documentW, p);
1199 static HRESULT WINAPI domdoc_get_text(
1200 IXMLDOMDocument3 *iface,
1201 BSTR *p)
1203 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1204 TRACE("(%p)->(%p)\n", This, p);
1205 return node_get_text(&This->node, p);
1209 static HRESULT WINAPI domdoc_put_text(
1210 IXMLDOMDocument3 *iface,
1211 BSTR text )
1213 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1214 TRACE("(%p)->(%s)\n", This, debugstr_w(text));
1215 return E_FAIL;
1219 static HRESULT WINAPI domdoc_get_specified(
1220 IXMLDOMDocument3 *iface,
1221 VARIANT_BOOL* isSpecified )
1223 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1224 FIXME("(%p)->(%p) stub!\n", This, isSpecified);
1225 *isSpecified = VARIANT_TRUE;
1226 return S_OK;
1230 static HRESULT WINAPI domdoc_get_definition(
1231 IXMLDOMDocument3 *iface,
1232 IXMLDOMNode** definitionNode )
1234 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1235 FIXME("(%p)->(%p)\n", This, definitionNode);
1236 return E_NOTIMPL;
1240 static HRESULT WINAPI domdoc_get_nodeTypedValue(
1241 IXMLDOMDocument3 *iface,
1242 VARIANT* v )
1244 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1245 TRACE("(%p)->(%p)\n", This, v);
1246 return return_null_var(v);
1249 static HRESULT WINAPI domdoc_put_nodeTypedValue(
1250 IXMLDOMDocument3 *iface,
1251 VARIANT typedValue )
1253 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1254 FIXME("(%p)->(%s)\n", This, debugstr_variant(&typedValue));
1255 return E_NOTIMPL;
1259 static HRESULT WINAPI domdoc_get_dataType(
1260 IXMLDOMDocument3 *iface,
1261 VARIANT* typename )
1263 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1264 TRACE("(%p)->(%p)\n", This, typename);
1265 return return_null_var( typename );
1269 static HRESULT WINAPI domdoc_put_dataType(
1270 IXMLDOMDocument3 *iface,
1271 BSTR dataTypeName )
1273 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1275 FIXME("(%p)->(%s)\n", This, debugstr_w(dataTypeName));
1277 if(!dataTypeName)
1278 return E_INVALIDARG;
1280 return E_FAIL;
1283 static int XMLCALL domdoc_get_xml_writecallback(void *ctx, const char *data, int len)
1285 return xmlBufferAdd((xmlBufferPtr)ctx, (xmlChar*)data, len) == 0 ? len : 0;
1288 static HRESULT WINAPI domdoc_get_xml(
1289 IXMLDOMDocument3 *iface,
1290 BSTR* p)
1292 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1293 xmlSaveCtxtPtr ctxt;
1294 xmlBufferPtr buf;
1295 int options;
1296 long ret;
1298 TRACE("(%p)->(%p)\n", This, p);
1300 if(!p)
1301 return E_INVALIDARG;
1303 *p = NULL;
1305 buf = xmlBufferCreate();
1306 if(!buf)
1307 return E_OUTOFMEMORY;
1309 options = XML_SAVE_FORMAT | XML_SAVE_NO_DECL;
1310 ctxt = xmlSaveToIO(domdoc_get_xml_writecallback, NULL, buf, "UTF-8", options);
1312 if(!ctxt)
1314 xmlBufferFree(buf);
1315 return E_OUTOFMEMORY;
1318 ret = xmlSaveDoc(ctxt, get_doc(This));
1319 /* flushes on close */
1320 xmlSaveClose(ctxt);
1322 TRACE("%ld, len=%d\n", ret, xmlBufferLength(buf));
1323 if(ret != -1 && xmlBufferLength(buf) > 0)
1325 BSTR content;
1327 content = bstr_from_xmlChar(xmlBufferContent(buf));
1328 content = EnsureCorrectEOL(content);
1330 *p = content;
1332 else
1334 *p = SysAllocStringLen(NULL, 0);
1337 xmlBufferFree(buf);
1339 return *p ? S_OK : E_OUTOFMEMORY;
1343 static HRESULT WINAPI domdoc_transformNode(
1344 IXMLDOMDocument3 *iface,
1345 IXMLDOMNode *node,
1346 BSTR *p)
1348 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1349 TRACE("(%p)->(%p %p)\n", This, node, p);
1350 return node_transform_node(&This->node, node, p);
1354 static HRESULT WINAPI domdoc_selectNodes(
1355 IXMLDOMDocument3 *iface,
1356 BSTR p,
1357 IXMLDOMNodeList **outList)
1359 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1360 TRACE("(%p)->(%s %p)\n", This, debugstr_w(p), outList);
1361 return node_select_nodes(&This->node, p, outList);
1365 static HRESULT WINAPI domdoc_selectSingleNode(
1366 IXMLDOMDocument3 *iface,
1367 BSTR p,
1368 IXMLDOMNode **outNode)
1370 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1371 TRACE("(%p)->(%s %p)\n", This, debugstr_w(p), outNode);
1372 return node_select_singlenode(&This->node, p, outNode);
1376 static HRESULT WINAPI domdoc_get_parsed(
1377 IXMLDOMDocument3 *iface,
1378 VARIANT_BOOL* isParsed )
1380 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1381 FIXME("(%p)->(%p) stub!\n", This, isParsed);
1382 *isParsed = VARIANT_TRUE;
1383 return S_OK;
1386 static HRESULT WINAPI domdoc_get_namespaceURI(
1387 IXMLDOMDocument3 *iface,
1388 BSTR* namespaceURI )
1390 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1391 TRACE("(%p)->(%p)\n", This, namespaceURI);
1392 return return_null_bstr( namespaceURI );
1395 static HRESULT WINAPI domdoc_get_prefix(
1396 IXMLDOMDocument3 *iface,
1397 BSTR* prefix )
1399 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1400 TRACE("(%p)->(%p)\n", This, prefix);
1401 return return_null_bstr( prefix );
1405 static HRESULT WINAPI domdoc_get_baseName(
1406 IXMLDOMDocument3 *iface,
1407 BSTR* name )
1409 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1410 TRACE("(%p)->(%p)\n", This, name);
1411 return return_null_bstr( name );
1415 static HRESULT WINAPI domdoc_transformNodeToObject(
1416 IXMLDOMDocument3 *iface,
1417 IXMLDOMNode* stylesheet,
1418 VARIANT outputObject)
1420 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1421 FIXME("(%p)->(%p %s)\n", This, stylesheet, debugstr_variant(&outputObject));
1422 return E_NOTIMPL;
1426 static HRESULT WINAPI domdoc_get_doctype(
1427 IXMLDOMDocument3 *iface,
1428 IXMLDOMDocumentType** doctype )
1430 domdoc *This = impl_from_IXMLDOMDocument3(iface);
1431 IXMLDOMNode *node;
1432 xmlDtdPtr dtd;
1433 HRESULT hr;
1435 TRACE("(%p)->(%p)\n", This, doctype);
1437 if (!doctype) return E_INVALIDARG;
1439 *doctype = NULL;
1441 dtd = xmlGetIntSubset(get_doc(This));
1442 if (!dtd) return S_FALSE;
1444 node = create_node((xmlNodePtr)dtd);
1445 if (!node) return S_FALSE;
1447 hr = IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMDocumentType, (void**)doctype);
1448 IXMLDOMNode_Release(node);
1450 return hr;
1454 static HRESULT WINAPI domdoc_get_implementation(
1455 IXMLDOMDocument3 *iface,
1456 IXMLDOMImplementation** impl )
1458 domdoc *This = impl_from_IXMLDOMDocument3(iface);
1460 TRACE("(%p)->(%p)\n", This, impl);
1462 if(!impl)
1463 return E_INVALIDARG;
1465 *impl = (IXMLDOMImplementation*)create_doc_Implementation();
1467 return S_OK;
1470 static HRESULT WINAPI domdoc_get_documentElement(
1471 IXMLDOMDocument3 *iface,
1472 IXMLDOMElement** DOMElement )
1474 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1475 IXMLDOMNode *element_node;
1476 xmlNodePtr root;
1477 HRESULT hr;
1479 TRACE("(%p)->(%p)\n", This, DOMElement);
1481 if(!DOMElement)
1482 return E_INVALIDARG;
1484 *DOMElement = NULL;
1486 root = xmlDocGetRootElement( get_doc(This) );
1487 if ( !root )
1488 return S_FALSE;
1490 element_node = create_node( root );
1491 if(!element_node) return S_FALSE;
1493 hr = IXMLDOMNode_QueryInterface(element_node, &IID_IXMLDOMElement, (void**)DOMElement);
1494 IXMLDOMNode_Release(element_node);
1496 return hr;
1500 static HRESULT WINAPI domdoc_put_documentElement(
1501 IXMLDOMDocument3 *iface,
1502 IXMLDOMElement* DOMElement )
1504 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1505 IXMLDOMNode *elementNode;
1506 xmlNodePtr oldRoot;
1507 xmlnode *xmlNode;
1508 HRESULT hr;
1510 TRACE("(%p)->(%p)\n", This, DOMElement);
1512 hr = IXMLDOMElement_QueryInterface( DOMElement, &IID_IXMLDOMNode, (void**)&elementNode );
1513 if(FAILED(hr))
1514 return hr;
1516 xmlNode = get_node_obj( elementNode );
1517 if(!xmlNode) return E_FAIL;
1519 if(!xmlNode->node->parent)
1520 if(xmldoc_remove_orphan(xmlNode->node->doc, xmlNode->node) != S_OK)
1521 WARN("%p is not an orphan of %p\n", xmlNode->node->doc, xmlNode->node);
1523 oldRoot = xmlDocSetRootElement( get_doc(This), xmlNode->node);
1524 IXMLDOMNode_Release( elementNode );
1526 if(oldRoot)
1527 xmldoc_add_orphan(oldRoot->doc, oldRoot);
1529 return S_OK;
1533 static HRESULT WINAPI domdoc_createElement(
1534 IXMLDOMDocument3 *iface,
1535 BSTR tagname,
1536 IXMLDOMElement** element )
1538 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1539 IXMLDOMNode *node;
1540 VARIANT type;
1541 HRESULT hr;
1543 TRACE("(%p)->(%s %p)\n", This, debugstr_w(tagname), element);
1545 if (!element || !tagname) return E_INVALIDARG;
1547 V_VT(&type) = VT_I1;
1548 V_I1(&type) = NODE_ELEMENT;
1550 hr = IXMLDOMDocument3_createNode(iface, type, tagname, NULL, &node);
1551 if (hr == S_OK)
1553 IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMElement, (void**)element);
1554 IXMLDOMNode_Release(node);
1557 return hr;
1561 static HRESULT WINAPI domdoc_createDocumentFragment(
1562 IXMLDOMDocument3 *iface,
1563 IXMLDOMDocumentFragment** frag )
1565 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1566 IXMLDOMNode *node;
1567 VARIANT type;
1568 HRESULT hr;
1570 TRACE("(%p)->(%p)\n", This, frag);
1572 if (!frag) return E_INVALIDARG;
1574 *frag = NULL;
1576 V_VT(&type) = VT_I1;
1577 V_I1(&type) = NODE_DOCUMENT_FRAGMENT;
1579 hr = IXMLDOMDocument3_createNode(iface, type, NULL, NULL, &node);
1580 if (hr == S_OK)
1582 IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMDocumentFragment, (void**)frag);
1583 IXMLDOMNode_Release(node);
1586 return hr;
1590 static HRESULT WINAPI domdoc_createTextNode(
1591 IXMLDOMDocument3 *iface,
1592 BSTR data,
1593 IXMLDOMText** text )
1595 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1596 IXMLDOMNode *node;
1597 VARIANT type;
1598 HRESULT hr;
1600 TRACE("(%p)->(%s %p)\n", This, debugstr_w(data), text);
1602 if (!text) return E_INVALIDARG;
1604 *text = NULL;
1606 V_VT(&type) = VT_I1;
1607 V_I1(&type) = NODE_TEXT;
1609 hr = IXMLDOMDocument3_createNode(iface, type, NULL, NULL, &node);
1610 if (hr == S_OK)
1612 IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMText, (void**)text);
1613 IXMLDOMNode_Release(node);
1614 hr = IXMLDOMText_put_data(*text, data);
1617 return hr;
1621 static HRESULT WINAPI domdoc_createComment(
1622 IXMLDOMDocument3 *iface,
1623 BSTR data,
1624 IXMLDOMComment** comment )
1626 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1627 VARIANT type;
1628 HRESULT hr;
1629 IXMLDOMNode *node;
1631 TRACE("(%p)->(%s %p)\n", This, debugstr_w(data), comment);
1633 if (!comment) return E_INVALIDARG;
1635 *comment = NULL;
1637 V_VT(&type) = VT_I1;
1638 V_I1(&type) = NODE_COMMENT;
1640 hr = IXMLDOMDocument3_createNode(iface, type, NULL, NULL, &node);
1641 if (hr == S_OK)
1643 IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMComment, (void**)comment);
1644 IXMLDOMNode_Release(node);
1645 hr = IXMLDOMComment_put_data(*comment, data);
1648 return hr;
1652 static HRESULT WINAPI domdoc_createCDATASection(
1653 IXMLDOMDocument3 *iface,
1654 BSTR data,
1655 IXMLDOMCDATASection** cdata )
1657 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1658 IXMLDOMNode *node;
1659 VARIANT type;
1660 HRESULT hr;
1662 TRACE("(%p)->(%s %p)\n", This, debugstr_w(data), cdata);
1664 if (!cdata) return E_INVALIDARG;
1666 *cdata = NULL;
1668 V_VT(&type) = VT_I1;
1669 V_I1(&type) = NODE_CDATA_SECTION;
1671 hr = IXMLDOMDocument3_createNode(iface, type, NULL, NULL, &node);
1672 if (hr == S_OK)
1674 IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMCDATASection, (void**)cdata);
1675 IXMLDOMNode_Release(node);
1676 hr = IXMLDOMCDATASection_put_data(*cdata, data);
1679 return hr;
1683 static HRESULT WINAPI domdoc_createProcessingInstruction(
1684 IXMLDOMDocument3 *iface,
1685 BSTR target,
1686 BSTR data,
1687 IXMLDOMProcessingInstruction** pi )
1689 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1690 IXMLDOMNode *node;
1691 VARIANT type;
1692 HRESULT hr;
1694 TRACE("(%p)->(%s %s %p)\n", This, debugstr_w(target), debugstr_w(data), pi);
1696 if (!pi) return E_INVALIDARG;
1698 *pi = NULL;
1700 V_VT(&type) = VT_I1;
1701 V_I1(&type) = NODE_PROCESSING_INSTRUCTION;
1703 hr = IXMLDOMDocument3_createNode(iface, type, target, NULL, &node);
1704 if (hr == S_OK)
1706 xmlnode *node_obj;
1708 /* this is to bypass check in ::put_data() that blocks "<?xml" PIs */
1709 node_obj = get_node_obj(node);
1710 hr = node_set_content(node_obj, data);
1712 IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMProcessingInstruction, (void**)pi);
1713 IXMLDOMNode_Release(node);
1716 return hr;
1720 static HRESULT WINAPI domdoc_createAttribute(
1721 IXMLDOMDocument3 *iface,
1722 BSTR name,
1723 IXMLDOMAttribute** attribute )
1725 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1726 IXMLDOMNode *node;
1727 VARIANT type;
1728 HRESULT hr;
1730 TRACE("(%p)->(%s %p)\n", This, debugstr_w(name), attribute);
1732 if (!attribute || !name) return E_INVALIDARG;
1734 V_VT(&type) = VT_I1;
1735 V_I1(&type) = NODE_ATTRIBUTE;
1737 hr = IXMLDOMDocument3_createNode(iface, type, name, NULL, &node);
1738 if (hr == S_OK)
1740 IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMAttribute, (void**)attribute);
1741 IXMLDOMNode_Release(node);
1744 return hr;
1748 static HRESULT WINAPI domdoc_createEntityReference(
1749 IXMLDOMDocument3 *iface,
1750 BSTR name,
1751 IXMLDOMEntityReference** entityref )
1753 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1754 IXMLDOMNode *node;
1755 VARIANT type;
1756 HRESULT hr;
1758 TRACE("(%p)->(%s %p)\n", This, debugstr_w(name), entityref);
1760 if (!entityref) return E_INVALIDARG;
1762 *entityref = NULL;
1764 V_VT(&type) = VT_I1;
1765 V_I1(&type) = NODE_ENTITY_REFERENCE;
1767 hr = IXMLDOMDocument3_createNode(iface, type, name, NULL, &node);
1768 if (hr == S_OK)
1770 IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMEntityReference, (void**)entityref);
1771 IXMLDOMNode_Release(node);
1774 return hr;
1777 xmlChar* tagName_to_XPath(const BSTR tagName)
1779 xmlChar *query, *tmp;
1780 static const xmlChar mod_pre[] = "*[local-name()='";
1781 static const xmlChar mod_post[] = "']";
1782 static const xmlChar prefix[] = "descendant::";
1783 const WCHAR *tokBegin, *tokEnd;
1784 int len;
1786 query = xmlStrdup(prefix);
1788 tokBegin = tagName;
1789 while (tokBegin && *tokBegin)
1791 switch (*tokBegin)
1793 case '/':
1794 query = xmlStrcat(query, BAD_CAST "/");
1795 ++tokBegin;
1796 break;
1797 case '*':
1798 query = xmlStrcat(query, BAD_CAST "*");
1799 ++tokBegin;
1800 break;
1801 default:
1802 query = xmlStrcat(query, mod_pre);
1803 tokEnd = tokBegin;
1804 while (*tokEnd && *tokEnd != '/')
1805 ++tokEnd;
1806 len = WideCharToMultiByte(CP_UTF8, 0, tokBegin, tokEnd-tokBegin, NULL, 0, NULL, NULL);
1807 tmp = xmlMalloc(len);
1808 WideCharToMultiByte(CP_UTF8, 0, tokBegin, tokEnd-tokBegin, (char*)tmp, len, NULL, NULL);
1809 query = xmlStrncat(query, tmp, len);
1810 xmlFree(tmp);
1811 tokBegin = tokEnd;
1812 query = xmlStrcat(query, mod_post);
1816 return query;
1819 static HRESULT WINAPI domdoc_getElementsByTagName(
1820 IXMLDOMDocument3 *iface,
1821 BSTR tagName,
1822 IXMLDOMNodeList** resultList )
1824 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1825 xmlChar *query;
1826 HRESULT hr;
1827 BOOL XPath;
1829 TRACE("(%p)->(%s, %p)\n", This, debugstr_w(tagName), resultList);
1831 if (!tagName || !resultList) return E_INVALIDARG;
1833 XPath = This->properties->XPath;
1834 This->properties->XPath = TRUE;
1835 query = tagName_to_XPath(tagName);
1836 hr = create_selection((xmlNodePtr)get_doc(This), query, resultList);
1837 xmlFree(query);
1838 This->properties->XPath = XPath;
1840 return hr;
1843 static HRESULT get_node_type(VARIANT Type, DOMNodeType * type)
1845 VARIANT tmp;
1846 HRESULT hr;
1848 VariantInit(&tmp);
1849 hr = VariantChangeType(&tmp, &Type, 0, VT_I4);
1850 if(FAILED(hr))
1851 return E_INVALIDARG;
1853 *type = V_I4(&tmp);
1855 return S_OK;
1858 static HRESULT WINAPI domdoc_createNode(
1859 IXMLDOMDocument3 *iface,
1860 VARIANT Type,
1861 BSTR name,
1862 BSTR namespaceURI,
1863 IXMLDOMNode** node )
1865 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1866 DOMNodeType node_type;
1867 xmlNodePtr xmlnode;
1868 xmlChar *xml_name, *href;
1869 HRESULT hr;
1871 TRACE("(%p)->(%s %s %s %p)\n", This, debugstr_variant(&Type), debugstr_w(name), debugstr_w(namespaceURI), node);
1873 if(!node) return E_INVALIDARG;
1875 hr = get_node_type(Type, &node_type);
1876 if(FAILED(hr)) return hr;
1878 if(namespaceURI && namespaceURI[0] && node_type != NODE_ELEMENT)
1879 FIXME("nodes with namespaces currently not supported.\n");
1881 TRACE("node_type %d\n", node_type);
1883 /* exit earlier for types that need name */
1884 switch(node_type)
1886 case NODE_ELEMENT:
1887 case NODE_ATTRIBUTE:
1888 case NODE_ENTITY_REFERENCE:
1889 case NODE_PROCESSING_INSTRUCTION:
1890 if (!name || *name == 0) return E_FAIL;
1891 break;
1892 default:
1893 break;
1896 xml_name = xmlchar_from_wchar(name);
1897 /* prevent empty href to be allocated */
1898 href = namespaceURI ? xmlchar_from_wchar(namespaceURI) : NULL;
1900 switch(node_type)
1902 case NODE_ELEMENT:
1904 xmlChar *local, *prefix;
1906 local = xmlSplitQName2(xml_name, &prefix);
1908 xmlnode = xmlNewDocNode(get_doc(This), NULL, local ? local : xml_name, NULL);
1910 /* allow to create default namespace xmlns= */
1911 if (local || (href && *href))
1913 xmlNsPtr ns = xmlNewNs(xmlnode, href, prefix);
1914 xmlSetNs(xmlnode, ns);
1917 xmlFree(local);
1918 xmlFree(prefix);
1920 break;
1922 case NODE_ATTRIBUTE:
1923 xmlnode = (xmlNodePtr)xmlNewDocProp(get_doc(This), xml_name, NULL);
1924 break;
1925 case NODE_TEXT:
1926 xmlnode = (xmlNodePtr)xmlNewDocText(get_doc(This), NULL);
1927 break;
1928 case NODE_CDATA_SECTION:
1929 xmlnode = xmlNewCDataBlock(get_doc(This), NULL, 0);
1930 break;
1931 case NODE_ENTITY_REFERENCE:
1932 xmlnode = xmlNewReference(get_doc(This), xml_name);
1933 break;
1934 case NODE_PROCESSING_INSTRUCTION:
1935 #ifdef HAVE_XMLNEWDOCPI
1936 xmlnode = xmlNewDocPI(get_doc(This), xml_name, NULL);
1937 #else
1938 FIXME("xmlNewDocPI() not supported, use libxml2 2.6.15 or greater\n");
1939 xmlnode = NULL;
1940 #endif
1941 break;
1942 case NODE_COMMENT:
1943 xmlnode = xmlNewDocComment(get_doc(This), NULL);
1944 break;
1945 case NODE_DOCUMENT_FRAGMENT:
1946 xmlnode = xmlNewDocFragment(get_doc(This));
1947 break;
1948 /* unsupported types */
1949 case NODE_DOCUMENT:
1950 case NODE_DOCUMENT_TYPE:
1951 case NODE_ENTITY:
1952 case NODE_NOTATION:
1953 heap_free(xml_name);
1954 return E_INVALIDARG;
1955 default:
1956 FIXME("unhandled node type %d\n", node_type);
1957 xmlnode = NULL;
1958 break;
1961 *node = create_node(xmlnode);
1962 heap_free(xml_name);
1963 heap_free(href);
1965 if(*node)
1967 TRACE("created node (%d, %p, %p)\n", node_type, *node, xmlnode);
1968 xmldoc_add_orphan(xmlnode->doc, xmlnode);
1969 return S_OK;
1972 return E_FAIL;
1975 static HRESULT WINAPI domdoc_nodeFromID(
1976 IXMLDOMDocument3 *iface,
1977 BSTR idString,
1978 IXMLDOMNode** node )
1980 domdoc *This = impl_from_IXMLDOMDocument3(iface);
1981 FIXME("(%p)->(%s %p)\n", This, debugstr_w(idString), node);
1982 return E_NOTIMPL;
1985 static HRESULT domdoc_onDataAvailable(void *obj, char *ptr, DWORD len)
1987 domdoc *This = obj;
1988 xmlDocPtr xmldoc;
1990 xmldoc = doparse(This, ptr, len, XML_CHAR_ENCODING_NONE);
1991 if(xmldoc) {
1992 xmldoc->_private = create_priv();
1993 return attach_xmldoc(This, xmldoc);
1996 return S_OK;
1999 static HRESULT domdoc_load_moniker(domdoc *This, IMoniker *mon)
2001 bsc_t *bsc;
2002 HRESULT hr;
2004 hr = bind_url(mon, domdoc_onDataAvailable, This, &bsc);
2005 if(FAILED(hr))
2006 return hr;
2008 if(This->bsc) {
2009 hr = detach_bsc(This->bsc);
2010 if(FAILED(hr))
2011 return hr;
2014 This->bsc = bsc;
2015 return S_OK;
2018 static HRESULT WINAPI domdoc_load(
2019 IXMLDOMDocument3 *iface,
2020 VARIANT source,
2021 VARIANT_BOOL* isSuccessful )
2023 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2024 LPWSTR filename = NULL;
2025 HRESULT hr = S_FALSE;
2026 IXMLDOMDocument3 *pNewDoc = NULL;
2027 IStream *pStream = NULL;
2028 xmlDocPtr xmldoc;
2030 TRACE("(%p)->(%s)\n", This, debugstr_variant(&source));
2032 if (!isSuccessful)
2033 return E_POINTER;
2034 *isSuccessful = VARIANT_FALSE;
2036 assert( &This->node );
2038 switch( V_VT(&source) )
2040 case VT_BSTR:
2041 filename = V_BSTR(&source);
2042 break;
2043 case VT_BSTR|VT_BYREF:
2044 if (!V_BSTRREF(&source)) return E_INVALIDARG;
2045 filename = *V_BSTRREF(&source);
2046 break;
2047 case VT_ARRAY|VT_UI1:
2049 SAFEARRAY *psa = V_ARRAY(&source);
2050 char *str;
2051 LONG len;
2052 UINT dim = SafeArrayGetDim(psa);
2054 switch (dim)
2056 case 0:
2057 ERR("SAFEARRAY == NULL\n");
2058 hr = This->error = E_INVALIDARG;
2059 break;
2060 case 1:
2061 /* Only takes UTF-8 strings.
2062 * NOT NULL-terminated. */
2063 SafeArrayAccessData(psa, (void**)&str);
2064 SafeArrayGetUBound(psa, 1, &len);
2066 if ((xmldoc = doparse(This, str, ++len, XML_CHAR_ENCODING_UTF8)))
2068 hr = This->error = S_OK;
2069 *isSuccessful = VARIANT_TRUE;
2070 TRACE("parsed document %p\n", xmldoc);
2072 else
2074 This->error = E_FAIL;
2075 TRACE("failed to parse document\n");
2078 SafeArrayUnaccessData(psa);
2080 if(xmldoc)
2082 xmldoc->_private = create_priv();
2083 return attach_xmldoc(This, xmldoc);
2085 break;
2086 default:
2087 FIXME("unhandled SAFEARRAY dim: %d\n", dim);
2088 hr = This->error = E_NOTIMPL;
2091 break;
2092 case VT_UNKNOWN:
2093 hr = IUnknown_QueryInterface(V_UNKNOWN(&source), &IID_IXMLDOMDocument3, (void**)&pNewDoc);
2094 if(hr == S_OK)
2096 if(pNewDoc)
2098 domdoc *newDoc = impl_from_IXMLDOMDocument3( pNewDoc );
2100 xmldoc = xmlCopyDoc(get_doc(newDoc), 1);
2101 xmldoc->_private = create_priv();
2102 hr = attach_xmldoc(This, xmldoc);
2104 if(SUCCEEDED(hr))
2105 *isSuccessful = VARIANT_TRUE;
2107 return hr;
2110 hr = IUnknown_QueryInterface(V_UNKNOWN(&source), &IID_IStream, (void**)&pStream);
2111 if(hr == S_OK)
2113 IPersistStream *pDocStream;
2114 hr = IUnknown_QueryInterface(iface, &IID_IPersistStream, (void**)&pDocStream);
2115 if(hr == S_OK)
2117 hr = IPersistStream_Load(pDocStream, pStream);
2118 IStream_Release(pStream);
2119 if(hr == S_OK)
2121 *isSuccessful = VARIANT_TRUE;
2123 TRACE("Using IStream to load Document\n");
2124 return S_OK;
2126 else
2128 ERR("xmldoc_IPersistStream_Load failed (%d)\n", hr);
2131 else
2133 ERR("QueryInterface IID_IPersistStream failed (%d)\n", hr);
2136 else
2138 /* ISequentialStream */
2139 FIXME("Unknown type not supported (%d) (%p)(%p)\n", hr, pNewDoc, V_UNKNOWN(&source)->lpVtbl);
2141 break;
2142 default:
2143 FIXME("VT type not supported (%d)\n", V_VT(&source));
2146 if ( filename )
2148 IMoniker *mon;
2150 hr = create_moniker_from_url( filename, &mon);
2151 if ( SUCCEEDED(hr) )
2153 hr = domdoc_load_moniker( This, mon );
2154 IMoniker_Release(mon);
2157 if ( FAILED(hr) )
2158 This->error = E_FAIL;
2159 else
2161 hr = This->error = S_OK;
2162 *isSuccessful = VARIANT_TRUE;
2166 if(!filename || FAILED(hr)) {
2167 xmldoc = xmlNewDoc(NULL);
2168 xmldoc->_private = create_priv();
2169 hr = attach_xmldoc(This, xmldoc);
2170 if(SUCCEEDED(hr))
2171 hr = S_FALSE;
2174 TRACE("ret (%d)\n", hr);
2176 return hr;
2180 static HRESULT WINAPI domdoc_get_readyState(
2181 IXMLDOMDocument3 *iface,
2182 LONG *value )
2184 domdoc *This = impl_from_IXMLDOMDocument3(iface);
2185 FIXME("stub! (%p)->(%p)\n", This, value);
2187 if (!value)
2188 return E_INVALIDARG;
2190 *value = READYSTATE_COMPLETE;
2191 return S_OK;
2195 static HRESULT WINAPI domdoc_get_parseError(
2196 IXMLDOMDocument3 *iface,
2197 IXMLDOMParseError** errorObj )
2199 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2200 static const WCHAR err[] = {'e','r','r','o','r',0};
2201 BSTR error_string = NULL;
2203 FIXME("(%p)->(%p): creating a dummy parseError\n", iface, errorObj);
2205 if(This->error)
2206 error_string = SysAllocString(err);
2208 *errorObj = create_parseError(This->error, NULL, error_string, NULL, 0, 0, 0);
2209 if(!*errorObj) return E_OUTOFMEMORY;
2210 return S_OK;
2214 static HRESULT WINAPI domdoc_get_url(
2215 IXMLDOMDocument3 *iface,
2216 BSTR* urlString )
2218 domdoc *This = impl_from_IXMLDOMDocument3(iface);
2219 FIXME("(%p)->(%p)\n", This, urlString);
2220 return E_NOTIMPL;
2224 static HRESULT WINAPI domdoc_get_async(
2225 IXMLDOMDocument3 *iface,
2226 VARIANT_BOOL* isAsync )
2228 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2230 TRACE("(%p)->(%p: %d)\n", This, isAsync, This->async);
2231 *isAsync = This->async;
2232 return S_OK;
2236 static HRESULT WINAPI domdoc_put_async(
2237 IXMLDOMDocument3 *iface,
2238 VARIANT_BOOL isAsync )
2240 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2242 TRACE("(%p)->(%d)\n", This, isAsync);
2243 This->async = isAsync;
2244 return S_OK;
2248 static HRESULT WINAPI domdoc_abort(
2249 IXMLDOMDocument3 *iface )
2251 domdoc *This = impl_from_IXMLDOMDocument3(iface);
2252 FIXME("%p\n", This);
2253 return E_NOTIMPL;
2256 /* don't rely on data to be in BSTR format, treat it as WCHAR string */
2257 static HRESULT WINAPI domdoc_loadXML(
2258 IXMLDOMDocument3 *iface,
2259 BSTR data,
2260 VARIANT_BOOL* isSuccessful )
2262 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2263 xmlDocPtr xmldoc = NULL;
2264 HRESULT hr = S_FALSE, hr2;
2266 TRACE("(%p)->(%s %p)\n", This, debugstr_w(data), isSuccessful );
2268 assert ( &This->node );
2270 if ( isSuccessful )
2272 *isSuccessful = VARIANT_FALSE;
2274 if (data)
2276 WCHAR *ptr = data;
2278 /* skip leading spaces if needed */
2279 if (This->properties->version == MSXML_DEFAULT || This->properties->version == MSXML26)
2280 while (*ptr)
2281 if (isspaceW(*ptr)) ptr++; else break;
2283 xmldoc = doparse(This, (char*)ptr, strlenW(ptr)*sizeof(WCHAR), XML_CHAR_ENCODING_UTF16LE);
2284 if ( !xmldoc )
2286 This->error = E_FAIL;
2287 TRACE("failed to parse document\n");
2289 else
2291 hr = This->error = S_OK;
2292 *isSuccessful = VARIANT_TRUE;
2293 TRACE("parsed document %p\n", xmldoc);
2298 if(!xmldoc)
2299 xmldoc = xmlNewDoc(NULL);
2300 xmldoc->_private = create_priv();
2301 hr2 = attach_xmldoc(This, xmldoc);
2302 if( FAILED(hr2) )
2303 hr = hr2;
2305 return hr;
2308 static int XMLCALL domdoc_save_writecallback(void *ctx, const char *buffer, int len)
2310 DWORD written = -1;
2312 if(!WriteFile(ctx, buffer, len, &written, NULL))
2314 WARN("write error\n");
2315 return -1;
2317 else
2318 return written;
2321 static int XMLCALL domdoc_save_closecallback(void *ctx)
2323 return CloseHandle(ctx) ? 0 : -1;
2326 static int XMLCALL domdoc_stream_save_writecallback(void *ctx, const char *buffer, int len)
2328 ULONG written = 0;
2329 HRESULT hr;
2331 hr = IStream_Write((IStream*)ctx, buffer, len, &written);
2332 if (hr != S_OK)
2334 WARN("stream write error: 0x%08x\n", hr);
2335 return -1;
2337 else
2338 return written;
2341 static int XMLCALL domdoc_stream_save_closecallback(void *ctx)
2343 IStream_Release((IStream*)ctx);
2344 return 0;
2347 static HRESULT WINAPI domdoc_save(
2348 IXMLDOMDocument3 *iface,
2349 VARIANT destination )
2351 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2352 xmlSaveCtxtPtr ctx = NULL;
2353 xmlNodePtr xmldecl;
2354 HRESULT ret = S_OK;
2356 TRACE("(%p)->(%s)\n", This, debugstr_variant(&destination));
2358 switch (V_VT(&destination))
2360 case VT_UNKNOWN:
2362 IUnknown *pUnk = V_UNKNOWN(&destination);
2363 IXMLDOMDocument3 *document;
2364 IStream *stream;
2366 ret = IUnknown_QueryInterface(pUnk, &IID_IXMLDOMDocument3, (void**)&document);
2367 if(ret == S_OK)
2369 VARIANT_BOOL success;
2370 BSTR xml;
2372 ret = IXMLDOMDocument3_get_xml(iface, &xml);
2373 if(ret == S_OK)
2375 ret = IXMLDOMDocument3_loadXML(document, xml, &success);
2376 SysFreeString(xml);
2379 IXMLDOMDocument3_Release(document);
2380 return ret;
2383 ret = IUnknown_QueryInterface(pUnk, &IID_IStream, (void**)&stream);
2384 if(ret == S_OK)
2386 ctx = xmlSaveToIO(domdoc_stream_save_writecallback,
2387 domdoc_stream_save_closecallback, stream, NULL, XML_SAVE_NO_DECL);
2389 if(!ctx)
2391 IStream_Release(stream);
2392 return E_FAIL;
2396 break;
2398 case VT_BSTR:
2399 case VT_BSTR | VT_BYREF:
2401 /* save with file path */
2402 HANDLE handle = CreateFileW( (V_VT(&destination) & VT_BYREF)? *V_BSTRREF(&destination) : V_BSTR(&destination),
2403 GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL );
2404 if( handle == INVALID_HANDLE_VALUE )
2406 WARN("failed to create file\n");
2407 return E_FAIL;
2410 /* disable top XML declaration */
2411 ctx = xmlSaveToIO(domdoc_save_writecallback, domdoc_save_closecallback,
2412 handle, NULL, XML_SAVE_NO_DECL);
2413 if (!ctx)
2415 CloseHandle(handle);
2416 return E_FAIL;
2419 break;
2421 default:
2422 FIXME("Unhandled VARIANT: %s\n", debugstr_variant(&destination));
2423 return S_FALSE;
2426 xmldecl = xmldoc_unlink_xmldecl(get_doc(This));
2427 if (xmlSaveDoc(ctx, get_doc(This)) == -1) ret = S_FALSE;
2428 xmldoc_link_xmldecl(get_doc(This), xmldecl);
2430 /* will release resources through close callback */
2431 xmlSaveClose(ctx);
2433 return ret;
2436 static HRESULT WINAPI domdoc_get_validateOnParse(
2437 IXMLDOMDocument3 *iface,
2438 VARIANT_BOOL* isValidating )
2440 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2441 TRACE("(%p)->(%p: %d)\n", This, isValidating, This->validating);
2442 *isValidating = This->validating;
2443 return S_OK;
2447 static HRESULT WINAPI domdoc_put_validateOnParse(
2448 IXMLDOMDocument3 *iface,
2449 VARIANT_BOOL isValidating )
2451 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2452 TRACE("(%p)->(%d)\n", This, isValidating);
2453 This->validating = isValidating;
2454 return S_OK;
2458 static HRESULT WINAPI domdoc_get_resolveExternals(
2459 IXMLDOMDocument3 *iface,
2460 VARIANT_BOOL* isResolving )
2462 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2463 TRACE("(%p)->(%p: %d)\n", This, isResolving, This->resolving);
2464 *isResolving = This->resolving;
2465 return S_OK;
2469 static HRESULT WINAPI domdoc_put_resolveExternals(
2470 IXMLDOMDocument3 *iface,
2471 VARIANT_BOOL isResolving )
2473 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2474 TRACE("(%p)->(%d)\n", This, isResolving);
2475 This->resolving = isResolving;
2476 return S_OK;
2480 static HRESULT WINAPI domdoc_get_preserveWhiteSpace(
2481 IXMLDOMDocument3 *iface,
2482 VARIANT_BOOL* isPreserving )
2484 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2485 TRACE("(%p)->(%p: %d)\n", This, isPreserving, This->properties->preserving);
2486 *isPreserving = This->properties->preserving;
2487 return S_OK;
2491 static HRESULT WINAPI domdoc_put_preserveWhiteSpace(
2492 IXMLDOMDocument3 *iface,
2493 VARIANT_BOOL isPreserving )
2495 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2496 TRACE("(%p)->(%d)\n", This, isPreserving);
2497 This->properties->preserving = isPreserving;
2498 return S_OK;
2502 static HRESULT WINAPI domdoc_put_onreadystatechange(
2503 IXMLDOMDocument3 *iface,
2504 VARIANT event )
2506 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2508 TRACE("(%p)->(%s)\n", This, debugstr_variant(&event));
2509 return set_doc_event(This, EVENTID_READYSTATECHANGE, &event);
2513 static HRESULT WINAPI domdoc_put_onDataAvailable(IXMLDOMDocument3 *iface, VARIANT sink)
2515 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2516 FIXME("(%p)->(%s): stub\n", This, debugstr_variant(&sink));
2517 return E_NOTIMPL;
2520 static HRESULT WINAPI domdoc_put_onTransformNode(IXMLDOMDocument3 *iface, VARIANT sink )
2522 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2523 FIXME("(%p)->(%s): stub\n", This, debugstr_variant(&sink));
2524 return E_NOTIMPL;
2527 static HRESULT WINAPI domdoc_get_namespaces(
2528 IXMLDOMDocument3* iface,
2529 IXMLDOMSchemaCollection** collection )
2531 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2532 HRESULT hr;
2534 FIXME("(%p)->(%p): semi-stub\n", This, collection);
2536 if (!collection) return E_POINTER;
2538 if (!This->namespaces)
2540 hr = SchemaCache_create(This->properties->version, NULL, (void**)&This->namespaces);
2541 if (hr != S_OK) return hr;
2543 hr = cache_from_doc_ns(This->namespaces, &This->node);
2544 if (hr != S_OK)
2545 release_namespaces(This);
2548 if (This->namespaces)
2549 return IXMLDOMSchemaCollection2_QueryInterface(This->namespaces,
2550 &IID_IXMLDOMSchemaCollection, (void**)collection);
2552 return hr;
2555 static HRESULT WINAPI domdoc_get_schemas(
2556 IXMLDOMDocument3* iface,
2557 VARIANT* var1 )
2559 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2560 HRESULT hr = S_FALSE;
2561 IXMLDOMSchemaCollection2* cur_schema = This->properties->schemaCache;
2563 TRACE("(%p)->(%p)\n", This, var1);
2565 VariantInit(var1); /* Test shows we don't call VariantClear here */
2566 V_VT(var1) = VT_NULL;
2568 if(cur_schema)
2570 hr = IXMLDOMSchemaCollection2_QueryInterface(cur_schema, &IID_IDispatch, (void**)&V_DISPATCH(var1));
2571 if(SUCCEEDED(hr))
2572 V_VT(var1) = VT_DISPATCH;
2574 return hr;
2577 static HRESULT WINAPI domdoc_putref_schemas(
2578 IXMLDOMDocument3* iface,
2579 VARIANT schema)
2581 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2582 HRESULT hr = E_FAIL;
2583 IXMLDOMSchemaCollection2* new_schema = NULL;
2585 FIXME("(%p)->(%s): semi-stub\n", This, debugstr_variant(&schema));
2586 switch(V_VT(&schema))
2588 case VT_UNKNOWN:
2589 hr = IUnknown_QueryInterface(V_UNKNOWN(&schema), &IID_IXMLDOMSchemaCollection, (void**)&new_schema);
2590 break;
2592 case VT_DISPATCH:
2593 hr = IDispatch_QueryInterface(V_DISPATCH(&schema), &IID_IXMLDOMSchemaCollection, (void**)&new_schema);
2594 break;
2596 case VT_NULL:
2597 case VT_EMPTY:
2598 hr = S_OK;
2599 break;
2601 default:
2602 WARN("Can't get schema from vt %x\n", V_VT(&schema));
2605 if(SUCCEEDED(hr))
2607 IXMLDOMSchemaCollection2* old_schema = InterlockedExchangePointer((void**)&This->properties->schemaCache, new_schema);
2608 if(old_schema) IXMLDOMSchemaCollection2_Release(old_schema);
2611 return hr;
2614 static inline BOOL is_wellformed(xmlDocPtr doc)
2616 #ifdef HAVE_XMLDOC_PROPERTIES
2617 return doc->properties & XML_DOC_WELLFORMED;
2618 #else
2619 /* Not a full check, but catches the worst violations */
2620 xmlNodePtr child;
2621 int root = 0;
2623 for (child = doc->children; child != NULL; child = child->next)
2625 switch (child->type)
2627 case XML_ELEMENT_NODE:
2628 if (++root > 1)
2629 return FALSE;
2630 break;
2631 case XML_TEXT_NODE:
2632 case XML_CDATA_SECTION_NODE:
2633 return FALSE;
2634 break;
2635 default:
2636 break;
2640 return root == 1;
2641 #endif
2644 static void LIBXML2_LOG_CALLBACK validate_error(void* ctx, char const* msg, ...)
2646 va_list ap;
2647 va_start(ap, msg);
2648 LIBXML2_CALLBACK_ERR(domdoc_validateNode, msg, ap);
2649 va_end(ap);
2652 static void LIBXML2_LOG_CALLBACK validate_warning(void* ctx, char const* msg, ...)
2654 va_list ap;
2655 va_start(ap, msg);
2656 LIBXML2_CALLBACK_WARN(domdoc_validateNode, msg, ap);
2657 va_end(ap);
2660 static HRESULT WINAPI domdoc_validateNode(
2661 IXMLDOMDocument3* iface,
2662 IXMLDOMNode* node,
2663 IXMLDOMParseError** err)
2665 domdoc* This = impl_from_IXMLDOMDocument3(iface);
2666 LONG state, err_code = 0;
2667 HRESULT hr = S_OK;
2668 int validated = 0;
2670 TRACE("(%p)->(%p, %p)\n", This, node, err);
2671 IXMLDOMDocument3_get_readyState(iface, &state);
2672 if (state != READYSTATE_COMPLETE)
2674 if (err)
2675 *err = create_parseError(err_code, NULL, NULL, NULL, 0, 0, 0);
2676 return E_PENDING;
2679 if (!node)
2681 if (err)
2682 *err = create_parseError(err_code, NULL, NULL, NULL, 0, 0, 0);
2683 return E_POINTER;
2686 if (!get_node_obj(node)->node || get_node_obj(node)->node->doc != get_doc(This))
2688 if (err)
2689 *err = create_parseError(err_code, NULL, NULL, NULL, 0, 0, 0);
2690 return E_FAIL;
2693 if (!is_wellformed(get_doc(This)))
2695 ERR("doc not well-formed\n");
2696 if (err)
2697 *err = create_parseError(E_XML_NOTWF, NULL, NULL, NULL, 0, 0, 0);
2698 return S_FALSE;
2701 /* DTD validation */
2702 if (get_doc(This)->intSubset || get_doc(This)->extSubset)
2704 xmlValidCtxtPtr vctx = xmlNewValidCtxt();
2705 vctx->error = validate_error;
2706 vctx->warning = validate_warning;
2707 ++validated;
2709 if (!((node == (IXMLDOMNode*)iface)?
2710 xmlValidateDocument(vctx, get_doc(This)) :
2711 xmlValidateElement(vctx, get_doc(This), get_node_obj(node)->node)))
2713 /* TODO: get a real error code here */
2714 TRACE("DTD validation failed\n");
2715 err_code = E_XML_INVALID;
2716 hr = S_FALSE;
2718 xmlFreeValidCtxt(vctx);
2721 /* Schema validation */
2722 if (hr == S_OK && This->properties->schemaCache != NULL)
2725 hr = SchemaCache_validate_tree(This->properties->schemaCache, get_node_obj(node)->node);
2726 if (SUCCEEDED(hr))
2728 ++validated;
2729 /* TODO: get a real error code here */
2730 if (hr == S_OK)
2732 TRACE("schema validation succeeded\n");
2734 else
2736 ERR("schema validation failed\n");
2737 err_code = E_XML_INVALID;
2740 else
2742 /* not really OK, just didn't find a schema for the ns */
2743 hr = S_OK;
2747 if (!validated)
2749 ERR("no DTD or schema found\n");
2750 err_code = E_XML_NODTD;
2751 hr = S_FALSE;
2754 if (err)
2755 *err = create_parseError(err_code, NULL, NULL, NULL, 0, 0, 0);
2757 return hr;
2760 static HRESULT WINAPI domdoc_validate(
2761 IXMLDOMDocument3* iface,
2762 IXMLDOMParseError** err)
2764 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2765 TRACE("(%p)->(%p)\n", This, err);
2766 return IXMLDOMDocument3_validateNode(iface, (IXMLDOMNode*)iface, err);
2769 static HRESULT WINAPI domdoc_setProperty(
2770 IXMLDOMDocument3* iface,
2771 BSTR p,
2772 VARIANT value)
2774 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2776 TRACE("(%p)->(%s %s)\n", This, debugstr_w(p), debugstr_variant(&value));
2778 if (lstrcmpiW(p, PropertySelectionLanguageW) == 0)
2780 VARIANT varStr;
2781 HRESULT hr;
2782 BSTR bstr;
2784 V_VT(&varStr) = VT_EMPTY;
2785 if (V_VT(&value) != VT_BSTR)
2787 if (FAILED(hr = VariantChangeType(&varStr, &value, 0, VT_BSTR)))
2788 return hr;
2789 bstr = V_BSTR(&varStr);
2791 else
2792 bstr = V_BSTR(&value);
2794 hr = S_OK;
2795 if (lstrcmpiW(bstr, PropValueXPathW) == 0)
2796 This->properties->XPath = TRUE;
2797 else if (lstrcmpiW(bstr, PropValueXSLPatternW) == 0)
2798 This->properties->XPath = FALSE;
2799 else
2800 hr = E_FAIL;
2802 VariantClear(&varStr);
2803 return hr;
2805 else if (lstrcmpiW(p, PropertySelectionNamespacesW) == 0)
2807 xmlChar *nsStr = (xmlChar*)This->properties->selectNsStr;
2808 struct list *pNsList;
2809 VARIANT varStr;
2810 HRESULT hr;
2811 BSTR bstr;
2813 V_VT(&varStr) = VT_EMPTY;
2814 if (V_VT(&value) != VT_BSTR)
2816 if (FAILED(hr = VariantChangeType(&varStr, &value, 0, VT_BSTR)))
2817 return hr;
2818 bstr = V_BSTR(&varStr);
2820 else
2821 bstr = V_BSTR(&value);
2823 hr = S_OK;
2825 pNsList = &(This->properties->selectNsList);
2826 clear_selectNsList(pNsList);
2827 heap_free(nsStr);
2828 nsStr = xmlchar_from_wchar(bstr);
2830 TRACE("property value: \"%s\"\n", debugstr_w(bstr));
2832 This->properties->selectNsStr = nsStr;
2833 This->properties->selectNsStr_len = xmlStrlen(nsStr);
2834 if (bstr && *bstr)
2836 xmlChar *pTokBegin, *pTokEnd, *pTokInner;
2837 select_ns_entry* ns_entry = NULL;
2838 xmlXPathContextPtr ctx;
2840 ctx = xmlXPathNewContext(This->node.node->doc);
2841 pTokBegin = nsStr;
2843 /* skip leading spaces */
2844 while (*pTokBegin == ' ' || *pTokBegin == '\n' ||
2845 *pTokBegin == '\t' || *pTokBegin == '\r')
2846 ++pTokBegin;
2848 for (; *pTokBegin; pTokBegin = pTokEnd)
2850 if (ns_entry)
2851 memset(ns_entry, 0, sizeof(select_ns_entry));
2852 else
2853 ns_entry = heap_alloc_zero(sizeof(select_ns_entry));
2855 while (*pTokBegin == ' ')
2856 ++pTokBegin;
2857 pTokEnd = pTokBegin;
2858 while (*pTokEnd != ' ' && *pTokEnd != 0)
2859 ++pTokEnd;
2861 if (xmlStrncmp(pTokBegin, (xmlChar const*)"xmlns", 5) != 0)
2863 hr = E_FAIL;
2864 WARN("Syntax error in xmlns string: %s\n\tat token: %s\n",
2865 debugstr_w(bstr), debugstr_an((const char*)pTokBegin, pTokEnd-pTokBegin));
2866 continue;
2869 pTokBegin += 5;
2870 if (*pTokBegin == '=')
2872 /*valid for XSLPattern?*/
2873 FIXME("Setting default xmlns not supported - skipping.\n");
2874 continue;
2876 else if (*pTokBegin == ':')
2878 ns_entry->prefix = ++pTokBegin;
2879 for (pTokInner = pTokBegin; pTokInner != pTokEnd && *pTokInner != '='; ++pTokInner)
2882 if (pTokInner == pTokEnd)
2884 hr = E_FAIL;
2885 WARN("Syntax error in xmlns string: %s\n\tat token: %s\n",
2886 debugstr_w(bstr), debugstr_an((const char*)pTokBegin, pTokEnd-pTokBegin));
2887 continue;
2890 ns_entry->prefix_end = *pTokInner;
2891 *pTokInner = 0;
2892 ++pTokInner;
2894 if (pTokEnd-pTokInner > 1 &&
2895 ((*pTokInner == '\'' && *(pTokEnd-1) == '\'') ||
2896 (*pTokInner == '"' && *(pTokEnd-1) == '"')))
2898 ns_entry->href = ++pTokInner;
2899 ns_entry->href_end = *(pTokEnd-1);
2900 *(pTokEnd-1) = 0;
2901 list_add_tail(pNsList, &ns_entry->entry);
2902 /*let libxml figure out if they're valid from here ;)*/
2903 if (xmlXPathRegisterNs(ctx, ns_entry->prefix, ns_entry->href) != 0)
2905 hr = E_FAIL;
2907 ns_entry = NULL;
2908 continue;
2910 else
2912 WARN("Syntax error in xmlns string: %s\n\tat token: %s\n",
2913 debugstr_w(bstr), debugstr_an((const char*)pTokInner, pTokEnd-pTokInner));
2914 list_add_tail(pNsList, &ns_entry->entry);
2916 ns_entry = NULL;
2917 hr = E_FAIL;
2918 continue;
2921 else
2923 hr = E_FAIL;
2924 continue;
2927 heap_free(ns_entry);
2928 xmlXPathFreeContext(ctx);
2931 VariantClear(&varStr);
2932 return hr;
2934 else if (lstrcmpiW(p, PropertyProhibitDTDW) == 0 ||
2935 lstrcmpiW(p, PropertyNewParserW) == 0 ||
2936 lstrcmpiW(p, PropertyResolveExternalsW) == 0)
2938 /* Ignore */
2939 FIXME("Ignoring property %s, value %d\n", debugstr_w(p), V_BOOL(&value));
2940 return S_OK;
2943 FIXME("Unknown property %s\n", debugstr_w(p));
2944 return E_FAIL;
2947 static HRESULT WINAPI domdoc_getProperty(
2948 IXMLDOMDocument3* iface,
2949 BSTR p,
2950 VARIANT* var)
2952 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2954 TRACE("(%p)->(%s)\n", This, debugstr_w(p));
2956 if (!var)
2957 return E_INVALIDARG;
2959 if (lstrcmpiW(p, PropertySelectionLanguageW) == 0)
2961 V_VT(var) = VT_BSTR;
2962 V_BSTR(var) = This->properties->XPath ?
2963 SysAllocString(PropValueXPathW) :
2964 SysAllocString(PropValueXSLPatternW);
2965 return V_BSTR(var) ? S_OK : E_OUTOFMEMORY;
2967 else if (lstrcmpiW(p, PropertySelectionNamespacesW) == 0)
2969 int lenA, lenW;
2970 BSTR rebuiltStr, cur;
2971 const xmlChar *nsStr;
2972 struct list *pNsList;
2973 select_ns_entry* pNsEntry;
2975 V_VT(var) = VT_BSTR;
2976 nsStr = This->properties->selectNsStr;
2977 pNsList = &This->properties->selectNsList;
2978 lenA = This->properties->selectNsStr_len;
2979 lenW = MultiByteToWideChar(CP_UTF8, 0, (LPCSTR)nsStr, lenA+1, NULL, 0);
2980 rebuiltStr = heap_alloc(lenW*sizeof(WCHAR));
2981 MultiByteToWideChar(CP_UTF8, 0, (LPCSTR)nsStr, lenA+1, rebuiltStr, lenW);
2982 cur = rebuiltStr;
2983 /* this is fine because all of the chars that end tokens are ASCII*/
2984 LIST_FOR_EACH_ENTRY(pNsEntry, pNsList, select_ns_entry, entry)
2986 while (*cur != 0) ++cur;
2987 if (pNsEntry->prefix_end)
2989 *cur = pNsEntry->prefix_end;
2990 while (*cur != 0) ++cur;
2993 if (pNsEntry->href_end)
2995 *cur = pNsEntry->href_end;
2998 V_BSTR(var) = SysAllocString(rebuiltStr);
2999 heap_free(rebuiltStr);
3000 return S_OK;
3003 FIXME("Unknown property %s\n", debugstr_w(p));
3004 return E_FAIL;
3007 static HRESULT WINAPI domdoc_importNode(
3008 IXMLDOMDocument3* iface,
3009 IXMLDOMNode* node,
3010 VARIANT_BOOL deep,
3011 IXMLDOMNode** clone)
3013 domdoc *This = impl_from_IXMLDOMDocument3( iface );
3014 FIXME("(%p)->(%p %d %p): stub\n", This, node, deep, clone);
3015 return E_NOTIMPL;
3018 static const struct IXMLDOMDocument3Vtbl XMLDOMDocument3Vtbl =
3020 domdoc_QueryInterface,
3021 domdoc_AddRef,
3022 domdoc_Release,
3023 domdoc_GetTypeInfoCount,
3024 domdoc_GetTypeInfo,
3025 domdoc_GetIDsOfNames,
3026 domdoc_Invoke,
3027 domdoc_get_nodeName,
3028 domdoc_get_nodeValue,
3029 domdoc_put_nodeValue,
3030 domdoc_get_nodeType,
3031 domdoc_get_parentNode,
3032 domdoc_get_childNodes,
3033 domdoc_get_firstChild,
3034 domdoc_get_lastChild,
3035 domdoc_get_previousSibling,
3036 domdoc_get_nextSibling,
3037 domdoc_get_attributes,
3038 domdoc_insertBefore,
3039 domdoc_replaceChild,
3040 domdoc_removeChild,
3041 domdoc_appendChild,
3042 domdoc_hasChildNodes,
3043 domdoc_get_ownerDocument,
3044 domdoc_cloneNode,
3045 domdoc_get_nodeTypeString,
3046 domdoc_get_text,
3047 domdoc_put_text,
3048 domdoc_get_specified,
3049 domdoc_get_definition,
3050 domdoc_get_nodeTypedValue,
3051 domdoc_put_nodeTypedValue,
3052 domdoc_get_dataType,
3053 domdoc_put_dataType,
3054 domdoc_get_xml,
3055 domdoc_transformNode,
3056 domdoc_selectNodes,
3057 domdoc_selectSingleNode,
3058 domdoc_get_parsed,
3059 domdoc_get_namespaceURI,
3060 domdoc_get_prefix,
3061 domdoc_get_baseName,
3062 domdoc_transformNodeToObject,
3063 domdoc_get_doctype,
3064 domdoc_get_implementation,
3065 domdoc_get_documentElement,
3066 domdoc_put_documentElement,
3067 domdoc_createElement,
3068 domdoc_createDocumentFragment,
3069 domdoc_createTextNode,
3070 domdoc_createComment,
3071 domdoc_createCDATASection,
3072 domdoc_createProcessingInstruction,
3073 domdoc_createAttribute,
3074 domdoc_createEntityReference,
3075 domdoc_getElementsByTagName,
3076 domdoc_createNode,
3077 domdoc_nodeFromID,
3078 domdoc_load,
3079 domdoc_get_readyState,
3080 domdoc_get_parseError,
3081 domdoc_get_url,
3082 domdoc_get_async,
3083 domdoc_put_async,
3084 domdoc_abort,
3085 domdoc_loadXML,
3086 domdoc_save,
3087 domdoc_get_validateOnParse,
3088 domdoc_put_validateOnParse,
3089 domdoc_get_resolveExternals,
3090 domdoc_put_resolveExternals,
3091 domdoc_get_preserveWhiteSpace,
3092 domdoc_put_preserveWhiteSpace,
3093 domdoc_put_onreadystatechange,
3094 domdoc_put_onDataAvailable,
3095 domdoc_put_onTransformNode,
3096 domdoc_get_namespaces,
3097 domdoc_get_schemas,
3098 domdoc_putref_schemas,
3099 domdoc_validate,
3100 domdoc_setProperty,
3101 domdoc_getProperty,
3102 domdoc_validateNode,
3103 domdoc_importNode
3106 /* IConnectionPointContainer */
3107 static HRESULT WINAPI ConnectionPointContainer_QueryInterface(IConnectionPointContainer *iface,
3108 REFIID riid, void **ppv)
3110 domdoc *This = impl_from_IConnectionPointContainer(iface);
3111 return IXMLDOMDocument3_QueryInterface(&This->IXMLDOMDocument3_iface, riid, ppv);
3114 static ULONG WINAPI ConnectionPointContainer_AddRef(IConnectionPointContainer *iface)
3116 domdoc *This = impl_from_IConnectionPointContainer(iface);
3117 return IXMLDOMDocument3_AddRef(&This->IXMLDOMDocument3_iface);
3120 static ULONG WINAPI ConnectionPointContainer_Release(IConnectionPointContainer *iface)
3122 domdoc *This = impl_from_IConnectionPointContainer(iface);
3123 return IXMLDOMDocument3_Release(&This->IXMLDOMDocument3_iface);
3126 static HRESULT WINAPI ConnectionPointContainer_EnumConnectionPoints(IConnectionPointContainer *iface,
3127 IEnumConnectionPoints **ppEnum)
3129 domdoc *This = impl_from_IConnectionPointContainer(iface);
3130 FIXME("(%p)->(%p): stub\n", This, ppEnum);
3131 return E_NOTIMPL;
3134 static HRESULT WINAPI ConnectionPointContainer_FindConnectionPoint(IConnectionPointContainer *iface,
3135 REFIID riid, IConnectionPoint **cp)
3137 domdoc *This = impl_from_IConnectionPointContainer(iface);
3138 ConnectionPoint *iter;
3140 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), cp);
3142 *cp = NULL;
3144 for(iter = This->cp_list; iter; iter = iter->next)
3146 if (IsEqualGUID(iter->iid, riid))
3147 *cp = &iter->IConnectionPoint_iface;
3150 if (*cp)
3152 IConnectionPoint_AddRef(*cp);
3153 return S_OK;
3156 FIXME("unsupported riid %s\n", debugstr_guid(riid));
3157 return CONNECT_E_NOCONNECTION;
3161 static const struct IConnectionPointContainerVtbl ConnectionPointContainerVtbl =
3163 ConnectionPointContainer_QueryInterface,
3164 ConnectionPointContainer_AddRef,
3165 ConnectionPointContainer_Release,
3166 ConnectionPointContainer_EnumConnectionPoints,
3167 ConnectionPointContainer_FindConnectionPoint
3170 /* IConnectionPoint */
3171 static HRESULT WINAPI ConnectionPoint_QueryInterface(IConnectionPoint *iface,
3172 REFIID riid, void **ppv)
3174 ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3176 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv );
3178 *ppv = NULL;
3180 if (IsEqualGUID(&IID_IUnknown, riid) ||
3181 IsEqualGUID(&IID_IConnectionPoint, riid))
3183 *ppv = iface;
3186 if (*ppv)
3188 IConnectionPoint_AddRef(iface);
3189 return S_OK;
3192 WARN("Unsupported interface %s\n", debugstr_guid(riid));
3193 return E_NOINTERFACE;
3196 static ULONG WINAPI ConnectionPoint_AddRef(IConnectionPoint *iface)
3198 ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3199 return IConnectionPointContainer_AddRef(This->container);
3202 static ULONG WINAPI ConnectionPoint_Release(IConnectionPoint *iface)
3204 ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3205 return IConnectionPointContainer_Release(This->container);
3208 static HRESULT WINAPI ConnectionPoint_GetConnectionInterface(IConnectionPoint *iface, IID *iid)
3210 ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3212 TRACE("(%p)->(%p)\n", This, iid);
3214 if (!iid) return E_POINTER;
3216 *iid = *This->iid;
3217 return S_OK;
3220 static HRESULT WINAPI ConnectionPoint_GetConnectionPointContainer(IConnectionPoint *iface,
3221 IConnectionPointContainer **container)
3223 ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3225 TRACE("(%p)->(%p)\n", This, container);
3227 if (!container) return E_POINTER;
3229 *container = This->container;
3230 IConnectionPointContainer_AddRef(*container);
3231 return S_OK;
3234 static HRESULT WINAPI ConnectionPoint_Advise(IConnectionPoint *iface, IUnknown *pUnkSink,
3235 DWORD *pdwCookie)
3237 ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3238 FIXME("(%p)->(%p %p): stub\n", This, pUnkSink, pdwCookie);
3239 return E_NOTIMPL;
3242 static HRESULT WINAPI ConnectionPoint_Unadvise(IConnectionPoint *iface, DWORD cookie)
3244 ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3246 TRACE("(%p)->(%d)\n", This, cookie);
3248 if (cookie == 0 || cookie > This->sinks_size || !This->sinks[cookie-1].unk)
3249 return CONNECT_E_NOCONNECTION;
3251 IUnknown_Release(This->sinks[cookie-1].unk);
3252 This->sinks[cookie-1].unk = NULL;
3254 return S_OK;
3257 static HRESULT WINAPI ConnectionPoint_EnumConnections(IConnectionPoint *iface,
3258 IEnumConnections **ppEnum)
3260 ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3261 FIXME("(%p)->(%p): stub\n", This, ppEnum);
3262 return E_NOTIMPL;
3265 static const IConnectionPointVtbl ConnectionPointVtbl =
3267 ConnectionPoint_QueryInterface,
3268 ConnectionPoint_AddRef,
3269 ConnectionPoint_Release,
3270 ConnectionPoint_GetConnectionInterface,
3271 ConnectionPoint_GetConnectionPointContainer,
3272 ConnectionPoint_Advise,
3273 ConnectionPoint_Unadvise,
3274 ConnectionPoint_EnumConnections
3277 static void ConnectionPoint_Init(ConnectionPoint *cp, struct domdoc *doc, REFIID riid)
3279 cp->IConnectionPoint_iface.lpVtbl = &ConnectionPointVtbl;
3280 cp->doc = doc;
3281 cp->iid = riid;
3282 cp->sinks = NULL;
3283 cp->sinks_size = 0;
3285 cp->next = doc->cp_list;
3286 doc->cp_list = cp;
3288 cp->container = &doc->IConnectionPointContainer_iface;
3291 /* domdoc implementation of IObjectWithSite */
3292 static HRESULT WINAPI
3293 domdoc_ObjectWithSite_QueryInterface( IObjectWithSite* iface, REFIID riid, void** ppvObject )
3295 domdoc *This = impl_from_IObjectWithSite(iface);
3296 return IXMLDOMDocument3_QueryInterface(&This->IXMLDOMDocument3_iface, riid, ppvObject);
3299 static ULONG WINAPI domdoc_ObjectWithSite_AddRef( IObjectWithSite* iface )
3301 domdoc *This = impl_from_IObjectWithSite(iface);
3302 return IXMLDOMDocument3_AddRef(&This->IXMLDOMDocument3_iface);
3305 static ULONG WINAPI domdoc_ObjectWithSite_Release( IObjectWithSite* iface )
3307 domdoc *This = impl_from_IObjectWithSite(iface);
3308 return IXMLDOMDocument3_Release(&This->IXMLDOMDocument3_iface);
3311 static HRESULT WINAPI domdoc_ObjectWithSite_GetSite( IObjectWithSite *iface, REFIID iid, void **ppvSite )
3313 domdoc *This = impl_from_IObjectWithSite(iface);
3315 TRACE("(%p)->(%s %p)\n", This, debugstr_guid( iid ), ppvSite );
3317 if ( !This->site )
3318 return E_FAIL;
3320 return IUnknown_QueryInterface( This->site, iid, ppvSite );
3323 static HRESULT WINAPI domdoc_ObjectWithSite_SetSite( IObjectWithSite *iface, IUnknown *punk )
3325 domdoc *This = impl_from_IObjectWithSite(iface);
3327 TRACE("(%p)->(%p)\n", iface, punk);
3329 if(!punk)
3331 if(This->site)
3333 IUnknown_Release( This->site );
3334 This->site = NULL;
3337 return S_OK;
3340 IUnknown_AddRef( punk );
3342 if(This->site)
3343 IUnknown_Release( This->site );
3345 This->site = punk;
3347 return S_OK;
3350 static const IObjectWithSiteVtbl domdocObjectSite =
3352 domdoc_ObjectWithSite_QueryInterface,
3353 domdoc_ObjectWithSite_AddRef,
3354 domdoc_ObjectWithSite_Release,
3355 domdoc_ObjectWithSite_SetSite,
3356 domdoc_ObjectWithSite_GetSite
3359 static HRESULT WINAPI domdoc_Safety_QueryInterface(IObjectSafety *iface, REFIID riid, void **ppv)
3361 domdoc *This = impl_from_IObjectSafety(iface);
3362 return IXMLDOMDocument3_QueryInterface(&This->IXMLDOMDocument3_iface, riid, ppv);
3365 static ULONG WINAPI domdoc_Safety_AddRef(IObjectSafety *iface)
3367 domdoc *This = impl_from_IObjectSafety(iface);
3368 return IXMLDOMDocument3_AddRef(&This->IXMLDOMDocument3_iface);
3371 static ULONG WINAPI domdoc_Safety_Release(IObjectSafety *iface)
3373 domdoc *This = impl_from_IObjectSafety(iface);
3374 return IXMLDOMDocument3_Release(&This->IXMLDOMDocument3_iface);
3377 #define SAFETY_SUPPORTED_OPTIONS (INTERFACESAFE_FOR_UNTRUSTED_CALLER|INTERFACESAFE_FOR_UNTRUSTED_DATA|INTERFACE_USES_SECURITY_MANAGER)
3379 static HRESULT WINAPI domdoc_Safety_GetInterfaceSafetyOptions(IObjectSafety *iface, REFIID riid,
3380 DWORD *supported, DWORD *enabled)
3382 domdoc *This = impl_from_IObjectSafety(iface);
3384 TRACE("(%p)->(%s %p %p)\n", This, debugstr_guid(riid), supported, enabled);
3386 if(!supported || !enabled) return E_POINTER;
3388 *supported = SAFETY_SUPPORTED_OPTIONS;
3389 *enabled = This->safeopt;
3391 return S_OK;
3394 static HRESULT WINAPI domdoc_Safety_SetInterfaceSafetyOptions(IObjectSafety *iface, REFIID riid,
3395 DWORD mask, DWORD enabled)
3397 domdoc *This = impl_from_IObjectSafety(iface);
3398 TRACE("(%p)->(%s %x %x)\n", This, debugstr_guid(riid), mask, enabled);
3400 if ((mask & ~SAFETY_SUPPORTED_OPTIONS) != 0)
3401 return E_FAIL;
3403 This->safeopt = (This->safeopt & ~mask) | (mask & enabled);
3405 return S_OK;
3408 #undef SAFETY_SUPPORTED_OPTIONS
3410 static const IObjectSafetyVtbl domdocObjectSafetyVtbl = {
3411 domdoc_Safety_QueryInterface,
3412 domdoc_Safety_AddRef,
3413 domdoc_Safety_Release,
3414 domdoc_Safety_GetInterfaceSafetyOptions,
3415 domdoc_Safety_SetInterfaceSafetyOptions
3418 static const tid_t domdoc_iface_tids[] = {
3419 IXMLDOMDocument3_tid,
3423 static dispex_static_data_t domdoc_dispex = {
3424 NULL,
3425 IXMLDOMDocument3_tid,
3426 NULL,
3427 domdoc_iface_tids
3430 HRESULT get_domdoc_from_xmldoc(xmlDocPtr xmldoc, IXMLDOMDocument3 **document)
3432 domdoc *doc;
3434 doc = heap_alloc( sizeof (*doc) );
3435 if( !doc )
3436 return E_OUTOFMEMORY;
3438 doc->IXMLDOMDocument3_iface.lpVtbl = &XMLDOMDocument3Vtbl;
3439 doc->IPersistStreamInit_iface.lpVtbl = &xmldoc_IPersistStreamInit_VTable;
3440 doc->IObjectWithSite_iface.lpVtbl = &domdocObjectSite;
3441 doc->IObjectSafety_iface.lpVtbl = &domdocObjectSafetyVtbl;
3442 doc->IConnectionPointContainer_iface.lpVtbl = &ConnectionPointContainerVtbl;
3443 doc->ref = 1;
3444 doc->async = VARIANT_TRUE;
3445 doc->validating = 0;
3446 doc->resolving = 0;
3447 doc->properties = properties_from_xmlDocPtr(xmldoc);
3448 doc->error = S_OK;
3449 doc->stream = NULL;
3450 doc->site = NULL;
3451 doc->safeopt = 0;
3452 doc->bsc = NULL;
3453 doc->cp_list = NULL;
3454 doc->namespaces = NULL;
3455 memset(doc->events, 0, sizeof(doc->events));
3457 /* events connection points */
3458 ConnectionPoint_Init(&doc->cp_dispatch, doc, &IID_IDispatch);
3459 ConnectionPoint_Init(&doc->cp_propnotif, doc, &IID_IPropertyNotifySink);
3460 ConnectionPoint_Init(&doc->cp_domdocevents, doc, &DIID_XMLDOMDocumentEvents);
3462 init_xmlnode(&doc->node, (xmlNodePtr)xmldoc, (IXMLDOMNode*)&doc->IXMLDOMDocument3_iface,
3463 &domdoc_dispex);
3465 *document = &doc->IXMLDOMDocument3_iface;
3467 TRACE("returning iface %p\n", *document);
3468 return S_OK;
3471 HRESULT DOMDocument_create(MSXML_VERSION version, IUnknown *pUnkOuter, void **ppObj)
3473 xmlDocPtr xmldoc;
3474 HRESULT hr;
3476 TRACE("(%d, %p, %p)\n", version, pUnkOuter, ppObj);
3478 xmldoc = xmlNewDoc(NULL);
3479 if(!xmldoc)
3480 return E_OUTOFMEMORY;
3482 xmldoc_init(xmldoc, version);
3484 hr = get_domdoc_from_xmldoc(xmldoc, (IXMLDOMDocument3**)ppObj);
3485 if(FAILED(hr))
3487 free_properties(properties_from_xmlDocPtr(xmldoc));
3488 heap_free(xmldoc->_private);
3489 xmlFreeDoc(xmldoc);
3490 return hr;
3493 return hr;
3496 IUnknown* create_domdoc( xmlNodePtr document )
3498 void* pObj = NULL;
3499 HRESULT hr;
3501 TRACE("(%p)\n", document);
3503 hr = get_domdoc_from_xmldoc((xmlDocPtr)document, (IXMLDOMDocument3**)&pObj);
3504 if (FAILED(hr))
3505 return NULL;
3507 return pObj;
3510 #else
3512 HRESULT DOMDocument_create(MSXML_VERSION version, IUnknown *pUnkOuter, void **ppObj)
3514 MESSAGE("This program tried to use a DOMDocument object, but\n"
3515 "libxml2 support was not present at compile time.\n");
3516 return E_NOTIMPL;
3519 #endif