po: Remove English strings from the Finnish translation.
[wine.git] / dlls / msxml3 / domdoc.c
blob47ce60d4a557d08fb4251abb3594110a45d234de
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];
154 static HRESULT set_doc_event(domdoc *doc, eventid_t eid, const VARIANT *v)
156 IDispatch *disp;
158 switch (V_VT(v))
160 case VT_UNKNOWN:
161 if (V_UNKNOWN(v))
162 IUnknown_QueryInterface(V_UNKNOWN(v), &IID_IDispatch, (void**)&disp);
163 else
164 disp = NULL;
165 break;
166 case VT_DISPATCH:
167 disp = V_DISPATCH(v);
168 if (disp) IDispatch_AddRef(disp);
169 break;
170 default:
171 return DISP_E_TYPEMISMATCH;
174 if (doc->events[eid]) IDispatch_Release(doc->events[eid]);
175 doc->events[eid] = disp;
177 return S_OK;
180 static inline ConnectionPoint *impl_from_IConnectionPoint(IConnectionPoint *iface)
182 return CONTAINING_RECORD(iface, ConnectionPoint, IConnectionPoint_iface);
186 In native windows, the whole lifetime management of XMLDOMNodes is
187 managed automatically using reference counts. Wine emulates that by
188 maintaining a reference count to the document that is increased for
189 each IXMLDOMNode pointer passed out for this document. If all these
190 pointers are gone, the document is unreachable and gets freed, that
191 is, all nodes in the tree of the document get freed.
193 You are able to create nodes that are associated to a document (in
194 fact, in msxml's XMLDOM model, all nodes are associated to a document),
195 but not in the tree of that document, for example using the createFoo
196 functions from IXMLDOMDocument. These nodes do not get cleaned up
197 by libxml, so we have to do it ourselves.
199 To catch these nodes, a list of "orphan nodes" is introduced.
200 It contains pointers to all roots of node trees that are
201 associated with the document without being part of the document
202 tree. All nodes with parent==NULL (except for the document root nodes)
203 should be in the orphan node list of their document. All orphan nodes
204 get freed together with the document itself.
207 typedef struct _xmldoc_priv {
208 LONG refs;
209 struct list orphans;
210 domdoc_properties* properties;
211 } xmldoc_priv;
213 typedef struct _orphan_entry {
214 struct list entry;
215 xmlNode * node;
216 } orphan_entry;
218 typedef struct _select_ns_entry {
219 struct list entry;
220 xmlChar const* prefix;
221 xmlChar prefix_end;
222 xmlChar const* href;
223 xmlChar href_end;
224 } select_ns_entry;
226 static inline xmldoc_priv * priv_from_xmlDocPtr(const xmlDocPtr doc)
228 return doc->_private;
231 static inline domdoc_properties * properties_from_xmlDocPtr(xmlDocPtr doc)
233 return priv_from_xmlDocPtr(doc)->properties;
236 BOOL is_xpathmode(const xmlDocPtr doc)
238 return properties_from_xmlDocPtr(doc)->XPath;
241 void set_xpathmode(xmlDocPtr doc, BOOL xpath)
243 properties_from_xmlDocPtr(doc)->XPath = xpath;
246 int registerNamespaces(xmlXPathContextPtr ctxt)
248 int n = 0;
249 const select_ns_entry* ns = NULL;
250 const struct list* pNsList = &properties_from_xmlDocPtr(ctxt->doc)->selectNsList;
252 TRACE("(%p)\n", ctxt);
254 LIST_FOR_EACH_ENTRY( ns, pNsList, select_ns_entry, entry )
256 xmlXPathRegisterNs(ctxt, ns->prefix, ns->href);
257 ++n;
260 return n;
263 static inline void clear_selectNsList(struct list* pNsList)
265 select_ns_entry *ns, *ns2;
266 LIST_FOR_EACH_ENTRY_SAFE( ns, ns2, pNsList, select_ns_entry, entry )
268 heap_free( ns );
270 list_init(pNsList);
273 static xmldoc_priv * create_priv(void)
275 xmldoc_priv *priv;
276 priv = heap_alloc( sizeof (*priv) );
278 if (priv)
280 priv->refs = 0;
281 list_init( &priv->orphans );
282 priv->properties = NULL;
285 return priv;
288 static domdoc_properties *create_properties(MSXML_VERSION version)
290 domdoc_properties *properties = heap_alloc(sizeof(domdoc_properties));
292 list_init(&properties->selectNsList);
293 properties->preserving = VARIANT_FALSE;
294 properties->schemaCache = NULL;
295 properties->selectNsStr = heap_alloc_zero(sizeof(xmlChar));
296 properties->selectNsStr_len = 0;
298 /* properties that are dependent on object versions */
299 properties->version = version;
300 properties->XPath = (version == MSXML4 || version == MSXML6);
302 return properties;
305 static domdoc_properties* copy_properties(domdoc_properties const* properties)
307 domdoc_properties* pcopy = heap_alloc(sizeof(domdoc_properties));
308 select_ns_entry const* ns = NULL;
309 select_ns_entry* new_ns = NULL;
310 int len = (properties->selectNsStr_len+1)*sizeof(xmlChar);
311 ptrdiff_t offset;
313 if (pcopy)
315 pcopy->version = properties->version;
316 pcopy->preserving = properties->preserving;
317 pcopy->schemaCache = properties->schemaCache;
318 if (pcopy->schemaCache)
319 IXMLDOMSchemaCollection2_AddRef(pcopy->schemaCache);
320 pcopy->XPath = properties->XPath;
321 pcopy->selectNsStr_len = properties->selectNsStr_len;
322 list_init( &pcopy->selectNsList );
323 pcopy->selectNsStr = heap_alloc(len);
324 memcpy((xmlChar*)pcopy->selectNsStr, properties->selectNsStr, len);
325 offset = pcopy->selectNsStr - properties->selectNsStr;
327 LIST_FOR_EACH_ENTRY( ns, (&properties->selectNsList), select_ns_entry, entry )
329 new_ns = heap_alloc(sizeof(select_ns_entry));
330 memcpy(new_ns, ns, sizeof(select_ns_entry));
331 new_ns->href += offset;
332 new_ns->prefix += offset;
333 list_add_tail(&pcopy->selectNsList, &new_ns->entry);
338 return pcopy;
341 static void free_properties(domdoc_properties* properties)
343 if (properties)
345 if (properties->schemaCache)
346 IXMLDOMSchemaCollection2_Release(properties->schemaCache);
347 clear_selectNsList(&properties->selectNsList);
348 heap_free((xmlChar*)properties->selectNsStr);
349 heap_free(properties);
353 /* links a "<?xml" node as a first child */
354 void xmldoc_link_xmldecl(xmlDocPtr doc, xmlNodePtr node)
356 assert(doc != NULL);
357 if (doc->standalone != -1) xmlAddPrevSibling( doc->children, node );
360 /* unlinks a first "<?xml" child if it was created */
361 xmlNodePtr xmldoc_unlink_xmldecl(xmlDocPtr doc)
363 xmlNodePtr node;
365 assert(doc != NULL);
367 if (doc->standalone != -1)
369 node = doc->children;
370 xmlUnlinkNode( node );
372 else
373 node = NULL;
375 return node;
378 BOOL is_preserving_whitespace(xmlNodePtr node)
380 domdoc_properties* properties = NULL;
381 /* during parsing the xmlDoc._private stuff is not there */
382 if (priv_from_xmlDocPtr(node->doc))
383 properties = properties_from_xmlDocPtr(node->doc);
384 return ((properties && properties->preserving == VARIANT_TRUE) ||
385 xmlNodeGetSpacePreserve(node) == 1);
388 static inline BOOL strn_isspace(xmlChar const* str, int len)
390 for (; str && len > 0 && *str; ++str, --len)
391 if (!isspace(*str))
392 break;
394 return len == 0;
397 static void sax_characters(void *ctx, const xmlChar *ch, int len)
399 xmlParserCtxtPtr ctxt;
400 const domdoc *This;
402 ctxt = (xmlParserCtxtPtr) ctx;
403 This = (const domdoc*) ctxt->_private;
405 if (ctxt->node)
407 /* during domdoc_loadXML() the xmlDocPtr->_private data is not available */
408 if (!This->properties->preserving &&
409 !is_preserving_whitespace(ctxt->node) &&
410 strn_isspace(ch, len))
411 return;
414 xmlSAX2Characters(ctxt, ch, len);
417 static void LIBXML2_LOG_CALLBACK sax_error(void* ctx, char const* msg, ...)
419 va_list ap;
420 va_start(ap, msg);
421 LIBXML2_CALLBACK_ERR(doparse, msg, ap);
422 va_end(ap);
425 static void LIBXML2_LOG_CALLBACK sax_warning(void* ctx, char const* msg, ...)
427 va_list ap;
428 va_start(ap, msg);
429 LIBXML2_CALLBACK_WARN(doparse, msg, ap);
430 va_end(ap);
433 static void sax_serror(void* ctx, xmlErrorPtr err)
435 LIBXML2_CALLBACK_SERROR(doparse, err);
438 static xmlDocPtr doparse(domdoc* This, char const* ptr, int len, xmlCharEncoding encoding)
440 xmlDocPtr doc = NULL;
441 xmlParserCtxtPtr pctx;
442 static xmlSAXHandler sax_handler = {
443 xmlSAX2InternalSubset, /* internalSubset */
444 xmlSAX2IsStandalone, /* isStandalone */
445 xmlSAX2HasInternalSubset, /* hasInternalSubset */
446 xmlSAX2HasExternalSubset, /* hasExternalSubset */
447 xmlSAX2ResolveEntity, /* resolveEntity */
448 xmlSAX2GetEntity, /* getEntity */
449 xmlSAX2EntityDecl, /* entityDecl */
450 xmlSAX2NotationDecl, /* notationDecl */
451 xmlSAX2AttributeDecl, /* attributeDecl */
452 xmlSAX2ElementDecl, /* elementDecl */
453 xmlSAX2UnparsedEntityDecl, /* unparsedEntityDecl */
454 xmlSAX2SetDocumentLocator, /* setDocumentLocator */
455 xmlSAX2StartDocument, /* startDocument */
456 xmlSAX2EndDocument, /* endDocument */
457 xmlSAX2StartElement, /* startElement */
458 xmlSAX2EndElement, /* endElement */
459 xmlSAX2Reference, /* reference */
460 sax_characters, /* characters */
461 sax_characters, /* ignorableWhitespace */
462 xmlSAX2ProcessingInstruction, /* processingInstruction */
463 xmlSAX2Comment, /* comment */
464 sax_warning, /* warning */
465 sax_error, /* error */
466 sax_error, /* fatalError */
467 xmlSAX2GetParameterEntity, /* getParameterEntity */
468 xmlSAX2CDataBlock, /* cdataBlock */
469 xmlSAX2ExternalSubset, /* externalSubset */
470 0, /* initialized */
471 NULL, /* _private */
472 xmlSAX2StartElementNs, /* startElementNs */
473 xmlSAX2EndElementNs, /* endElementNs */
474 sax_serror /* serror */
476 xmlInitParser();
478 pctx = xmlCreateMemoryParserCtxt(ptr, len);
479 if (!pctx)
481 ERR("Failed to create parser context\n");
482 return NULL;
485 if (pctx->sax) xmlFree(pctx->sax);
486 pctx->sax = &sax_handler;
487 pctx->_private = This;
488 pctx->recovery = 0;
490 if (encoding != XML_CHAR_ENCODING_NONE)
491 xmlSwitchEncoding(pctx, encoding);
493 xmlParseDocument(pctx);
495 if (pctx->wellFormed)
497 doc = pctx->myDoc;
499 else
501 xmlFreeDoc(pctx->myDoc);
502 pctx->myDoc = NULL;
504 pctx->sax = NULL;
505 xmlFreeParserCtxt(pctx);
507 /* TODO: put this in one of the SAX callbacks */
508 /* create first child as a <?xml...?> */
509 if (doc && doc->standalone != -1)
511 xmlNodePtr node;
512 char buff[30];
513 xmlChar *xmlbuff = (xmlChar*)buff;
515 node = xmlNewDocPI( doc, (xmlChar*)"xml", NULL );
517 /* version attribute can't be omitted */
518 sprintf(buff, "version=\"%s\"", doc->version ? (char*)doc->version : "1.0");
519 xmlNodeAddContent( node, xmlbuff );
521 if (doc->encoding)
523 sprintf(buff, " encoding=\"%s\"", doc->encoding);
524 xmlNodeAddContent( node, xmlbuff );
527 if (doc->standalone != -2)
529 sprintf(buff, " standalone=\"%s\"", doc->standalone == 0 ? "no" : "yes");
530 xmlNodeAddContent( node, xmlbuff );
533 xmldoc_link_xmldecl( doc, node );
536 return doc;
539 void xmldoc_init(xmlDocPtr doc, MSXML_VERSION version)
541 doc->_private = create_priv();
542 priv_from_xmlDocPtr(doc)->properties = create_properties(version);
545 LONG xmldoc_add_ref(xmlDocPtr doc)
547 LONG ref = InterlockedIncrement(&priv_from_xmlDocPtr(doc)->refs);
548 TRACE("(%p)->(%d)\n", doc, ref);
549 return ref;
552 LONG xmldoc_release(xmlDocPtr doc)
554 xmldoc_priv *priv = priv_from_xmlDocPtr(doc);
555 LONG ref = InterlockedDecrement(&priv->refs);
556 TRACE("(%p)->(%d)\n", doc, ref);
557 if(ref == 0)
559 orphan_entry *orphan, *orphan2;
560 TRACE("freeing docptr %p\n", doc);
562 LIST_FOR_EACH_ENTRY_SAFE( orphan, orphan2, &priv->orphans, orphan_entry, entry )
564 xmlFreeNode( orphan->node );
565 heap_free( orphan );
567 free_properties(priv->properties);
568 heap_free(doc->_private);
570 xmlFreeDoc(doc);
573 return ref;
576 HRESULT xmldoc_add_orphan(xmlDocPtr doc, xmlNodePtr node)
578 xmldoc_priv *priv = priv_from_xmlDocPtr(doc);
579 orphan_entry *entry;
581 entry = heap_alloc( sizeof (*entry) );
582 if(!entry)
583 return E_OUTOFMEMORY;
585 entry->node = node;
586 list_add_head( &priv->orphans, &entry->entry );
587 return S_OK;
590 HRESULT xmldoc_remove_orphan(xmlDocPtr doc, xmlNodePtr node)
592 xmldoc_priv *priv = priv_from_xmlDocPtr(doc);
593 orphan_entry *entry, *entry2;
595 LIST_FOR_EACH_ENTRY_SAFE( entry, entry2, &priv->orphans, orphan_entry, entry )
597 if( entry->node == node )
599 list_remove( &entry->entry );
600 heap_free( entry );
601 return S_OK;
605 return S_FALSE;
608 static inline xmlDocPtr get_doc( domdoc *This )
610 return (xmlDocPtr)This->node.node;
613 static HRESULT attach_xmldoc(domdoc *This, xmlDocPtr xml )
615 if(This->node.node)
617 priv_from_xmlDocPtr(get_doc(This))->properties = NULL;
618 if (xmldoc_release(get_doc(This)) != 0)
619 priv_from_xmlDocPtr(get_doc(This))->properties =
620 copy_properties(This->properties);
623 This->node.node = (xmlNodePtr) xml;
625 if(This->node.node)
627 xmldoc_add_ref(get_doc(This));
628 priv_from_xmlDocPtr(get_doc(This))->properties = This->properties;
631 return S_OK;
634 static inline domdoc *impl_from_IXMLDOMDocument3( IXMLDOMDocument3 *iface )
636 return CONTAINING_RECORD(iface, domdoc, IXMLDOMDocument3_iface);
639 static inline domdoc *impl_from_IPersistStreamInit(IPersistStreamInit *iface)
641 return CONTAINING_RECORD(iface, domdoc, IPersistStreamInit_iface);
644 static inline domdoc *impl_from_IObjectWithSite(IObjectWithSite *iface)
646 return CONTAINING_RECORD(iface, domdoc, IObjectWithSite_iface);
649 static inline domdoc *impl_from_IObjectSafety(IObjectSafety *iface)
651 return CONTAINING_RECORD(iface, domdoc, IObjectSafety_iface);
654 static inline domdoc *impl_from_IConnectionPointContainer(IConnectionPointContainer *iface)
656 return CONTAINING_RECORD(iface, domdoc, IConnectionPointContainer_iface);
659 /************************************************************************
660 * domdoc implementation of IPersistStream.
662 static HRESULT WINAPI domdoc_IPersistStreamInit_QueryInterface(
663 IPersistStreamInit *iface, REFIID riid, void **ppvObj)
665 domdoc* This = impl_from_IPersistStreamInit(iface);
666 return IXMLDOMDocument3_QueryInterface(&This->IXMLDOMDocument3_iface, riid, ppvObj);
669 static ULONG WINAPI domdoc_IPersistStreamInit_AddRef(
670 IPersistStreamInit *iface)
672 domdoc* This = impl_from_IPersistStreamInit(iface);
673 return IXMLDOMDocument3_AddRef(&This->IXMLDOMDocument3_iface);
676 static ULONG WINAPI domdoc_IPersistStreamInit_Release(
677 IPersistStreamInit *iface)
679 domdoc* This = impl_from_IPersistStreamInit(iface);
680 return IXMLDOMDocument3_Release(&This->IXMLDOMDocument3_iface);
683 static HRESULT WINAPI domdoc_IPersistStreamInit_GetClassID(
684 IPersistStreamInit *iface, CLSID *classid)
686 domdoc* This = impl_from_IPersistStreamInit(iface);
687 TRACE("(%p)->(%p)\n", This, classid);
689 if(!classid)
690 return E_POINTER;
692 *classid = *DOMDocument_version(This->properties->version);
694 return S_OK;
697 static HRESULT WINAPI domdoc_IPersistStreamInit_IsDirty(
698 IPersistStreamInit *iface)
700 domdoc *This = impl_from_IPersistStreamInit(iface);
701 FIXME("(%p): stub!\n", This);
702 return S_FALSE;
705 static HRESULT WINAPI domdoc_IPersistStreamInit_Load(
706 IPersistStreamInit *iface, LPSTREAM pStm)
708 domdoc *This = impl_from_IPersistStreamInit(iface);
709 HRESULT hr;
710 HGLOBAL hglobal;
711 DWORD read, written, len;
712 BYTE buf[4096];
713 char *ptr;
714 xmlDocPtr xmldoc = NULL;
716 TRACE("(%p)->(%p)\n", This, pStm);
718 if (!pStm)
719 return E_INVALIDARG;
721 hr = CreateStreamOnHGlobal(NULL, TRUE, &This->stream);
722 if (FAILED(hr))
723 return hr;
727 IStream_Read(pStm, buf, sizeof(buf), &read);
728 hr = IStream_Write(This->stream, buf, read, &written);
729 } while(SUCCEEDED(hr) && written != 0 && read != 0);
731 if (FAILED(hr))
733 ERR("Failed to copy stream\n");
734 return hr;
737 hr = GetHGlobalFromStream(This->stream, &hglobal);
738 if (FAILED(hr))
739 return hr;
741 len = GlobalSize(hglobal);
742 ptr = GlobalLock(hglobal);
743 if (len != 0)
744 xmldoc = doparse(This, ptr, len, XML_CHAR_ENCODING_NONE);
745 GlobalUnlock(hglobal);
747 if (!xmldoc)
749 ERR("Failed to parse xml\n");
750 return E_FAIL;
753 xmldoc->_private = create_priv();
755 return attach_xmldoc(This, xmldoc);
758 static HRESULT WINAPI domdoc_IPersistStreamInit_Save(
759 IPersistStreamInit *iface, IStream *stream, BOOL clr_dirty)
761 domdoc *This = impl_from_IPersistStreamInit(iface);
762 BSTR xmlString;
763 HRESULT hr;
765 TRACE("(%p)->(%p %d)\n", This, stream, clr_dirty);
767 hr = IXMLDOMDocument3_get_xml(&This->IXMLDOMDocument3_iface, &xmlString);
768 if(hr == S_OK)
770 DWORD len = SysStringLen(xmlString) * sizeof(WCHAR);
772 hr = IStream_Write( stream, xmlString, len, NULL );
773 SysFreeString(xmlString);
776 TRACE("ret 0x%08x\n", hr);
778 return hr;
781 static HRESULT WINAPI domdoc_IPersistStreamInit_GetSizeMax(
782 IPersistStreamInit *iface, ULARGE_INTEGER *pcbSize)
784 domdoc *This = impl_from_IPersistStreamInit(iface);
785 TRACE("(%p)->(%p): stub!\n", This, pcbSize);
786 return E_NOTIMPL;
789 static HRESULT WINAPI domdoc_IPersistStreamInit_InitNew(
790 IPersistStreamInit *iface)
792 domdoc *This = impl_from_IPersistStreamInit(iface);
793 TRACE("(%p)\n", This);
794 return S_OK;
797 static const IPersistStreamInitVtbl xmldoc_IPersistStreamInit_VTable =
799 domdoc_IPersistStreamInit_QueryInterface,
800 domdoc_IPersistStreamInit_AddRef,
801 domdoc_IPersistStreamInit_Release,
802 domdoc_IPersistStreamInit_GetClassID,
803 domdoc_IPersistStreamInit_IsDirty,
804 domdoc_IPersistStreamInit_Load,
805 domdoc_IPersistStreamInit_Save,
806 domdoc_IPersistStreamInit_GetSizeMax,
807 domdoc_IPersistStreamInit_InitNew
810 /* IXMLDOMDocument3 interface */
812 static const tid_t domdoc_se_tids[] = {
813 IXMLDOMNode_tid,
814 IXMLDOMDocument_tid,
815 IXMLDOMDocument2_tid,
816 IXMLDOMDocument3_tid,
820 static HRESULT WINAPI domdoc_QueryInterface( IXMLDOMDocument3 *iface, REFIID riid, void** ppvObject )
822 domdoc *This = impl_from_IXMLDOMDocument3( iface );
824 TRACE("(%p)->(%s %p)\n", This, debugstr_guid( riid ), ppvObject );
826 *ppvObject = NULL;
828 if ( IsEqualGUID( riid, &IID_IUnknown ) ||
829 IsEqualGUID( riid, &IID_IDispatch ) ||
830 IsEqualGUID( riid, &IID_IXMLDOMNode ) ||
831 IsEqualGUID( riid, &IID_IXMLDOMDocument ) ||
832 IsEqualGUID( riid, &IID_IXMLDOMDocument2 )||
833 IsEqualGUID( riid, &IID_IXMLDOMDocument3 ))
835 *ppvObject = iface;
837 else if (IsEqualGUID(&IID_IPersistStream, riid) ||
838 IsEqualGUID(&IID_IPersistStreamInit, riid))
840 *ppvObject = &This->IPersistStreamInit_iface;
842 else if (IsEqualGUID(&IID_IObjectWithSite, riid))
844 *ppvObject = &This->IObjectWithSite_iface;
846 else if (IsEqualGUID(&IID_IObjectSafety, riid))
848 *ppvObject = &This->IObjectSafety_iface;
850 else if( IsEqualGUID( riid, &IID_ISupportErrorInfo ))
852 return node_create_supporterrorinfo(domdoc_se_tids, ppvObject);
854 else if(node_query_interface(&This->node, riid, ppvObject))
856 return *ppvObject ? S_OK : E_NOINTERFACE;
858 else if (IsEqualGUID( riid, &IID_IConnectionPointContainer ))
860 *ppvObject = &This->IConnectionPointContainer_iface;
862 else
864 TRACE("interface %s not implemented\n", debugstr_guid(riid));
865 return E_NOINTERFACE;
868 IUnknown_AddRef((IUnknown*)*ppvObject);
870 return S_OK;
873 static ULONG WINAPI domdoc_AddRef( IXMLDOMDocument3 *iface )
875 domdoc *This = impl_from_IXMLDOMDocument3( iface );
876 ULONG ref = InterlockedIncrement( &This->ref );
877 TRACE("(%p)->(%d)\n", This, ref );
878 return ref;
881 static ULONG WINAPI domdoc_Release( IXMLDOMDocument3 *iface )
883 domdoc *This = impl_from_IXMLDOMDocument3( iface );
884 LONG ref = InterlockedDecrement( &This->ref );
886 TRACE("(%p)->(%d)\n", This, ref );
888 if ( ref == 0 )
890 int eid;
892 if(This->bsc)
893 detach_bsc(This->bsc);
895 if (This->site)
896 IUnknown_Release( This->site );
897 destroy_xmlnode(&This->node);
898 if (This->stream)
899 IStream_Release(This->stream);
901 for (eid = 0; eid < EVENTID_LAST; eid++)
902 if (This->events[eid]) IDispatch_Release(This->events[eid]);
904 heap_free(This);
907 return ref;
910 static HRESULT WINAPI domdoc_GetTypeInfoCount( IXMLDOMDocument3 *iface, UINT* pctinfo )
912 domdoc *This = impl_from_IXMLDOMDocument3( iface );
913 return IDispatchEx_GetTypeInfoCount(&This->node.dispex.IDispatchEx_iface, pctinfo);
916 static HRESULT WINAPI domdoc_GetTypeInfo(
917 IXMLDOMDocument3 *iface,
918 UINT iTInfo, LCID lcid, ITypeInfo** ppTInfo )
920 domdoc *This = impl_from_IXMLDOMDocument3( iface );
921 return IDispatchEx_GetTypeInfo(&This->node.dispex.IDispatchEx_iface, iTInfo, lcid, ppTInfo);
924 static HRESULT WINAPI domdoc_GetIDsOfNames(
925 IXMLDOMDocument3 *iface,
926 REFIID riid,
927 LPOLESTR* rgszNames,
928 UINT cNames,
929 LCID lcid,
930 DISPID* rgDispId)
932 domdoc *This = impl_from_IXMLDOMDocument3( iface );
933 return IDispatchEx_GetIDsOfNames(&This->node.dispex.IDispatchEx_iface,
934 riid, rgszNames, cNames, lcid, rgDispId);
937 static HRESULT WINAPI domdoc_Invoke(
938 IXMLDOMDocument3 *iface,
939 DISPID dispIdMember,
940 REFIID riid,
941 LCID lcid,
942 WORD wFlags,
943 DISPPARAMS* pDispParams,
944 VARIANT* pVarResult,
945 EXCEPINFO* pExcepInfo,
946 UINT* puArgErr)
948 domdoc *This = impl_from_IXMLDOMDocument3( iface );
949 return IDispatchEx_Invoke(&This->node.dispex.IDispatchEx_iface,
950 dispIdMember, riid, lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
953 static HRESULT WINAPI domdoc_get_nodeName(
954 IXMLDOMDocument3 *iface,
955 BSTR* name )
957 domdoc *This = impl_from_IXMLDOMDocument3( iface );
959 static const WCHAR documentW[] = {'#','d','o','c','u','m','e','n','t',0};
961 TRACE("(%p)->(%p)\n", This, name);
963 return return_bstr(documentW, name);
967 static HRESULT WINAPI domdoc_get_nodeValue(
968 IXMLDOMDocument3 *iface,
969 VARIANT* value )
971 domdoc *This = impl_from_IXMLDOMDocument3( iface );
973 TRACE("(%p)->(%p)\n", This, value);
975 if(!value)
976 return E_INVALIDARG;
978 V_VT(value) = VT_NULL;
979 V_BSTR(value) = NULL; /* tests show that we should do this */
980 return S_FALSE;
984 static HRESULT WINAPI domdoc_put_nodeValue(
985 IXMLDOMDocument3 *iface,
986 VARIANT value)
988 domdoc *This = impl_from_IXMLDOMDocument3( iface );
989 TRACE("(%p)->(v%d)\n", This, V_VT(&value));
990 return E_FAIL;
994 static HRESULT WINAPI domdoc_get_nodeType(
995 IXMLDOMDocument3 *iface,
996 DOMNodeType* type )
998 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1000 TRACE("(%p)->(%p)\n", This, type);
1002 *type = NODE_DOCUMENT;
1003 return S_OK;
1007 static HRESULT WINAPI domdoc_get_parentNode(
1008 IXMLDOMDocument3 *iface,
1009 IXMLDOMNode** parent )
1011 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1013 TRACE("(%p)->(%p)\n", This, parent);
1015 return node_get_parent(&This->node, parent);
1019 static HRESULT WINAPI domdoc_get_childNodes(
1020 IXMLDOMDocument3 *iface,
1021 IXMLDOMNodeList** childList )
1023 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1025 TRACE("(%p)->(%p)\n", This, childList);
1027 return node_get_child_nodes(&This->node, childList);
1031 static HRESULT WINAPI domdoc_get_firstChild(
1032 IXMLDOMDocument3 *iface,
1033 IXMLDOMNode** firstChild )
1035 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1037 TRACE("(%p)->(%p)\n", This, firstChild);
1039 return node_get_first_child(&This->node, firstChild);
1043 static HRESULT WINAPI domdoc_get_lastChild(
1044 IXMLDOMDocument3 *iface,
1045 IXMLDOMNode** lastChild )
1047 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1049 TRACE("(%p)->(%p)\n", This, lastChild);
1051 return node_get_last_child(&This->node, lastChild);
1055 static HRESULT WINAPI domdoc_get_previousSibling(
1056 IXMLDOMDocument3 *iface,
1057 IXMLDOMNode** previousSibling )
1059 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1061 TRACE("(%p)->(%p)\n", This, previousSibling);
1063 return return_null_node(previousSibling);
1067 static HRESULT WINAPI domdoc_get_nextSibling(
1068 IXMLDOMDocument3 *iface,
1069 IXMLDOMNode** nextSibling )
1071 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1073 TRACE("(%p)->(%p)\n", This, nextSibling);
1075 return return_null_node(nextSibling);
1079 static HRESULT WINAPI domdoc_get_attributes(
1080 IXMLDOMDocument3 *iface,
1081 IXMLDOMNamedNodeMap** attributeMap )
1083 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1085 TRACE("(%p)->(%p)\n", This, attributeMap);
1087 return return_null_ptr((void**)attributeMap);
1091 static HRESULT WINAPI domdoc_insertBefore(
1092 IXMLDOMDocument3 *iface,
1093 IXMLDOMNode* newChild,
1094 VARIANT refChild,
1095 IXMLDOMNode** outNewChild )
1097 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1099 TRACE("(%p)->(%p x%d %p)\n", This, newChild, V_VT(&refChild), outNewChild);
1101 return node_insert_before(&This->node, newChild, &refChild, outNewChild);
1105 static HRESULT WINAPI domdoc_replaceChild(
1106 IXMLDOMDocument3 *iface,
1107 IXMLDOMNode* newChild,
1108 IXMLDOMNode* oldChild,
1109 IXMLDOMNode** outOldChild)
1111 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1113 TRACE("(%p)->(%p %p %p)\n", This, newChild, oldChild, outOldChild);
1115 return node_replace_child(&This->node, newChild, oldChild, outOldChild);
1119 static HRESULT WINAPI domdoc_removeChild(
1120 IXMLDOMDocument3 *iface,
1121 IXMLDOMNode *child,
1122 IXMLDOMNode **oldChild)
1124 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1125 TRACE("(%p)->(%p %p)\n", This, child, oldChild);
1126 return node_remove_child(&This->node, child, oldChild);
1130 static HRESULT WINAPI domdoc_appendChild(
1131 IXMLDOMDocument3 *iface,
1132 IXMLDOMNode *child,
1133 IXMLDOMNode **outChild)
1135 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1136 TRACE("(%p)->(%p %p)\n", This, child, outChild);
1137 return node_append_child(&This->node, child, outChild);
1141 static HRESULT WINAPI domdoc_hasChildNodes(
1142 IXMLDOMDocument3 *iface,
1143 VARIANT_BOOL *ret)
1145 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1146 TRACE("(%p)->(%p)\n", This, ret);
1147 return node_has_childnodes(&This->node, ret);
1151 static HRESULT WINAPI domdoc_get_ownerDocument(
1152 IXMLDOMDocument3 *iface,
1153 IXMLDOMDocument **doc)
1155 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1156 TRACE("(%p)->(%p)\n", This, doc);
1157 return node_get_owner_doc(&This->node, doc);
1161 static HRESULT WINAPI domdoc_cloneNode(
1162 IXMLDOMDocument3 *iface,
1163 VARIANT_BOOL deep,
1164 IXMLDOMNode** outNode)
1166 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1167 TRACE("(%p)->(%d %p)\n", This, deep, outNode);
1168 return node_clone( &This->node, deep, outNode );
1172 static HRESULT WINAPI domdoc_get_nodeTypeString(
1173 IXMLDOMDocument3 *iface,
1174 BSTR *p)
1176 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1177 static const WCHAR documentW[] = {'d','o','c','u','m','e','n','t',0};
1179 TRACE("(%p)->(%p)\n", This, p);
1181 return return_bstr(documentW, p);
1185 static HRESULT WINAPI domdoc_get_text(
1186 IXMLDOMDocument3 *iface,
1187 BSTR *p)
1189 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1190 TRACE("(%p)->(%p)\n", This, p);
1191 return node_get_text(&This->node, p);
1195 static HRESULT WINAPI domdoc_put_text(
1196 IXMLDOMDocument3 *iface,
1197 BSTR text )
1199 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1200 TRACE("(%p)->(%s)\n", This, debugstr_w(text));
1201 return E_FAIL;
1205 static HRESULT WINAPI domdoc_get_specified(
1206 IXMLDOMDocument3 *iface,
1207 VARIANT_BOOL* isSpecified )
1209 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1210 FIXME("(%p)->(%p) stub!\n", This, isSpecified);
1211 *isSpecified = VARIANT_TRUE;
1212 return S_OK;
1216 static HRESULT WINAPI domdoc_get_definition(
1217 IXMLDOMDocument3 *iface,
1218 IXMLDOMNode** definitionNode )
1220 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1221 FIXME("(%p)->(%p)\n", This, definitionNode);
1222 return E_NOTIMPL;
1226 static HRESULT WINAPI domdoc_get_nodeTypedValue(
1227 IXMLDOMDocument3 *iface,
1228 VARIANT* v )
1230 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1231 TRACE("(%p)->(%p)\n", This, v);
1232 return return_null_var(v);
1235 static HRESULT WINAPI domdoc_put_nodeTypedValue(
1236 IXMLDOMDocument3 *iface,
1237 VARIANT typedValue )
1239 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1240 FIXME("(%p)->(%s)\n", This, debugstr_variant(&typedValue));
1241 return E_NOTIMPL;
1245 static HRESULT WINAPI domdoc_get_dataType(
1246 IXMLDOMDocument3 *iface,
1247 VARIANT* typename )
1249 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1250 TRACE("(%p)->(%p)\n", This, typename);
1251 return return_null_var( typename );
1255 static HRESULT WINAPI domdoc_put_dataType(
1256 IXMLDOMDocument3 *iface,
1257 BSTR dataTypeName )
1259 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1261 FIXME("(%p)->(%s)\n", This, debugstr_w(dataTypeName));
1263 if(!dataTypeName)
1264 return E_INVALIDARG;
1266 return E_FAIL;
1269 static int XMLCALL domdoc_get_xml_writecallback(void *ctx, const char *data, int len)
1271 return xmlBufferAdd((xmlBufferPtr)ctx, (xmlChar*)data, len) == 0 ? len : 0;
1274 static HRESULT WINAPI domdoc_get_xml(
1275 IXMLDOMDocument3 *iface,
1276 BSTR* p)
1278 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1279 xmlSaveCtxtPtr ctxt;
1280 xmlBufferPtr buf;
1281 int options;
1282 long ret;
1284 TRACE("(%p)->(%p)\n", This, p);
1286 if(!p)
1287 return E_INVALIDARG;
1289 *p = NULL;
1291 buf = xmlBufferCreate();
1292 if(!buf)
1293 return E_OUTOFMEMORY;
1295 options = XML_SAVE_FORMAT | XML_SAVE_NO_DECL;
1296 ctxt = xmlSaveToIO(domdoc_get_xml_writecallback, NULL, buf, "UTF-8", options);
1298 if(!ctxt)
1300 xmlBufferFree(buf);
1301 return E_OUTOFMEMORY;
1304 ret = xmlSaveDoc(ctxt, get_doc(This));
1305 /* flushes on close */
1306 xmlSaveClose(ctxt);
1308 TRACE("%ld, len=%d\n", ret, xmlBufferLength(buf));
1309 if(ret != -1 && xmlBufferLength(buf) > 0)
1311 BSTR content;
1313 content = bstr_from_xmlChar(xmlBufferContent(buf));
1314 content = EnsureCorrectEOL(content);
1316 *p = content;
1318 else
1320 *p = SysAllocStringLen(NULL, 0);
1323 xmlBufferFree(buf);
1325 return *p ? S_OK : E_OUTOFMEMORY;
1329 static HRESULT WINAPI domdoc_transformNode(
1330 IXMLDOMDocument3 *iface,
1331 IXMLDOMNode *node,
1332 BSTR *p)
1334 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1335 TRACE("(%p)->(%p %p)\n", This, node, p);
1336 return node_transform_node(&This->node, node, p);
1340 static HRESULT WINAPI domdoc_selectNodes(
1341 IXMLDOMDocument3 *iface,
1342 BSTR p,
1343 IXMLDOMNodeList **outList)
1345 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1346 TRACE("(%p)->(%s %p)\n", This, debugstr_w(p), outList);
1347 return node_select_nodes(&This->node, p, outList);
1351 static HRESULT WINAPI domdoc_selectSingleNode(
1352 IXMLDOMDocument3 *iface,
1353 BSTR p,
1354 IXMLDOMNode **outNode)
1356 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1357 TRACE("(%p)->(%s %p)\n", This, debugstr_w(p), outNode);
1358 return node_select_singlenode(&This->node, p, outNode);
1362 static HRESULT WINAPI domdoc_get_parsed(
1363 IXMLDOMDocument3 *iface,
1364 VARIANT_BOOL* isParsed )
1366 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1367 FIXME("(%p)->(%p) stub!\n", This, isParsed);
1368 *isParsed = VARIANT_TRUE;
1369 return S_OK;
1372 static HRESULT WINAPI domdoc_get_namespaceURI(
1373 IXMLDOMDocument3 *iface,
1374 BSTR* namespaceURI )
1376 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1377 TRACE("(%p)->(%p)\n", This, namespaceURI);
1378 return return_null_bstr( namespaceURI );
1381 static HRESULT WINAPI domdoc_get_prefix(
1382 IXMLDOMDocument3 *iface,
1383 BSTR* prefix )
1385 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1386 TRACE("(%p)->(%p)\n", This, prefix);
1387 return return_null_bstr( prefix );
1391 static HRESULT WINAPI domdoc_get_baseName(
1392 IXMLDOMDocument3 *iface,
1393 BSTR* name )
1395 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1396 TRACE("(%p)->(%p)\n", This, name);
1397 return return_null_bstr( name );
1401 static HRESULT WINAPI domdoc_transformNodeToObject(
1402 IXMLDOMDocument3 *iface,
1403 IXMLDOMNode* stylesheet,
1404 VARIANT outputObject)
1406 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1407 FIXME("(%p)->(%p %s)\n", This, stylesheet, debugstr_variant(&outputObject));
1408 return E_NOTIMPL;
1412 static HRESULT WINAPI domdoc_get_doctype(
1413 IXMLDOMDocument3 *iface,
1414 IXMLDOMDocumentType** doctype )
1416 domdoc *This = impl_from_IXMLDOMDocument3(iface);
1417 IXMLDOMNode *node;
1418 xmlDtdPtr dtd;
1419 HRESULT hr;
1421 TRACE("(%p)->(%p)\n", This, doctype);
1423 if (!doctype) return E_INVALIDARG;
1425 *doctype = NULL;
1427 dtd = xmlGetIntSubset(get_doc(This));
1428 if (!dtd) return S_FALSE;
1430 node = create_node((xmlNodePtr)dtd);
1431 if (!node) return S_FALSE;
1433 hr = IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMDocumentType, (void**)doctype);
1434 IXMLDOMNode_Release(node);
1436 return hr;
1440 static HRESULT WINAPI domdoc_get_implementation(
1441 IXMLDOMDocument3 *iface,
1442 IXMLDOMImplementation** impl )
1444 domdoc *This = impl_from_IXMLDOMDocument3(iface);
1446 TRACE("(%p)->(%p)\n", This, impl);
1448 if(!impl)
1449 return E_INVALIDARG;
1451 *impl = (IXMLDOMImplementation*)create_doc_Implementation();
1453 return S_OK;
1456 static HRESULT WINAPI domdoc_get_documentElement(
1457 IXMLDOMDocument3 *iface,
1458 IXMLDOMElement** DOMElement )
1460 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1461 IXMLDOMNode *element_node;
1462 xmlNodePtr root;
1463 HRESULT hr;
1465 TRACE("(%p)->(%p)\n", This, DOMElement);
1467 if(!DOMElement)
1468 return E_INVALIDARG;
1470 *DOMElement = NULL;
1472 root = xmlDocGetRootElement( get_doc(This) );
1473 if ( !root )
1474 return S_FALSE;
1476 element_node = create_node( root );
1477 if(!element_node) return S_FALSE;
1479 hr = IXMLDOMNode_QueryInterface(element_node, &IID_IXMLDOMElement, (void**)DOMElement);
1480 IXMLDOMNode_Release(element_node);
1482 return hr;
1486 static HRESULT WINAPI domdoc_put_documentElement(
1487 IXMLDOMDocument3 *iface,
1488 IXMLDOMElement* DOMElement )
1490 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1491 IXMLDOMNode *elementNode;
1492 xmlNodePtr oldRoot;
1493 xmlnode *xmlNode;
1494 HRESULT hr;
1496 TRACE("(%p)->(%p)\n", This, DOMElement);
1498 hr = IXMLDOMElement_QueryInterface( DOMElement, &IID_IXMLDOMNode, (void**)&elementNode );
1499 if(FAILED(hr))
1500 return hr;
1502 xmlNode = get_node_obj( elementNode );
1503 if(!xmlNode) return E_FAIL;
1505 if(!xmlNode->node->parent)
1506 if(xmldoc_remove_orphan(xmlNode->node->doc, xmlNode->node) != S_OK)
1507 WARN("%p is not an orphan of %p\n", xmlNode->node->doc, xmlNode->node);
1509 oldRoot = xmlDocSetRootElement( get_doc(This), xmlNode->node);
1510 IXMLDOMNode_Release( elementNode );
1512 if(oldRoot)
1513 xmldoc_add_orphan(oldRoot->doc, oldRoot);
1515 return S_OK;
1519 static HRESULT WINAPI domdoc_createElement(
1520 IXMLDOMDocument3 *iface,
1521 BSTR tagname,
1522 IXMLDOMElement** element )
1524 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1525 IXMLDOMNode *node;
1526 VARIANT type;
1527 HRESULT hr;
1529 TRACE("(%p)->(%s %p)\n", This, debugstr_w(tagname), element);
1531 if (!element || !tagname) return E_INVALIDARG;
1533 V_VT(&type) = VT_I1;
1534 V_I1(&type) = NODE_ELEMENT;
1536 hr = IXMLDOMDocument3_createNode(iface, type, tagname, NULL, &node);
1537 if (hr == S_OK)
1539 IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMElement, (void**)element);
1540 IXMLDOMNode_Release(node);
1543 return hr;
1547 static HRESULT WINAPI domdoc_createDocumentFragment(
1548 IXMLDOMDocument3 *iface,
1549 IXMLDOMDocumentFragment** frag )
1551 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1552 IXMLDOMNode *node;
1553 VARIANT type;
1554 HRESULT hr;
1556 TRACE("(%p)->(%p)\n", This, frag);
1558 if (!frag) return E_INVALIDARG;
1560 *frag = NULL;
1562 V_VT(&type) = VT_I1;
1563 V_I1(&type) = NODE_DOCUMENT_FRAGMENT;
1565 hr = IXMLDOMDocument3_createNode(iface, type, NULL, NULL, &node);
1566 if (hr == S_OK)
1568 IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMDocumentFragment, (void**)frag);
1569 IXMLDOMNode_Release(node);
1572 return hr;
1576 static HRESULT WINAPI domdoc_createTextNode(
1577 IXMLDOMDocument3 *iface,
1578 BSTR data,
1579 IXMLDOMText** text )
1581 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1582 IXMLDOMNode *node;
1583 VARIANT type;
1584 HRESULT hr;
1586 TRACE("(%p)->(%s %p)\n", This, debugstr_w(data), text);
1588 if (!text) return E_INVALIDARG;
1590 *text = NULL;
1592 V_VT(&type) = VT_I1;
1593 V_I1(&type) = NODE_TEXT;
1595 hr = IXMLDOMDocument3_createNode(iface, type, NULL, NULL, &node);
1596 if (hr == S_OK)
1598 IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMText, (void**)text);
1599 IXMLDOMNode_Release(node);
1600 hr = IXMLDOMText_put_data(*text, data);
1603 return hr;
1607 static HRESULT WINAPI domdoc_createComment(
1608 IXMLDOMDocument3 *iface,
1609 BSTR data,
1610 IXMLDOMComment** comment )
1612 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1613 VARIANT type;
1614 HRESULT hr;
1615 IXMLDOMNode *node;
1617 TRACE("(%p)->(%s %p)\n", This, debugstr_w(data), comment);
1619 if (!comment) return E_INVALIDARG;
1621 *comment = NULL;
1623 V_VT(&type) = VT_I1;
1624 V_I1(&type) = NODE_COMMENT;
1626 hr = IXMLDOMDocument3_createNode(iface, type, NULL, NULL, &node);
1627 if (hr == S_OK)
1629 IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMComment, (void**)comment);
1630 IXMLDOMNode_Release(node);
1631 hr = IXMLDOMComment_put_data(*comment, data);
1634 return hr;
1638 static HRESULT WINAPI domdoc_createCDATASection(
1639 IXMLDOMDocument3 *iface,
1640 BSTR data,
1641 IXMLDOMCDATASection** cdata )
1643 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1644 IXMLDOMNode *node;
1645 VARIANT type;
1646 HRESULT hr;
1648 TRACE("(%p)->(%s %p)\n", This, debugstr_w(data), cdata);
1650 if (!cdata) return E_INVALIDARG;
1652 *cdata = NULL;
1654 V_VT(&type) = VT_I1;
1655 V_I1(&type) = NODE_CDATA_SECTION;
1657 hr = IXMLDOMDocument3_createNode(iface, type, NULL, NULL, &node);
1658 if (hr == S_OK)
1660 IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMCDATASection, (void**)cdata);
1661 IXMLDOMNode_Release(node);
1662 hr = IXMLDOMCDATASection_put_data(*cdata, data);
1665 return hr;
1669 static HRESULT WINAPI domdoc_createProcessingInstruction(
1670 IXMLDOMDocument3 *iface,
1671 BSTR target,
1672 BSTR data,
1673 IXMLDOMProcessingInstruction** pi )
1675 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1676 IXMLDOMNode *node;
1677 VARIANT type;
1678 HRESULT hr;
1680 TRACE("(%p)->(%s %s %p)\n", This, debugstr_w(target), debugstr_w(data), pi);
1682 if (!pi) return E_INVALIDARG;
1684 *pi = NULL;
1686 V_VT(&type) = VT_I1;
1687 V_I1(&type) = NODE_PROCESSING_INSTRUCTION;
1689 hr = IXMLDOMDocument3_createNode(iface, type, target, NULL, &node);
1690 if (hr == S_OK)
1692 xmlnode *node_obj;
1694 /* this is to bypass check in ::put_data() that blocks "<?xml" PIs */
1695 node_obj = get_node_obj(node);
1696 hr = node_set_content(node_obj, data);
1698 IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMProcessingInstruction, (void**)pi);
1699 IXMLDOMNode_Release(node);
1702 return hr;
1706 static HRESULT WINAPI domdoc_createAttribute(
1707 IXMLDOMDocument3 *iface,
1708 BSTR name,
1709 IXMLDOMAttribute** attribute )
1711 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1712 IXMLDOMNode *node;
1713 VARIANT type;
1714 HRESULT hr;
1716 TRACE("(%p)->(%s %p)\n", This, debugstr_w(name), attribute);
1718 if (!attribute || !name) return E_INVALIDARG;
1720 V_VT(&type) = VT_I1;
1721 V_I1(&type) = NODE_ATTRIBUTE;
1723 hr = IXMLDOMDocument3_createNode(iface, type, name, NULL, &node);
1724 if (hr == S_OK)
1726 IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMAttribute, (void**)attribute);
1727 IXMLDOMNode_Release(node);
1730 return hr;
1734 static HRESULT WINAPI domdoc_createEntityReference(
1735 IXMLDOMDocument3 *iface,
1736 BSTR name,
1737 IXMLDOMEntityReference** entityref )
1739 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1740 IXMLDOMNode *node;
1741 VARIANT type;
1742 HRESULT hr;
1744 TRACE("(%p)->(%s %p)\n", This, debugstr_w(name), entityref);
1746 if (!entityref) return E_INVALIDARG;
1748 *entityref = NULL;
1750 V_VT(&type) = VT_I1;
1751 V_I1(&type) = NODE_ENTITY_REFERENCE;
1753 hr = IXMLDOMDocument3_createNode(iface, type, name, NULL, &node);
1754 if (hr == S_OK)
1756 IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMEntityReference, (void**)entityref);
1757 IXMLDOMNode_Release(node);
1760 return hr;
1763 xmlChar* tagName_to_XPath(const BSTR tagName)
1765 xmlChar *query, *tmp;
1766 static const xmlChar mod_pre[] = "*[local-name()='";
1767 static const xmlChar mod_post[] = "']";
1768 static const xmlChar prefix[] = "descendant::";
1769 const WCHAR *tokBegin, *tokEnd;
1770 int len;
1772 query = xmlStrdup(prefix);
1774 tokBegin = tagName;
1775 while (tokBegin && *tokBegin)
1777 switch (*tokBegin)
1779 case '/':
1780 query = xmlStrcat(query, BAD_CAST "/");
1781 ++tokBegin;
1782 break;
1783 case '*':
1784 query = xmlStrcat(query, BAD_CAST "*");
1785 ++tokBegin;
1786 break;
1787 default:
1788 query = xmlStrcat(query, mod_pre);
1789 tokEnd = tokBegin;
1790 while (*tokEnd && *tokEnd != '/')
1791 ++tokEnd;
1792 len = WideCharToMultiByte(CP_UTF8, 0, tokBegin, tokEnd-tokBegin, NULL, 0, NULL, NULL);
1793 tmp = xmlMalloc(len);
1794 WideCharToMultiByte(CP_UTF8, 0, tokBegin, tokEnd-tokBegin, (char*)tmp, len, NULL, NULL);
1795 query = xmlStrncat(query, tmp, len);
1796 xmlFree(tmp);
1797 tokBegin = tokEnd;
1798 query = xmlStrcat(query, mod_post);
1802 return query;
1805 static HRESULT WINAPI domdoc_getElementsByTagName(
1806 IXMLDOMDocument3 *iface,
1807 BSTR tagName,
1808 IXMLDOMNodeList** resultList )
1810 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1811 xmlChar *query;
1812 HRESULT hr;
1813 BOOL XPath;
1815 TRACE("(%p)->(%s, %p)\n", This, debugstr_w(tagName), resultList);
1817 if (!tagName || !resultList) return E_INVALIDARG;
1819 XPath = This->properties->XPath;
1820 This->properties->XPath = TRUE;
1821 query = tagName_to_XPath(tagName);
1822 hr = create_selection((xmlNodePtr)get_doc(This), query, resultList);
1823 xmlFree(query);
1824 This->properties->XPath = XPath;
1826 return hr;
1829 static HRESULT get_node_type(VARIANT Type, DOMNodeType * type)
1831 VARIANT tmp;
1832 HRESULT hr;
1834 VariantInit(&tmp);
1835 hr = VariantChangeType(&tmp, &Type, 0, VT_I4);
1836 if(FAILED(hr))
1837 return E_INVALIDARG;
1839 *type = V_I4(&tmp);
1841 return S_OK;
1844 static HRESULT WINAPI domdoc_createNode(
1845 IXMLDOMDocument3 *iface,
1846 VARIANT Type,
1847 BSTR name,
1848 BSTR namespaceURI,
1849 IXMLDOMNode** node )
1851 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1852 DOMNodeType node_type;
1853 xmlNodePtr xmlnode;
1854 xmlChar *xml_name, *href;
1855 HRESULT hr;
1857 TRACE("(%p)->(%s %s %p)\n", This, debugstr_w(name), debugstr_w(namespaceURI), node);
1859 if(!node) return E_INVALIDARG;
1861 hr = get_node_type(Type, &node_type);
1862 if(FAILED(hr)) return hr;
1864 if(namespaceURI && namespaceURI[0] && node_type != NODE_ELEMENT)
1865 FIXME("nodes with namespaces currently not supported.\n");
1867 TRACE("node_type %d\n", node_type);
1869 /* exit earlier for types that need name */
1870 switch(node_type)
1872 case NODE_ELEMENT:
1873 case NODE_ATTRIBUTE:
1874 case NODE_ENTITY_REFERENCE:
1875 case NODE_PROCESSING_INSTRUCTION:
1876 if (!name || *name == 0) return E_FAIL;
1877 break;
1878 default:
1879 break;
1882 xml_name = xmlchar_from_wchar(name);
1883 /* prevent empty href to be allocated */
1884 href = namespaceURI ? xmlchar_from_wchar(namespaceURI) : NULL;
1886 switch(node_type)
1888 case NODE_ELEMENT:
1890 xmlChar *local, *prefix;
1892 local = xmlSplitQName2(xml_name, &prefix);
1894 xmlnode = xmlNewDocNode(get_doc(This), NULL, local ? local : xml_name, NULL);
1896 /* allow to create default namespace xmlns= */
1897 if (local || (href && *href))
1899 xmlNsPtr ns = xmlNewNs(xmlnode, href, prefix);
1900 xmlSetNs(xmlnode, ns);
1903 xmlFree(local);
1904 xmlFree(prefix);
1906 break;
1908 case NODE_ATTRIBUTE:
1909 xmlnode = (xmlNodePtr)xmlNewDocProp(get_doc(This), xml_name, NULL);
1910 break;
1911 case NODE_TEXT:
1912 xmlnode = (xmlNodePtr)xmlNewDocText(get_doc(This), NULL);
1913 break;
1914 case NODE_CDATA_SECTION:
1915 xmlnode = xmlNewCDataBlock(get_doc(This), NULL, 0);
1916 break;
1917 case NODE_ENTITY_REFERENCE:
1918 xmlnode = xmlNewReference(get_doc(This), xml_name);
1919 break;
1920 case NODE_PROCESSING_INSTRUCTION:
1921 #ifdef HAVE_XMLNEWDOCPI
1922 xmlnode = xmlNewDocPI(get_doc(This), xml_name, NULL);
1923 #else
1924 FIXME("xmlNewDocPI() not supported, use libxml2 2.6.15 or greater\n");
1925 xmlnode = NULL;
1926 #endif
1927 break;
1928 case NODE_COMMENT:
1929 xmlnode = xmlNewDocComment(get_doc(This), NULL);
1930 break;
1931 case NODE_DOCUMENT_FRAGMENT:
1932 xmlnode = xmlNewDocFragment(get_doc(This));
1933 break;
1934 /* unsupported types */
1935 case NODE_DOCUMENT:
1936 case NODE_DOCUMENT_TYPE:
1937 case NODE_ENTITY:
1938 case NODE_NOTATION:
1939 heap_free(xml_name);
1940 return E_INVALIDARG;
1941 default:
1942 FIXME("unhandled node type %d\n", node_type);
1943 xmlnode = NULL;
1944 break;
1947 *node = create_node(xmlnode);
1948 heap_free(xml_name);
1949 heap_free(href);
1951 if(*node)
1953 TRACE("created node (%d, %p, %p)\n", node_type, *node, xmlnode);
1954 xmldoc_add_orphan(xmlnode->doc, xmlnode);
1955 return S_OK;
1958 return E_FAIL;
1961 static HRESULT WINAPI domdoc_nodeFromID(
1962 IXMLDOMDocument3 *iface,
1963 BSTR idString,
1964 IXMLDOMNode** node )
1966 domdoc *This = impl_from_IXMLDOMDocument3(iface);
1967 FIXME("(%p)->(%s %p)\n", This, debugstr_w(idString), node);
1968 return E_NOTIMPL;
1971 static HRESULT domdoc_onDataAvailable(void *obj, char *ptr, DWORD len)
1973 domdoc *This = obj;
1974 xmlDocPtr xmldoc;
1976 xmldoc = doparse(This, ptr, len, XML_CHAR_ENCODING_NONE);
1977 if(xmldoc) {
1978 xmldoc->_private = create_priv();
1979 return attach_xmldoc(This, xmldoc);
1982 return S_OK;
1985 static HRESULT doread( domdoc *This, LPWSTR filename )
1987 bsc_t *bsc;
1988 HRESULT hr;
1990 hr = bind_url(filename, domdoc_onDataAvailable, This, &bsc);
1991 if(FAILED(hr))
1992 return hr;
1994 if(This->bsc) {
1995 hr = detach_bsc(This->bsc);
1996 if(FAILED(hr))
1997 return hr;
2000 This->bsc = bsc;
2001 return S_OK;
2004 static HRESULT WINAPI domdoc_load(
2005 IXMLDOMDocument3 *iface,
2006 VARIANT source,
2007 VARIANT_BOOL* isSuccessful )
2009 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2010 LPWSTR filename = NULL;
2011 HRESULT hr = S_FALSE;
2012 IXMLDOMDocument3 *pNewDoc = NULL;
2013 IStream *pStream = NULL;
2014 xmlDocPtr xmldoc;
2016 TRACE("(%p)->(%s)\n", This, debugstr_variant(&source));
2018 if (!isSuccessful)
2019 return E_POINTER;
2020 *isSuccessful = VARIANT_FALSE;
2022 assert( &This->node );
2024 switch( V_VT(&source) )
2026 case VT_BSTR:
2027 filename = V_BSTR(&source);
2028 break;
2029 case VT_BSTR|VT_BYREF:
2030 if (!V_BSTRREF(&source)) return E_INVALIDARG;
2031 filename = *V_BSTRREF(&source);
2032 break;
2033 case VT_ARRAY|VT_UI1:
2035 SAFEARRAY *psa = V_ARRAY(&source);
2036 char *str;
2037 LONG len;
2038 UINT dim = SafeArrayGetDim(psa);
2040 switch (dim)
2042 case 0:
2043 ERR("SAFEARRAY == NULL\n");
2044 hr = This->error = E_INVALIDARG;
2045 break;
2046 case 1:
2047 /* Only takes UTF-8 strings.
2048 * NOT NULL-terminated. */
2049 SafeArrayAccessData(psa, (void**)&str);
2050 SafeArrayGetUBound(psa, 1, &len);
2052 if ((xmldoc = doparse(This, str, ++len, XML_CHAR_ENCODING_UTF8)))
2054 hr = This->error = S_OK;
2055 *isSuccessful = VARIANT_TRUE;
2056 TRACE("parsed document %p\n", xmldoc);
2058 else
2060 This->error = E_FAIL;
2061 TRACE("failed to parse document\n");
2064 SafeArrayUnaccessData(psa);
2066 if(xmldoc)
2068 xmldoc->_private = create_priv();
2069 return attach_xmldoc(This, xmldoc);
2071 break;
2072 default:
2073 FIXME("unhandled SAFEARRAY dim: %d\n", dim);
2074 hr = This->error = E_NOTIMPL;
2077 break;
2078 case VT_UNKNOWN:
2079 hr = IUnknown_QueryInterface(V_UNKNOWN(&source), &IID_IXMLDOMDocument3, (void**)&pNewDoc);
2080 if(hr == S_OK)
2082 if(pNewDoc)
2084 domdoc *newDoc = impl_from_IXMLDOMDocument3( pNewDoc );
2085 xmldoc = xmlCopyDoc(get_doc(newDoc), 1);
2086 hr = attach_xmldoc(This, xmldoc);
2088 if(SUCCEEDED(hr))
2089 *isSuccessful = VARIANT_TRUE;
2091 return hr;
2094 hr = IUnknown_QueryInterface(V_UNKNOWN(&source), &IID_IStream, (void**)&pStream);
2095 if(hr == S_OK)
2097 IPersistStream *pDocStream;
2098 hr = IUnknown_QueryInterface(iface, &IID_IPersistStream, (void**)&pDocStream);
2099 if(hr == S_OK)
2101 hr = IPersistStream_Load(pDocStream, pStream);
2102 IStream_Release(pStream);
2103 if(hr == S_OK)
2105 *isSuccessful = VARIANT_TRUE;
2107 TRACE("Using IStream to load Document\n");
2108 return S_OK;
2110 else
2112 ERR("xmldoc_IPersistStream_Load failed (%d)\n", hr);
2115 else
2117 ERR("QueryInterface IID_IPersistStream failed (%d)\n", hr);
2120 else
2122 /* ISequentialStream */
2123 FIXME("Unknown type not supported (%d) (%p)(%p)\n", hr, pNewDoc, V_UNKNOWN(&source)->lpVtbl);
2125 break;
2126 default:
2127 FIXME("VT type not supported (%d)\n", V_VT(&source));
2130 if ( filename )
2132 hr = doread( This, filename );
2134 if ( FAILED(hr) )
2135 This->error = E_FAIL;
2136 else
2138 hr = This->error = S_OK;
2139 *isSuccessful = VARIANT_TRUE;
2143 if(!filename || FAILED(hr)) {
2144 xmldoc = xmlNewDoc(NULL);
2145 xmldoc->_private = create_priv();
2146 hr = attach_xmldoc(This, xmldoc);
2147 if(SUCCEEDED(hr))
2148 hr = S_FALSE;
2151 TRACE("ret (%d)\n", hr);
2153 return hr;
2157 static HRESULT WINAPI domdoc_get_readyState(
2158 IXMLDOMDocument3 *iface,
2159 LONG *value )
2161 domdoc *This = impl_from_IXMLDOMDocument3(iface);
2162 FIXME("stub! (%p)->(%p)\n", This, value);
2164 if (!value)
2165 return E_INVALIDARG;
2167 *value = READYSTATE_COMPLETE;
2168 return S_OK;
2172 static HRESULT WINAPI domdoc_get_parseError(
2173 IXMLDOMDocument3 *iface,
2174 IXMLDOMParseError** errorObj )
2176 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2177 static const WCHAR err[] = {'e','r','r','o','r',0};
2178 BSTR error_string = NULL;
2180 FIXME("(%p)->(%p): creating a dummy parseError\n", iface, errorObj);
2182 if(This->error)
2183 error_string = SysAllocString(err);
2185 *errorObj = create_parseError(This->error, NULL, error_string, NULL, 0, 0, 0);
2186 if(!*errorObj) return E_OUTOFMEMORY;
2187 return S_OK;
2191 static HRESULT WINAPI domdoc_get_url(
2192 IXMLDOMDocument3 *iface,
2193 BSTR* urlString )
2195 domdoc *This = impl_from_IXMLDOMDocument3(iface);
2196 FIXME("(%p)->(%p)\n", This, urlString);
2197 return E_NOTIMPL;
2201 static HRESULT WINAPI domdoc_get_async(
2202 IXMLDOMDocument3 *iface,
2203 VARIANT_BOOL* isAsync )
2205 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2207 TRACE("(%p)->(%p: %d)\n", This, isAsync, This->async);
2208 *isAsync = This->async;
2209 return S_OK;
2213 static HRESULT WINAPI domdoc_put_async(
2214 IXMLDOMDocument3 *iface,
2215 VARIANT_BOOL isAsync )
2217 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2219 TRACE("(%p)->(%d)\n", This, isAsync);
2220 This->async = isAsync;
2221 return S_OK;
2225 static HRESULT WINAPI domdoc_abort(
2226 IXMLDOMDocument3 *iface )
2228 domdoc *This = impl_from_IXMLDOMDocument3(iface);
2229 FIXME("%p\n", This);
2230 return E_NOTIMPL;
2233 /* don't rely on data to be in BSTR format, treat it as WCHAR string */
2234 static HRESULT WINAPI domdoc_loadXML(
2235 IXMLDOMDocument3 *iface,
2236 BSTR data,
2237 VARIANT_BOOL* isSuccessful )
2239 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2240 xmlDocPtr xmldoc = NULL;
2241 HRESULT hr = S_FALSE, hr2;
2243 TRACE("(%p)->(%s %p)\n", This, debugstr_w(data), isSuccessful );
2245 assert ( &This->node );
2247 if ( isSuccessful )
2249 *isSuccessful = VARIANT_FALSE;
2251 if (data)
2253 WCHAR *ptr = data;
2255 /* skip leading spaces if needed */
2256 if (This->properties->version == MSXML_DEFAULT || This->properties->version == MSXML26)
2257 while (*ptr)
2258 if (isspaceW(*ptr)) ptr++; else break;
2260 xmldoc = doparse(This, (char*)ptr, strlenW(ptr)*sizeof(WCHAR), XML_CHAR_ENCODING_UTF16LE);
2261 if ( !xmldoc )
2263 This->error = E_FAIL;
2264 TRACE("failed to parse document\n");
2266 else
2268 hr = This->error = S_OK;
2269 *isSuccessful = VARIANT_TRUE;
2270 TRACE("parsed document %p\n", xmldoc);
2274 if(!xmldoc)
2275 xmldoc = xmlNewDoc(NULL);
2277 xmldoc->_private = create_priv();
2279 hr2 = attach_xmldoc(This, xmldoc);
2280 if( FAILED(hr2) )
2281 hr = hr2;
2283 return hr;
2286 static int XMLCALL domdoc_save_writecallback(void *ctx, const char *buffer, int len)
2288 DWORD written = -1;
2290 if(!WriteFile(ctx, buffer, len, &written, NULL))
2292 WARN("write error\n");
2293 return -1;
2295 else
2296 return written;
2299 static int XMLCALL domdoc_save_closecallback(void *ctx)
2301 return CloseHandle(ctx) ? 0 : -1;
2304 static int XMLCALL domdoc_stream_save_writecallback(void *ctx, const char *buffer, int len)
2306 ULONG written = 0;
2307 HRESULT hr;
2309 hr = IStream_Write((IStream*)ctx, buffer, len, &written);
2310 if (hr != S_OK)
2312 WARN("stream write error: 0x%08x\n", hr);
2313 return -1;
2315 else
2316 return written;
2319 static int XMLCALL domdoc_stream_save_closecallback(void *ctx)
2321 IStream_Release((IStream*)ctx);
2322 return 0;
2325 static HRESULT WINAPI domdoc_save(
2326 IXMLDOMDocument3 *iface,
2327 VARIANT destination )
2329 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2330 xmlSaveCtxtPtr ctx = NULL;
2331 xmlNodePtr xmldecl;
2332 HRESULT ret = S_OK;
2334 TRACE("(%p)->(%s)\n", This, debugstr_variant(&destination));
2336 switch (V_VT(&destination))
2338 case VT_UNKNOWN:
2340 IUnknown *pUnk = V_UNKNOWN(&destination);
2341 IXMLDOMDocument3 *document;
2342 IStream *stream;
2344 ret = IUnknown_QueryInterface(pUnk, &IID_IXMLDOMDocument3, (void**)&document);
2345 if(ret == S_OK)
2347 VARIANT_BOOL success;
2348 BSTR xml;
2350 ret = IXMLDOMDocument3_get_xml(iface, &xml);
2351 if(ret == S_OK)
2353 ret = IXMLDOMDocument3_loadXML(document, xml, &success);
2354 SysFreeString(xml);
2357 IXMLDOMDocument3_Release(document);
2358 return ret;
2361 ret = IUnknown_QueryInterface(pUnk, &IID_IStream, (void**)&stream);
2362 if(ret == S_OK)
2364 ctx = xmlSaveToIO(domdoc_stream_save_writecallback,
2365 domdoc_stream_save_closecallback, stream, NULL, XML_SAVE_NO_DECL);
2367 if(!ctx)
2369 IStream_Release(stream);
2370 return E_FAIL;
2374 break;
2376 case VT_BSTR:
2377 case VT_BSTR | VT_BYREF:
2379 /* save with file path */
2380 HANDLE handle = CreateFileW( (V_VT(&destination) & VT_BYREF)? *V_BSTRREF(&destination) : V_BSTR(&destination),
2381 GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL );
2382 if( handle == INVALID_HANDLE_VALUE )
2384 WARN("failed to create file\n");
2385 return E_FAIL;
2388 /* disable top XML declaration */
2389 ctx = xmlSaveToIO(domdoc_save_writecallback, domdoc_save_closecallback,
2390 handle, NULL, XML_SAVE_NO_DECL);
2391 if (!ctx)
2393 CloseHandle(handle);
2394 return E_FAIL;
2397 break;
2399 default:
2400 FIXME("Unhandled VARIANT: %s\n", debugstr_variant(&destination));
2401 return S_FALSE;
2404 xmldecl = xmldoc_unlink_xmldecl(get_doc(This));
2405 if (xmlSaveDoc(ctx, get_doc(This)) == -1) ret = S_FALSE;
2406 xmldoc_link_xmldecl(get_doc(This), xmldecl);
2408 /* will release resources through close callback */
2409 xmlSaveClose(ctx);
2411 return ret;
2414 static HRESULT WINAPI domdoc_get_validateOnParse(
2415 IXMLDOMDocument3 *iface,
2416 VARIANT_BOOL* isValidating )
2418 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2419 TRACE("(%p)->(%p: %d)\n", This, isValidating, This->validating);
2420 *isValidating = This->validating;
2421 return S_OK;
2425 static HRESULT WINAPI domdoc_put_validateOnParse(
2426 IXMLDOMDocument3 *iface,
2427 VARIANT_BOOL isValidating )
2429 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2430 TRACE("(%p)->(%d)\n", This, isValidating);
2431 This->validating = isValidating;
2432 return S_OK;
2436 static HRESULT WINAPI domdoc_get_resolveExternals(
2437 IXMLDOMDocument3 *iface,
2438 VARIANT_BOOL* isResolving )
2440 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2441 TRACE("(%p)->(%p: %d)\n", This, isResolving, This->resolving);
2442 *isResolving = This->resolving;
2443 return S_OK;
2447 static HRESULT WINAPI domdoc_put_resolveExternals(
2448 IXMLDOMDocument3 *iface,
2449 VARIANT_BOOL isResolving )
2451 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2452 TRACE("(%p)->(%d)\n", This, isResolving);
2453 This->resolving = isResolving;
2454 return S_OK;
2458 static HRESULT WINAPI domdoc_get_preserveWhiteSpace(
2459 IXMLDOMDocument3 *iface,
2460 VARIANT_BOOL* isPreserving )
2462 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2463 TRACE("(%p)->(%p: %d)\n", This, isPreserving, This->properties->preserving);
2464 *isPreserving = This->properties->preserving;
2465 return S_OK;
2469 static HRESULT WINAPI domdoc_put_preserveWhiteSpace(
2470 IXMLDOMDocument3 *iface,
2471 VARIANT_BOOL isPreserving )
2473 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2474 TRACE("(%p)->(%d)\n", This, isPreserving);
2475 This->properties->preserving = isPreserving;
2476 return S_OK;
2480 static HRESULT WINAPI domdoc_put_onreadystatechange(
2481 IXMLDOMDocument3 *iface,
2482 VARIANT event )
2484 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2486 TRACE("(%p)->(%s)\n", This, debugstr_variant(&event));
2487 return set_doc_event(This, EVENTID_READYSTATECHANGE, &event);
2491 static HRESULT WINAPI domdoc_put_onDataAvailable(
2492 IXMLDOMDocument3 *iface,
2493 VARIANT onDataAvailableSink )
2495 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2496 FIXME("%p\n", This);
2497 return E_NOTIMPL;
2500 static HRESULT WINAPI domdoc_put_onTransformNode(
2501 IXMLDOMDocument3 *iface,
2502 VARIANT onTransformNodeSink )
2504 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2505 FIXME("%p\n", This);
2506 return E_NOTIMPL;
2509 static HRESULT WINAPI domdoc_get_namespaces(
2510 IXMLDOMDocument3* iface,
2511 IXMLDOMSchemaCollection** schemaCollection )
2513 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2514 FIXME("(%p)->(%p)\n", This, schemaCollection);
2515 return E_NOTIMPL;
2518 static HRESULT WINAPI domdoc_get_schemas(
2519 IXMLDOMDocument3* iface,
2520 VARIANT* var1 )
2522 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2523 HRESULT hr = S_FALSE;
2524 IXMLDOMSchemaCollection2* cur_schema = This->properties->schemaCache;
2526 TRACE("(%p)->(%p)\n", This, var1);
2528 VariantInit(var1); /* Test shows we don't call VariantClear here */
2529 V_VT(var1) = VT_NULL;
2531 if(cur_schema)
2533 hr = IXMLDOMSchemaCollection2_QueryInterface(cur_schema, &IID_IDispatch, (void**)&V_DISPATCH(var1));
2534 if(SUCCEEDED(hr))
2535 V_VT(var1) = VT_DISPATCH;
2537 return hr;
2540 static HRESULT WINAPI domdoc_putref_schemas(
2541 IXMLDOMDocument3* iface,
2542 VARIANT var1)
2544 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2545 HRESULT hr = E_FAIL;
2546 IXMLDOMSchemaCollection2* new_schema = NULL;
2548 FIXME("(%p): semi-stub\n", This);
2549 switch(V_VT(&var1))
2551 case VT_UNKNOWN:
2552 hr = IUnknown_QueryInterface(V_UNKNOWN(&var1), &IID_IXMLDOMSchemaCollection, (void**)&new_schema);
2553 break;
2555 case VT_DISPATCH:
2556 hr = IDispatch_QueryInterface(V_DISPATCH(&var1), &IID_IXMLDOMSchemaCollection, (void**)&new_schema);
2557 break;
2559 case VT_NULL:
2560 case VT_EMPTY:
2561 hr = S_OK;
2562 break;
2564 default:
2565 WARN("Can't get schema from vt %x\n", V_VT(&var1));
2568 if(SUCCEEDED(hr))
2570 IXMLDOMSchemaCollection2* old_schema = InterlockedExchangePointer((void**)&This->properties->schemaCache, new_schema);
2571 if(old_schema) IXMLDOMSchemaCollection2_Release(old_schema);
2574 return hr;
2577 static inline BOOL is_wellformed(xmlDocPtr doc)
2579 #ifdef HAVE_XMLDOC_PROPERTIES
2580 return doc->properties & XML_DOC_WELLFORMED;
2581 #else
2582 /* Not a full check, but catches the worst violations */
2583 xmlNodePtr child;
2584 int root = 0;
2586 for (child = doc->children; child != NULL; child = child->next)
2588 switch (child->type)
2590 case XML_ELEMENT_NODE:
2591 if (++root > 1)
2592 return FALSE;
2593 break;
2594 case XML_TEXT_NODE:
2595 case XML_CDATA_SECTION_NODE:
2596 return FALSE;
2597 break;
2598 default:
2599 break;
2603 return root == 1;
2604 #endif
2607 static void LIBXML2_LOG_CALLBACK validate_error(void* ctx, char const* msg, ...)
2609 va_list ap;
2610 va_start(ap, msg);
2611 LIBXML2_CALLBACK_ERR(domdoc_validateNode, msg, ap);
2612 va_end(ap);
2615 static void LIBXML2_LOG_CALLBACK validate_warning(void* ctx, char const* msg, ...)
2617 va_list ap;
2618 va_start(ap, msg);
2619 LIBXML2_CALLBACK_WARN(domdoc_validateNode, msg, ap);
2620 va_end(ap);
2623 static HRESULT WINAPI domdoc_validateNode(
2624 IXMLDOMDocument3* iface,
2625 IXMLDOMNode* node,
2626 IXMLDOMParseError** err)
2628 domdoc* This = impl_from_IXMLDOMDocument3(iface);
2629 LONG state, err_code = 0;
2630 HRESULT hr = S_OK;
2631 int validated = 0;
2633 TRACE("(%p)->(%p, %p)\n", This, node, err);
2634 domdoc_get_readyState(iface, &state);
2635 if (state != READYSTATE_COMPLETE)
2637 if (err)
2638 *err = create_parseError(err_code, NULL, NULL, NULL, 0, 0, 0);
2639 return E_PENDING;
2642 if (!node)
2644 if (err)
2645 *err = create_parseError(err_code, NULL, NULL, NULL, 0, 0, 0);
2646 return E_POINTER;
2649 if (!get_node_obj(node)->node || get_node_obj(node)->node->doc != get_doc(This))
2651 if (err)
2652 *err = create_parseError(err_code, NULL, NULL, NULL, 0, 0, 0);
2653 return E_FAIL;
2656 if (!is_wellformed(get_doc(This)))
2658 ERR("doc not well-formed\n");
2659 if (err)
2660 *err = create_parseError(E_XML_NOTWF, NULL, NULL, NULL, 0, 0, 0);
2661 return S_FALSE;
2664 /* DTD validation */
2665 if (get_doc(This)->intSubset || get_doc(This)->extSubset)
2667 xmlValidCtxtPtr vctx = xmlNewValidCtxt();
2668 vctx->error = validate_error;
2669 vctx->warning = validate_warning;
2670 ++validated;
2672 if (!((node == (IXMLDOMNode*)iface)?
2673 xmlValidateDocument(vctx, get_doc(This)) :
2674 xmlValidateElement(vctx, get_doc(This), get_node_obj(node)->node)))
2676 /* TODO: get a real error code here */
2677 TRACE("DTD validation failed\n");
2678 err_code = E_XML_INVALID;
2679 hr = S_FALSE;
2681 xmlFreeValidCtxt(vctx);
2684 /* Schema validation */
2685 if (hr == S_OK && This->properties->schemaCache != NULL)
2688 hr = SchemaCache_validate_tree(This->properties->schemaCache, get_node_obj(node)->node);
2689 if (SUCCEEDED(hr))
2691 ++validated;
2692 /* TODO: get a real error code here */
2693 if (hr == S_OK)
2695 TRACE("schema validation succeeded\n");
2697 else
2699 ERR("schema validation failed\n");
2700 err_code = E_XML_INVALID;
2703 else
2705 /* not really OK, just didn't find a schema for the ns */
2706 hr = S_OK;
2710 if (!validated)
2712 ERR("no DTD or schema found\n");
2713 err_code = E_XML_NODTD;
2714 hr = S_FALSE;
2717 if (err)
2718 *err = create_parseError(err_code, NULL, NULL, NULL, 0, 0, 0);
2720 return hr;
2723 static HRESULT WINAPI domdoc_validate(
2724 IXMLDOMDocument3* iface,
2725 IXMLDOMParseError** err)
2727 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2728 TRACE("(%p)->(%p)\n", This, err);
2729 return domdoc_validateNode(iface, (IXMLDOMNode*)iface, err);
2732 static HRESULT WINAPI domdoc_setProperty(
2733 IXMLDOMDocument3* iface,
2734 BSTR p,
2735 VARIANT var)
2737 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2739 TRACE("(%p)->(%s)\n", This, debugstr_w(p));
2741 if (lstrcmpiW(p, PropertySelectionLanguageW) == 0)
2743 VARIANT varStr;
2744 HRESULT hr;
2745 BSTR bstr;
2747 V_VT(&varStr) = VT_EMPTY;
2748 if (V_VT(&var) != VT_BSTR)
2750 if (FAILED(hr = VariantChangeType(&varStr, &var, 0, VT_BSTR)))
2751 return hr;
2752 bstr = V_BSTR(&varStr);
2754 else
2755 bstr = V_BSTR(&var);
2757 hr = S_OK;
2758 if (lstrcmpiW(bstr, PropValueXPathW) == 0)
2759 This->properties->XPath = TRUE;
2760 else if (lstrcmpiW(bstr, PropValueXSLPatternW) == 0)
2761 This->properties->XPath = FALSE;
2762 else
2763 hr = E_FAIL;
2765 VariantClear(&varStr);
2766 return hr;
2768 else if (lstrcmpiW(p, PropertySelectionNamespacesW) == 0)
2770 xmlChar *nsStr = (xmlChar*)This->properties->selectNsStr;
2771 struct list *pNsList;
2772 VARIANT varStr;
2773 HRESULT hr;
2774 BSTR bstr;
2776 V_VT(&varStr) = VT_EMPTY;
2777 if (V_VT(&var) != VT_BSTR)
2779 if (FAILED(hr = VariantChangeType(&varStr, &var, 0, VT_BSTR)))
2780 return hr;
2781 bstr = V_BSTR(&varStr);
2783 else
2784 bstr = V_BSTR(&var);
2786 hr = S_OK;
2788 pNsList = &(This->properties->selectNsList);
2789 clear_selectNsList(pNsList);
2790 heap_free(nsStr);
2791 nsStr = xmlchar_from_wchar(bstr);
2793 TRACE("property value: \"%s\"\n", debugstr_w(bstr));
2795 This->properties->selectNsStr = nsStr;
2796 This->properties->selectNsStr_len = xmlStrlen(nsStr);
2797 if (bstr && *bstr)
2799 xmlChar *pTokBegin, *pTokEnd, *pTokInner;
2800 select_ns_entry* ns_entry = NULL;
2801 xmlXPathContextPtr ctx;
2803 ctx = xmlXPathNewContext(This->node.node->doc);
2804 pTokBegin = nsStr;
2806 /* skip leading spaces */
2807 while (*pTokBegin == ' ' || *pTokBegin == '\n' ||
2808 *pTokBegin == '\t' || *pTokBegin == '\r')
2809 ++pTokBegin;
2811 for (; *pTokBegin; pTokBegin = pTokEnd)
2813 if (ns_entry)
2814 memset(ns_entry, 0, sizeof(select_ns_entry));
2815 else
2816 ns_entry = heap_alloc_zero(sizeof(select_ns_entry));
2818 while (*pTokBegin == ' ')
2819 ++pTokBegin;
2820 pTokEnd = pTokBegin;
2821 while (*pTokEnd != ' ' && *pTokEnd != 0)
2822 ++pTokEnd;
2824 if (xmlStrncmp(pTokBegin, (xmlChar const*)"xmlns", 5) != 0)
2826 hr = E_FAIL;
2827 WARN("Syntax error in xmlns string: %s\n\tat token: %s\n",
2828 wine_dbgstr_w(bstr), wine_dbgstr_an((const char*)pTokBegin, pTokEnd-pTokBegin));
2829 continue;
2832 pTokBegin += 5;
2833 if (*pTokBegin == '=')
2835 /*valid for XSLPattern?*/
2836 FIXME("Setting default xmlns not supported - skipping.\n");
2837 continue;
2839 else if (*pTokBegin == ':')
2841 ns_entry->prefix = ++pTokBegin;
2842 for (pTokInner = pTokBegin; pTokInner != pTokEnd && *pTokInner != '='; ++pTokInner)
2845 if (pTokInner == pTokEnd)
2847 hr = E_FAIL;
2848 WARN("Syntax error in xmlns string: %s\n\tat token: %s\n",
2849 wine_dbgstr_w(bstr), wine_dbgstr_an((const char*)pTokBegin, pTokEnd-pTokBegin));
2850 continue;
2853 ns_entry->prefix_end = *pTokInner;
2854 *pTokInner = 0;
2855 ++pTokInner;
2857 if (pTokEnd-pTokInner > 1 &&
2858 ((*pTokInner == '\'' && *(pTokEnd-1) == '\'') ||
2859 (*pTokInner == '"' && *(pTokEnd-1) == '"')))
2861 ns_entry->href = ++pTokInner;
2862 ns_entry->href_end = *(pTokEnd-1);
2863 *(pTokEnd-1) = 0;
2864 list_add_tail(pNsList, &ns_entry->entry);
2865 /*let libxml figure out if they're valid from here ;)*/
2866 if (xmlXPathRegisterNs(ctx, ns_entry->prefix, ns_entry->href) != 0)
2868 hr = E_FAIL;
2870 ns_entry = NULL;
2871 continue;
2873 else
2875 WARN("Syntax error in xmlns string: %s\n\tat token: %s\n",
2876 wine_dbgstr_w(bstr), wine_dbgstr_an((const char*)pTokInner, pTokEnd-pTokInner));
2877 list_add_tail(pNsList, &ns_entry->entry);
2879 ns_entry = NULL;
2880 hr = E_FAIL;
2881 continue;
2884 else
2886 hr = E_FAIL;
2887 continue;
2890 heap_free(ns_entry);
2891 xmlXPathFreeContext(ctx);
2894 VariantClear(&varStr);
2895 return hr;
2897 else if (lstrcmpiW(p, PropertyProhibitDTDW) == 0 ||
2898 lstrcmpiW(p, PropertyNewParserW) == 0 ||
2899 lstrcmpiW(p, PropertyResolveExternalsW) == 0)
2901 /* Ignore */
2902 FIXME("Ignoring property %s, value %d\n", debugstr_w(p), V_BOOL(&var));
2903 return S_OK;
2906 FIXME("Unknown property %s\n", wine_dbgstr_w(p));
2907 return E_FAIL;
2910 static HRESULT WINAPI domdoc_getProperty(
2911 IXMLDOMDocument3* iface,
2912 BSTR p,
2913 VARIANT* var)
2915 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2917 TRACE("(%p)->(%p)\n", This, debugstr_w(p));
2919 if (!var)
2920 return E_INVALIDARG;
2922 if (lstrcmpiW(p, PropertySelectionLanguageW) == 0)
2924 V_VT(var) = VT_BSTR;
2925 V_BSTR(var) = This->properties->XPath ?
2926 SysAllocString(PropValueXPathW) :
2927 SysAllocString(PropValueXSLPatternW);
2928 return V_BSTR(var) ? S_OK : E_OUTOFMEMORY;
2930 else if (lstrcmpiW(p, PropertySelectionNamespacesW) == 0)
2932 int lenA, lenW;
2933 BSTR rebuiltStr, cur;
2934 const xmlChar *nsStr;
2935 struct list *pNsList;
2936 select_ns_entry* pNsEntry;
2938 V_VT(var) = VT_BSTR;
2939 nsStr = This->properties->selectNsStr;
2940 pNsList = &This->properties->selectNsList;
2941 lenA = This->properties->selectNsStr_len;
2942 lenW = MultiByteToWideChar(CP_UTF8, 0, (LPCSTR)nsStr, lenA+1, NULL, 0);
2943 rebuiltStr = heap_alloc(lenW*sizeof(WCHAR));
2944 MultiByteToWideChar(CP_UTF8, 0, (LPCSTR)nsStr, lenA+1, rebuiltStr, lenW);
2945 cur = rebuiltStr;
2946 /* this is fine because all of the chars that end tokens are ASCII*/
2947 LIST_FOR_EACH_ENTRY(pNsEntry, pNsList, select_ns_entry, entry)
2949 while (*cur != 0) ++cur;
2950 if (pNsEntry->prefix_end)
2952 *cur = pNsEntry->prefix_end;
2953 while (*cur != 0) ++cur;
2956 if (pNsEntry->href_end)
2958 *cur = pNsEntry->href_end;
2961 V_BSTR(var) = SysAllocString(rebuiltStr);
2962 heap_free(rebuiltStr);
2963 return S_OK;
2966 FIXME("Unknown property %s\n", wine_dbgstr_w(p));
2967 return E_FAIL;
2970 static HRESULT WINAPI domdoc_importNode(
2971 IXMLDOMDocument3* iface,
2972 IXMLDOMNode* node,
2973 VARIANT_BOOL deep,
2974 IXMLDOMNode** clone)
2976 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2977 FIXME("(%p)->(%p %d %p): stub\n", This, node, deep, clone);
2978 return E_NOTIMPL;
2981 static const struct IXMLDOMDocument3Vtbl XMLDOMDocument3Vtbl =
2983 domdoc_QueryInterface,
2984 domdoc_AddRef,
2985 domdoc_Release,
2986 domdoc_GetTypeInfoCount,
2987 domdoc_GetTypeInfo,
2988 domdoc_GetIDsOfNames,
2989 domdoc_Invoke,
2990 domdoc_get_nodeName,
2991 domdoc_get_nodeValue,
2992 domdoc_put_nodeValue,
2993 domdoc_get_nodeType,
2994 domdoc_get_parentNode,
2995 domdoc_get_childNodes,
2996 domdoc_get_firstChild,
2997 domdoc_get_lastChild,
2998 domdoc_get_previousSibling,
2999 domdoc_get_nextSibling,
3000 domdoc_get_attributes,
3001 domdoc_insertBefore,
3002 domdoc_replaceChild,
3003 domdoc_removeChild,
3004 domdoc_appendChild,
3005 domdoc_hasChildNodes,
3006 domdoc_get_ownerDocument,
3007 domdoc_cloneNode,
3008 domdoc_get_nodeTypeString,
3009 domdoc_get_text,
3010 domdoc_put_text,
3011 domdoc_get_specified,
3012 domdoc_get_definition,
3013 domdoc_get_nodeTypedValue,
3014 domdoc_put_nodeTypedValue,
3015 domdoc_get_dataType,
3016 domdoc_put_dataType,
3017 domdoc_get_xml,
3018 domdoc_transformNode,
3019 domdoc_selectNodes,
3020 domdoc_selectSingleNode,
3021 domdoc_get_parsed,
3022 domdoc_get_namespaceURI,
3023 domdoc_get_prefix,
3024 domdoc_get_baseName,
3025 domdoc_transformNodeToObject,
3026 domdoc_get_doctype,
3027 domdoc_get_implementation,
3028 domdoc_get_documentElement,
3029 domdoc_put_documentElement,
3030 domdoc_createElement,
3031 domdoc_createDocumentFragment,
3032 domdoc_createTextNode,
3033 domdoc_createComment,
3034 domdoc_createCDATASection,
3035 domdoc_createProcessingInstruction,
3036 domdoc_createAttribute,
3037 domdoc_createEntityReference,
3038 domdoc_getElementsByTagName,
3039 domdoc_createNode,
3040 domdoc_nodeFromID,
3041 domdoc_load,
3042 domdoc_get_readyState,
3043 domdoc_get_parseError,
3044 domdoc_get_url,
3045 domdoc_get_async,
3046 domdoc_put_async,
3047 domdoc_abort,
3048 domdoc_loadXML,
3049 domdoc_save,
3050 domdoc_get_validateOnParse,
3051 domdoc_put_validateOnParse,
3052 domdoc_get_resolveExternals,
3053 domdoc_put_resolveExternals,
3054 domdoc_get_preserveWhiteSpace,
3055 domdoc_put_preserveWhiteSpace,
3056 domdoc_put_onreadystatechange,
3057 domdoc_put_onDataAvailable,
3058 domdoc_put_onTransformNode,
3059 domdoc_get_namespaces,
3060 domdoc_get_schemas,
3061 domdoc_putref_schemas,
3062 domdoc_validate,
3063 domdoc_setProperty,
3064 domdoc_getProperty,
3065 domdoc_validateNode,
3066 domdoc_importNode
3069 /* IConnectionPointContainer */
3070 static HRESULT WINAPI ConnectionPointContainer_QueryInterface(IConnectionPointContainer *iface,
3071 REFIID riid, void **ppv)
3073 domdoc *This = impl_from_IConnectionPointContainer(iface);
3074 return IXMLDOMDocument3_QueryInterface(&This->IXMLDOMDocument3_iface, riid, ppv);
3077 static ULONG WINAPI ConnectionPointContainer_AddRef(IConnectionPointContainer *iface)
3079 domdoc *This = impl_from_IConnectionPointContainer(iface);
3080 return IXMLDOMDocument3_AddRef(&This->IXMLDOMDocument3_iface);
3083 static ULONG WINAPI ConnectionPointContainer_Release(IConnectionPointContainer *iface)
3085 domdoc *This = impl_from_IConnectionPointContainer(iface);
3086 return IXMLDOMDocument3_Release(&This->IXMLDOMDocument3_iface);
3089 static HRESULT WINAPI ConnectionPointContainer_EnumConnectionPoints(IConnectionPointContainer *iface,
3090 IEnumConnectionPoints **ppEnum)
3092 domdoc *This = impl_from_IConnectionPointContainer(iface);
3093 FIXME("(%p)->(%p): stub\n", This, ppEnum);
3094 return E_NOTIMPL;
3097 static HRESULT WINAPI ConnectionPointContainer_FindConnectionPoint(IConnectionPointContainer *iface,
3098 REFIID riid, IConnectionPoint **cp)
3100 domdoc *This = impl_from_IConnectionPointContainer(iface);
3101 ConnectionPoint *iter;
3103 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), cp);
3105 *cp = NULL;
3107 for(iter = This->cp_list; iter; iter = iter->next)
3109 if (IsEqualGUID(iter->iid, riid))
3110 *cp = &iter->IConnectionPoint_iface;
3113 if (*cp)
3115 IConnectionPoint_AddRef(*cp);
3116 return S_OK;
3119 FIXME("unsupported riid %s\n", debugstr_guid(riid));
3120 return CONNECT_E_NOCONNECTION;
3124 static const struct IConnectionPointContainerVtbl ConnectionPointContainerVtbl =
3126 ConnectionPointContainer_QueryInterface,
3127 ConnectionPointContainer_AddRef,
3128 ConnectionPointContainer_Release,
3129 ConnectionPointContainer_EnumConnectionPoints,
3130 ConnectionPointContainer_FindConnectionPoint
3133 /* IConnectionPoint */
3134 static HRESULT WINAPI ConnectionPoint_QueryInterface(IConnectionPoint *iface,
3135 REFIID riid, void **ppv)
3137 ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3139 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv );
3141 *ppv = NULL;
3143 if (IsEqualGUID(&IID_IUnknown, riid) ||
3144 IsEqualGUID(&IID_IConnectionPoint, riid))
3146 *ppv = iface;
3149 if (*ppv)
3151 IConnectionPoint_AddRef(iface);
3152 return S_OK;
3155 WARN("Unsupported interface %s\n", debugstr_guid(riid));
3156 return E_NOINTERFACE;
3159 static ULONG WINAPI ConnectionPoint_AddRef(IConnectionPoint *iface)
3161 ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3162 return IConnectionPointContainer_AddRef(This->container);
3165 static ULONG WINAPI ConnectionPoint_Release(IConnectionPoint *iface)
3167 ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3168 return IConnectionPointContainer_Release(This->container);
3171 static HRESULT WINAPI ConnectionPoint_GetConnectionInterface(IConnectionPoint *iface, IID *iid)
3173 ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3175 TRACE("(%p)->(%p)\n", This, iid);
3177 if (!iid) return E_POINTER;
3179 *iid = *This->iid;
3180 return S_OK;
3183 static HRESULT WINAPI ConnectionPoint_GetConnectionPointContainer(IConnectionPoint *iface,
3184 IConnectionPointContainer **container)
3186 ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3188 TRACE("(%p)->(%p)\n", This, container);
3190 if (!container) return E_POINTER;
3192 *container = This->container;
3193 IConnectionPointContainer_AddRef(*container);
3194 return S_OK;
3197 static HRESULT WINAPI ConnectionPoint_Advise(IConnectionPoint *iface, IUnknown *pUnkSink,
3198 DWORD *pdwCookie)
3200 ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3201 FIXME("(%p)->(%p %p): stub\n", This, pUnkSink, pdwCookie);
3202 return E_NOTIMPL;
3205 static HRESULT WINAPI ConnectionPoint_Unadvise(IConnectionPoint *iface, DWORD cookie)
3207 ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3209 TRACE("(%p)->(%d)\n", This, cookie);
3211 if (cookie == 0 || cookie > This->sinks_size || !This->sinks[cookie-1].unk)
3212 return CONNECT_E_NOCONNECTION;
3214 IUnknown_Release(This->sinks[cookie-1].unk);
3215 This->sinks[cookie-1].unk = NULL;
3217 return S_OK;
3220 static HRESULT WINAPI ConnectionPoint_EnumConnections(IConnectionPoint *iface,
3221 IEnumConnections **ppEnum)
3223 ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3224 FIXME("(%p)->(%p): stub\n", This, ppEnum);
3225 return E_NOTIMPL;
3228 static const IConnectionPointVtbl ConnectionPointVtbl =
3230 ConnectionPoint_QueryInterface,
3231 ConnectionPoint_AddRef,
3232 ConnectionPoint_Release,
3233 ConnectionPoint_GetConnectionInterface,
3234 ConnectionPoint_GetConnectionPointContainer,
3235 ConnectionPoint_Advise,
3236 ConnectionPoint_Unadvise,
3237 ConnectionPoint_EnumConnections
3240 static void ConnectionPoint_Init(ConnectionPoint *cp, struct domdoc *doc, REFIID riid)
3242 cp->IConnectionPoint_iface.lpVtbl = &ConnectionPointVtbl;
3243 cp->doc = doc;
3244 cp->iid = riid;
3245 cp->sinks = NULL;
3246 cp->sinks_size = 0;
3248 cp->next = doc->cp_list;
3249 doc->cp_list = cp;
3251 cp->container = &doc->IConnectionPointContainer_iface;
3254 /* domdoc implementation of IObjectWithSite */
3255 static HRESULT WINAPI
3256 domdoc_ObjectWithSite_QueryInterface( IObjectWithSite* iface, REFIID riid, void** ppvObject )
3258 domdoc *This = impl_from_IObjectWithSite(iface);
3259 return IXMLDOMDocument3_QueryInterface(&This->IXMLDOMDocument3_iface, riid, ppvObject);
3262 static ULONG WINAPI domdoc_ObjectWithSite_AddRef( IObjectWithSite* iface )
3264 domdoc *This = impl_from_IObjectWithSite(iface);
3265 return IXMLDOMDocument3_AddRef(&This->IXMLDOMDocument3_iface);
3268 static ULONG WINAPI domdoc_ObjectWithSite_Release( IObjectWithSite* iface )
3270 domdoc *This = impl_from_IObjectWithSite(iface);
3271 return IXMLDOMDocument3_Release(&This->IXMLDOMDocument3_iface);
3274 static HRESULT WINAPI domdoc_ObjectWithSite_GetSite( IObjectWithSite *iface, REFIID iid, void **ppvSite )
3276 domdoc *This = impl_from_IObjectWithSite(iface);
3278 TRACE("(%p)->(%s %p)\n", This, debugstr_guid( iid ), ppvSite );
3280 if ( !This->site )
3281 return E_FAIL;
3283 return IUnknown_QueryInterface( This->site, iid, ppvSite );
3286 static HRESULT WINAPI domdoc_ObjectWithSite_SetSite( IObjectWithSite *iface, IUnknown *punk )
3288 domdoc *This = impl_from_IObjectWithSite(iface);
3290 TRACE("(%p)->(%p)\n", iface, punk);
3292 if(!punk)
3294 if(This->site)
3296 IUnknown_Release( This->site );
3297 This->site = NULL;
3300 return S_OK;
3303 IUnknown_AddRef( punk );
3305 if(This->site)
3306 IUnknown_Release( This->site );
3308 This->site = punk;
3310 return S_OK;
3313 static const IObjectWithSiteVtbl domdocObjectSite =
3315 domdoc_ObjectWithSite_QueryInterface,
3316 domdoc_ObjectWithSite_AddRef,
3317 domdoc_ObjectWithSite_Release,
3318 domdoc_ObjectWithSite_SetSite,
3319 domdoc_ObjectWithSite_GetSite
3322 static HRESULT WINAPI domdoc_Safety_QueryInterface(IObjectSafety *iface, REFIID riid, void **ppv)
3324 domdoc *This = impl_from_IObjectSafety(iface);
3325 return IXMLDOMDocument3_QueryInterface(&This->IXMLDOMDocument3_iface, riid, ppv);
3328 static ULONG WINAPI domdoc_Safety_AddRef(IObjectSafety *iface)
3330 domdoc *This = impl_from_IObjectSafety(iface);
3331 return IXMLDOMDocument3_AddRef(&This->IXMLDOMDocument3_iface);
3334 static ULONG WINAPI domdoc_Safety_Release(IObjectSafety *iface)
3336 domdoc *This = impl_from_IObjectSafety(iface);
3337 return IXMLDOMDocument3_Release(&This->IXMLDOMDocument3_iface);
3340 #define SAFETY_SUPPORTED_OPTIONS (INTERFACESAFE_FOR_UNTRUSTED_CALLER|INTERFACESAFE_FOR_UNTRUSTED_DATA|INTERFACE_USES_SECURITY_MANAGER)
3342 static HRESULT WINAPI domdoc_Safety_GetInterfaceSafetyOptions(IObjectSafety *iface, REFIID riid,
3343 DWORD *supported, DWORD *enabled)
3345 domdoc *This = impl_from_IObjectSafety(iface);
3347 TRACE("(%p)->(%s %p %p)\n", This, debugstr_guid(riid), supported, enabled);
3349 if(!supported || !enabled) return E_POINTER;
3351 *supported = SAFETY_SUPPORTED_OPTIONS;
3352 *enabled = This->safeopt;
3354 return S_OK;
3357 static HRESULT WINAPI domdoc_Safety_SetInterfaceSafetyOptions(IObjectSafety *iface, REFIID riid,
3358 DWORD mask, DWORD enabled)
3360 domdoc *This = impl_from_IObjectSafety(iface);
3361 TRACE("(%p)->(%s %x %x)\n", This, debugstr_guid(riid), mask, enabled);
3363 if ((mask & ~SAFETY_SUPPORTED_OPTIONS) != 0)
3364 return E_FAIL;
3366 This->safeopt = (This->safeopt & ~mask) | (mask & enabled);
3368 return S_OK;
3371 #undef SAFETY_SUPPORTED_OPTIONS
3373 static const IObjectSafetyVtbl domdocObjectSafetyVtbl = {
3374 domdoc_Safety_QueryInterface,
3375 domdoc_Safety_AddRef,
3376 domdoc_Safety_Release,
3377 domdoc_Safety_GetInterfaceSafetyOptions,
3378 domdoc_Safety_SetInterfaceSafetyOptions
3381 static const tid_t domdoc_iface_tids[] = {
3382 IXMLDOMDocument3_tid,
3386 static dispex_static_data_t domdoc_dispex = {
3387 NULL,
3388 IXMLDOMDocument3_tid,
3389 NULL,
3390 domdoc_iface_tids
3393 HRESULT get_domdoc_from_xmldoc(xmlDocPtr xmldoc, IXMLDOMDocument3 **document)
3395 domdoc *doc;
3397 doc = heap_alloc( sizeof (*doc) );
3398 if( !doc )
3399 return E_OUTOFMEMORY;
3401 doc->IXMLDOMDocument3_iface.lpVtbl = &XMLDOMDocument3Vtbl;
3402 doc->IPersistStreamInit_iface.lpVtbl = &xmldoc_IPersistStreamInit_VTable;
3403 doc->IObjectWithSite_iface.lpVtbl = &domdocObjectSite;
3404 doc->IObjectSafety_iface.lpVtbl = &domdocObjectSafetyVtbl;
3405 doc->IConnectionPointContainer_iface.lpVtbl = &ConnectionPointContainerVtbl;
3406 doc->ref = 1;
3407 doc->async = VARIANT_TRUE;
3408 doc->validating = 0;
3409 doc->resolving = 0;
3410 doc->properties = properties_from_xmlDocPtr(xmldoc);
3411 doc->error = S_OK;
3412 doc->stream = NULL;
3413 doc->site = NULL;
3414 doc->safeopt = 0;
3415 doc->bsc = NULL;
3416 doc->cp_list = NULL;
3417 memset(doc->events, 0, sizeof(doc->events));
3419 /* events connection points */
3420 ConnectionPoint_Init(&doc->cp_dispatch, doc, &IID_IDispatch);
3421 ConnectionPoint_Init(&doc->cp_propnotif, doc, &IID_IPropertyNotifySink);
3422 ConnectionPoint_Init(&doc->cp_domdocevents, doc, &DIID_XMLDOMDocumentEvents);
3424 init_xmlnode(&doc->node, (xmlNodePtr)xmldoc, (IXMLDOMNode*)&doc->IXMLDOMDocument3_iface,
3425 &domdoc_dispex);
3427 *document = &doc->IXMLDOMDocument3_iface;
3429 TRACE("returning iface %p\n", *document);
3430 return S_OK;
3433 HRESULT DOMDocument_create(MSXML_VERSION version, IUnknown *pUnkOuter, void **ppObj)
3435 xmlDocPtr xmldoc;
3436 HRESULT hr;
3438 TRACE("(%d, %p, %p)\n", version, pUnkOuter, ppObj);
3440 xmldoc = xmlNewDoc(NULL);
3441 if(!xmldoc)
3442 return E_OUTOFMEMORY;
3444 xmldoc->_private = create_priv();
3445 priv_from_xmlDocPtr(xmldoc)->properties = create_properties(version);
3447 hr = get_domdoc_from_xmldoc(xmldoc, (IXMLDOMDocument3**)ppObj);
3448 if(FAILED(hr))
3450 free_properties(properties_from_xmlDocPtr(xmldoc));
3451 heap_free(xmldoc->_private);
3452 xmlFreeDoc(xmldoc);
3453 return hr;
3456 return hr;
3459 IUnknown* create_domdoc( xmlNodePtr document )
3461 void* pObj = NULL;
3462 HRESULT hr;
3464 TRACE("(%p)\n", document);
3466 hr = get_domdoc_from_xmldoc((xmlDocPtr)document, (IXMLDOMDocument3**)&pObj);
3467 if (FAILED(hr))
3468 return NULL;
3470 return pObj;
3473 #else
3475 HRESULT DOMDocument_create(MSXML_VERSION version, IUnknown *pUnkOuter, void **ppObj)
3477 MESSAGE("This program tried to use a DOMDocument object, but\n"
3478 "libxml2 support was not present at compile time.\n");
3479 return E_NOTIMPL;
3482 #endif