wininet: Avoid calling HTTP_ReceiveRequestData before reading headers.
[wine/multimedia.git] / dlls / msxml3 / domdoc.c
blob4640e62940a3023977f7db17f7bdcf45b03c8d4c
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 _domdoc_properties {
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;
1373 static HRESULT WINAPI domdoc_get_namespaceURI(
1374 IXMLDOMDocument3 *iface,
1375 BSTR* namespaceURI )
1377 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1378 TRACE("(%p)->(%p)\n", This, namespaceURI);
1379 return node_get_namespaceURI(&This->node, namespaceURI);
1383 static HRESULT WINAPI domdoc_get_prefix(
1384 IXMLDOMDocument3 *iface,
1385 BSTR* prefix )
1387 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1388 TRACE("(%p)->(%p)\n", This, prefix);
1389 return return_null_bstr( prefix );
1393 static HRESULT WINAPI domdoc_get_baseName(
1394 IXMLDOMDocument3 *iface,
1395 BSTR* name )
1397 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1398 TRACE("(%p)->(%p)\n", This, name);
1399 return return_null_bstr( name );
1403 static HRESULT WINAPI domdoc_transformNodeToObject(
1404 IXMLDOMDocument3 *iface,
1405 IXMLDOMNode* stylesheet,
1406 VARIANT outputObject)
1408 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1409 FIXME("(%p)->(%p %s)\n", This, stylesheet, debugstr_variant(&outputObject));
1410 return E_NOTIMPL;
1414 static HRESULT WINAPI domdoc_get_doctype(
1415 IXMLDOMDocument3 *iface,
1416 IXMLDOMDocumentType** doctype )
1418 domdoc *This = impl_from_IXMLDOMDocument3(iface);
1419 IXMLDOMNode *node;
1420 xmlDtdPtr dtd;
1421 HRESULT hr;
1423 TRACE("(%p)->(%p)\n", This, doctype);
1425 if (!doctype) return E_INVALIDARG;
1427 *doctype = NULL;
1429 dtd = xmlGetIntSubset(get_doc(This));
1430 if (!dtd) return S_FALSE;
1432 node = create_node((xmlNodePtr)dtd);
1433 if (!node) return S_FALSE;
1435 hr = IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMDocumentType, (void**)doctype);
1436 IXMLDOMNode_Release(node);
1438 return hr;
1442 static HRESULT WINAPI domdoc_get_implementation(
1443 IXMLDOMDocument3 *iface,
1444 IXMLDOMImplementation** impl )
1446 domdoc *This = impl_from_IXMLDOMDocument3(iface);
1448 TRACE("(%p)->(%p)\n", This, impl);
1450 if(!impl)
1451 return E_INVALIDARG;
1453 *impl = (IXMLDOMImplementation*)create_doc_Implementation();
1455 return S_OK;
1458 static HRESULT WINAPI domdoc_get_documentElement(
1459 IXMLDOMDocument3 *iface,
1460 IXMLDOMElement** DOMElement )
1462 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1463 IXMLDOMNode *element_node;
1464 xmlNodePtr root;
1465 HRESULT hr;
1467 TRACE("(%p)->(%p)\n", This, DOMElement);
1469 if(!DOMElement)
1470 return E_INVALIDARG;
1472 *DOMElement = NULL;
1474 root = xmlDocGetRootElement( get_doc(This) );
1475 if ( !root )
1476 return S_FALSE;
1478 element_node = create_node( root );
1479 if(!element_node) return S_FALSE;
1481 hr = IXMLDOMNode_QueryInterface(element_node, &IID_IXMLDOMElement, (void**)DOMElement);
1482 IXMLDOMNode_Release(element_node);
1484 return hr;
1488 static HRESULT WINAPI domdoc_put_documentElement(
1489 IXMLDOMDocument3 *iface,
1490 IXMLDOMElement* DOMElement )
1492 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1493 IXMLDOMNode *elementNode;
1494 xmlNodePtr oldRoot;
1495 xmlnode *xmlNode;
1496 HRESULT hr;
1498 TRACE("(%p)->(%p)\n", This, DOMElement);
1500 hr = IXMLDOMElement_QueryInterface( DOMElement, &IID_IXMLDOMNode, (void**)&elementNode );
1501 if(FAILED(hr))
1502 return hr;
1504 xmlNode = get_node_obj( elementNode );
1505 if(!xmlNode) return E_FAIL;
1507 if(!xmlNode->node->parent)
1508 if(xmldoc_remove_orphan(xmlNode->node->doc, xmlNode->node) != S_OK)
1509 WARN("%p is not an orphan of %p\n", xmlNode->node->doc, xmlNode->node);
1511 oldRoot = xmlDocSetRootElement( get_doc(This), xmlNode->node);
1512 IXMLDOMNode_Release( elementNode );
1514 if(oldRoot)
1515 xmldoc_add_orphan(oldRoot->doc, oldRoot);
1517 return S_OK;
1521 static HRESULT WINAPI domdoc_createElement(
1522 IXMLDOMDocument3 *iface,
1523 BSTR tagname,
1524 IXMLDOMElement** element )
1526 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1527 IXMLDOMNode *node;
1528 VARIANT type;
1529 HRESULT hr;
1531 TRACE("(%p)->(%s %p)\n", This, debugstr_w(tagname), element);
1533 if (!element || !tagname) return E_INVALIDARG;
1535 V_VT(&type) = VT_I1;
1536 V_I1(&type) = NODE_ELEMENT;
1538 hr = IXMLDOMDocument3_createNode(iface, type, tagname, NULL, &node);
1539 if (hr == S_OK)
1541 IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMElement, (void**)element);
1542 IXMLDOMNode_Release(node);
1545 return hr;
1549 static HRESULT WINAPI domdoc_createDocumentFragment(
1550 IXMLDOMDocument3 *iface,
1551 IXMLDOMDocumentFragment** frag )
1553 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1554 IXMLDOMNode *node;
1555 VARIANT type;
1556 HRESULT hr;
1558 TRACE("(%p)->(%p)\n", This, frag);
1560 if (!frag) return E_INVALIDARG;
1562 *frag = NULL;
1564 V_VT(&type) = VT_I1;
1565 V_I1(&type) = NODE_DOCUMENT_FRAGMENT;
1567 hr = IXMLDOMDocument3_createNode(iface, type, NULL, NULL, &node);
1568 if (hr == S_OK)
1570 IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMDocumentFragment, (void**)frag);
1571 IXMLDOMNode_Release(node);
1574 return hr;
1578 static HRESULT WINAPI domdoc_createTextNode(
1579 IXMLDOMDocument3 *iface,
1580 BSTR data,
1581 IXMLDOMText** text )
1583 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1584 IXMLDOMNode *node;
1585 VARIANT type;
1586 HRESULT hr;
1588 TRACE("(%p)->(%s %p)\n", This, debugstr_w(data), text);
1590 if (!text) return E_INVALIDARG;
1592 *text = NULL;
1594 V_VT(&type) = VT_I1;
1595 V_I1(&type) = NODE_TEXT;
1597 hr = IXMLDOMDocument3_createNode(iface, type, NULL, NULL, &node);
1598 if (hr == S_OK)
1600 IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMText, (void**)text);
1601 IXMLDOMNode_Release(node);
1602 hr = IXMLDOMText_put_data(*text, data);
1605 return hr;
1609 static HRESULT WINAPI domdoc_createComment(
1610 IXMLDOMDocument3 *iface,
1611 BSTR data,
1612 IXMLDOMComment** comment )
1614 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1615 VARIANT type;
1616 HRESULT hr;
1617 IXMLDOMNode *node;
1619 TRACE("(%p)->(%s %p)\n", This, debugstr_w(data), comment);
1621 if (!comment) return E_INVALIDARG;
1623 *comment = NULL;
1625 V_VT(&type) = VT_I1;
1626 V_I1(&type) = NODE_COMMENT;
1628 hr = IXMLDOMDocument3_createNode(iface, type, NULL, NULL, &node);
1629 if (hr == S_OK)
1631 IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMComment, (void**)comment);
1632 IXMLDOMNode_Release(node);
1633 hr = IXMLDOMComment_put_data(*comment, data);
1636 return hr;
1640 static HRESULT WINAPI domdoc_createCDATASection(
1641 IXMLDOMDocument3 *iface,
1642 BSTR data,
1643 IXMLDOMCDATASection** cdata )
1645 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1646 IXMLDOMNode *node;
1647 VARIANT type;
1648 HRESULT hr;
1650 TRACE("(%p)->(%s %p)\n", This, debugstr_w(data), cdata);
1652 if (!cdata) return E_INVALIDARG;
1654 *cdata = NULL;
1656 V_VT(&type) = VT_I1;
1657 V_I1(&type) = NODE_CDATA_SECTION;
1659 hr = IXMLDOMDocument3_createNode(iface, type, NULL, NULL, &node);
1660 if (hr == S_OK)
1662 IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMCDATASection, (void**)cdata);
1663 IXMLDOMNode_Release(node);
1664 hr = IXMLDOMCDATASection_put_data(*cdata, data);
1667 return hr;
1671 static HRESULT WINAPI domdoc_createProcessingInstruction(
1672 IXMLDOMDocument3 *iface,
1673 BSTR target,
1674 BSTR data,
1675 IXMLDOMProcessingInstruction** pi )
1677 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1678 IXMLDOMNode *node;
1679 VARIANT type;
1680 HRESULT hr;
1682 TRACE("(%p)->(%s %s %p)\n", This, debugstr_w(target), debugstr_w(data), pi);
1684 if (!pi) return E_INVALIDARG;
1686 *pi = NULL;
1688 V_VT(&type) = VT_I1;
1689 V_I1(&type) = NODE_PROCESSING_INSTRUCTION;
1691 hr = IXMLDOMDocument3_createNode(iface, type, target, NULL, &node);
1692 if (hr == S_OK)
1694 xmlnode *node_obj;
1696 /* this is to bypass check in ::put_data() that blocks "<?xml" PIs */
1697 node_obj = get_node_obj(node);
1698 hr = node_set_content(node_obj, data);
1700 IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMProcessingInstruction, (void**)pi);
1701 IXMLDOMNode_Release(node);
1704 return hr;
1708 static HRESULT WINAPI domdoc_createAttribute(
1709 IXMLDOMDocument3 *iface,
1710 BSTR name,
1711 IXMLDOMAttribute** attribute )
1713 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1714 IXMLDOMNode *node;
1715 VARIANT type;
1716 HRESULT hr;
1718 TRACE("(%p)->(%s %p)\n", This, debugstr_w(name), attribute);
1720 if (!attribute || !name) return E_INVALIDARG;
1722 V_VT(&type) = VT_I1;
1723 V_I1(&type) = NODE_ATTRIBUTE;
1725 hr = IXMLDOMDocument3_createNode(iface, type, name, NULL, &node);
1726 if (hr == S_OK)
1728 IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMAttribute, (void**)attribute);
1729 IXMLDOMNode_Release(node);
1732 return hr;
1736 static HRESULT WINAPI domdoc_createEntityReference(
1737 IXMLDOMDocument3 *iface,
1738 BSTR name,
1739 IXMLDOMEntityReference** entityref )
1741 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1742 IXMLDOMNode *node;
1743 VARIANT type;
1744 HRESULT hr;
1746 TRACE("(%p)->(%s %p)\n", This, debugstr_w(name), entityref);
1748 if (!entityref) return E_INVALIDARG;
1750 *entityref = NULL;
1752 V_VT(&type) = VT_I1;
1753 V_I1(&type) = NODE_ENTITY_REFERENCE;
1755 hr = IXMLDOMDocument3_createNode(iface, type, name, NULL, &node);
1756 if (hr == S_OK)
1758 IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMEntityReference, (void**)entityref);
1759 IXMLDOMNode_Release(node);
1762 return hr;
1765 xmlChar* tagName_to_XPath(const BSTR tagName)
1767 xmlChar *query, *tmp;
1768 static const xmlChar mod_pre[] = "*[local-name()='";
1769 static const xmlChar mod_post[] = "']";
1770 static const xmlChar prefix[] = "descendant::";
1771 const WCHAR *tokBegin, *tokEnd;
1772 int len;
1774 query = xmlStrdup(prefix);
1776 tokBegin = tagName;
1777 while (tokBegin && *tokBegin)
1779 switch (*tokBegin)
1781 case '/':
1782 query = xmlStrcat(query, BAD_CAST "/");
1783 ++tokBegin;
1784 break;
1785 case '*':
1786 query = xmlStrcat(query, BAD_CAST "*");
1787 ++tokBegin;
1788 break;
1789 default:
1790 query = xmlStrcat(query, mod_pre);
1791 tokEnd = tokBegin;
1792 while (*tokEnd && *tokEnd != '/')
1793 ++tokEnd;
1794 len = WideCharToMultiByte(CP_UTF8, 0, tokBegin, tokEnd-tokBegin, NULL, 0, NULL, NULL);
1795 tmp = xmlMalloc(len);
1796 WideCharToMultiByte(CP_UTF8, 0, tokBegin, tokEnd-tokBegin, (char*)tmp, len, NULL, NULL);
1797 query = xmlStrncat(query, tmp, len);
1798 xmlFree(tmp);
1799 tokBegin = tokEnd;
1800 query = xmlStrcat(query, mod_post);
1804 return query;
1807 static HRESULT WINAPI domdoc_getElementsByTagName(
1808 IXMLDOMDocument3 *iface,
1809 BSTR tagName,
1810 IXMLDOMNodeList** resultList )
1812 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1813 xmlChar *query;
1814 HRESULT hr;
1815 BOOL XPath;
1817 TRACE("(%p)->(%s, %p)\n", This, debugstr_w(tagName), resultList);
1819 if (!tagName || !resultList) return E_INVALIDARG;
1821 XPath = This->properties->XPath;
1822 This->properties->XPath = TRUE;
1823 query = tagName_to_XPath(tagName);
1824 hr = create_selection((xmlNodePtr)get_doc(This), query, resultList);
1825 xmlFree(query);
1826 This->properties->XPath = XPath;
1828 return hr;
1831 static HRESULT get_node_type(VARIANT Type, DOMNodeType * type)
1833 VARIANT tmp;
1834 HRESULT hr;
1836 VariantInit(&tmp);
1837 hr = VariantChangeType(&tmp, &Type, 0, VT_I4);
1838 if(FAILED(hr))
1839 return E_INVALIDARG;
1841 *type = V_I4(&tmp);
1843 return S_OK;
1846 static HRESULT WINAPI domdoc_createNode(
1847 IXMLDOMDocument3 *iface,
1848 VARIANT Type,
1849 BSTR name,
1850 BSTR namespaceURI,
1851 IXMLDOMNode** node )
1853 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1854 DOMNodeType node_type;
1855 xmlNodePtr xmlnode;
1856 xmlChar *xml_name, *href;
1857 HRESULT hr;
1859 TRACE("(%p)->(%s %s %p)\n", This, debugstr_w(name), debugstr_w(namespaceURI), node);
1861 if(!node) return E_INVALIDARG;
1863 hr = get_node_type(Type, &node_type);
1864 if(FAILED(hr)) return hr;
1866 if(namespaceURI && namespaceURI[0] && node_type != NODE_ELEMENT)
1867 FIXME("nodes with namespaces currently not supported.\n");
1869 TRACE("node_type %d\n", node_type);
1871 /* exit earlier for types that need name */
1872 switch(node_type)
1874 case NODE_ELEMENT:
1875 case NODE_ATTRIBUTE:
1876 case NODE_ENTITY_REFERENCE:
1877 case NODE_PROCESSING_INSTRUCTION:
1878 if (!name || *name == 0) return E_FAIL;
1879 break;
1880 default:
1881 break;
1884 xml_name = xmlchar_from_wchar(name);
1885 /* prevent empty href to be allocated */
1886 href = namespaceURI ? xmlchar_from_wchar(namespaceURI) : NULL;
1888 switch(node_type)
1890 case NODE_ELEMENT:
1892 xmlChar *local, *prefix;
1894 local = xmlSplitQName2(xml_name, &prefix);
1896 xmlnode = xmlNewDocNode(get_doc(This), NULL, local ? local : xml_name, NULL);
1898 /* allow to create default namespace xmlns= */
1899 if (local || (href && *href))
1901 xmlNsPtr ns = xmlNewNs(xmlnode, href, prefix);
1902 xmlSetNs(xmlnode, ns);
1905 xmlFree(local);
1906 xmlFree(prefix);
1908 break;
1910 case NODE_ATTRIBUTE:
1911 xmlnode = (xmlNodePtr)xmlNewDocProp(get_doc(This), xml_name, NULL);
1912 break;
1913 case NODE_TEXT:
1914 xmlnode = (xmlNodePtr)xmlNewDocText(get_doc(This), NULL);
1915 break;
1916 case NODE_CDATA_SECTION:
1917 xmlnode = xmlNewCDataBlock(get_doc(This), NULL, 0);
1918 break;
1919 case NODE_ENTITY_REFERENCE:
1920 xmlnode = xmlNewReference(get_doc(This), xml_name);
1921 break;
1922 case NODE_PROCESSING_INSTRUCTION:
1923 #ifdef HAVE_XMLNEWDOCPI
1924 xmlnode = xmlNewDocPI(get_doc(This), xml_name, NULL);
1925 #else
1926 FIXME("xmlNewDocPI() not supported, use libxml2 2.6.15 or greater\n");
1927 xmlnode = NULL;
1928 #endif
1929 break;
1930 case NODE_COMMENT:
1931 xmlnode = xmlNewDocComment(get_doc(This), NULL);
1932 break;
1933 case NODE_DOCUMENT_FRAGMENT:
1934 xmlnode = xmlNewDocFragment(get_doc(This));
1935 break;
1936 /* unsupported types */
1937 case NODE_DOCUMENT:
1938 case NODE_DOCUMENT_TYPE:
1939 case NODE_ENTITY:
1940 case NODE_NOTATION:
1941 heap_free(xml_name);
1942 return E_INVALIDARG;
1943 default:
1944 FIXME("unhandled node type %d\n", node_type);
1945 xmlnode = NULL;
1946 break;
1949 *node = create_node(xmlnode);
1950 heap_free(xml_name);
1951 heap_free(href);
1953 if(*node)
1955 TRACE("created node (%d, %p, %p)\n", node_type, *node, xmlnode);
1956 xmldoc_add_orphan(xmlnode->doc, xmlnode);
1957 return S_OK;
1960 return E_FAIL;
1963 static HRESULT WINAPI domdoc_nodeFromID(
1964 IXMLDOMDocument3 *iface,
1965 BSTR idString,
1966 IXMLDOMNode** node )
1968 domdoc *This = impl_from_IXMLDOMDocument3(iface);
1969 FIXME("(%p)->(%s %p)\n", This, debugstr_w(idString), node);
1970 return E_NOTIMPL;
1973 static HRESULT domdoc_onDataAvailable(void *obj, char *ptr, DWORD len)
1975 domdoc *This = obj;
1976 xmlDocPtr xmldoc;
1978 xmldoc = doparse(This, ptr, len, XML_CHAR_ENCODING_NONE);
1979 if(xmldoc) {
1980 xmldoc->_private = create_priv();
1981 return attach_xmldoc(This, xmldoc);
1984 return S_OK;
1987 static HRESULT doread( domdoc *This, LPWSTR filename )
1989 bsc_t *bsc;
1990 HRESULT hr;
1992 hr = bind_url(filename, domdoc_onDataAvailable, This, &bsc);
1993 if(FAILED(hr))
1994 return hr;
1996 if(This->bsc) {
1997 hr = detach_bsc(This->bsc);
1998 if(FAILED(hr))
1999 return hr;
2002 This->bsc = bsc;
2003 return S_OK;
2006 static HRESULT WINAPI domdoc_load(
2007 IXMLDOMDocument3 *iface,
2008 VARIANT source,
2009 VARIANT_BOOL* isSuccessful )
2011 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2012 LPWSTR filename = NULL;
2013 HRESULT hr = S_FALSE;
2014 IXMLDOMDocument3 *pNewDoc = NULL;
2015 IStream *pStream = NULL;
2016 xmlDocPtr xmldoc;
2018 TRACE("(%p)->(%s)\n", This, debugstr_variant(&source));
2020 if (!isSuccessful)
2021 return E_POINTER;
2022 *isSuccessful = VARIANT_FALSE;
2024 assert( &This->node );
2026 switch( V_VT(&source) )
2028 case VT_BSTR:
2029 filename = V_BSTR(&source);
2030 break;
2031 case VT_BSTR|VT_BYREF:
2032 if (!V_BSTRREF(&source)) return E_INVALIDARG;
2033 filename = *V_BSTRREF(&source);
2034 break;
2035 case VT_ARRAY|VT_UI1:
2037 SAFEARRAY *psa = V_ARRAY(&source);
2038 char *str;
2039 LONG len;
2040 UINT dim = SafeArrayGetDim(psa);
2042 switch (dim)
2044 case 0:
2045 ERR("SAFEARRAY == NULL\n");
2046 hr = This->error = E_INVALIDARG;
2047 break;
2048 case 1:
2049 /* Only takes UTF-8 strings.
2050 * NOT NULL-terminated. */
2051 SafeArrayAccessData(psa, (void**)&str);
2052 SafeArrayGetUBound(psa, 1, &len);
2054 if ((xmldoc = doparse(This, str, ++len, XML_CHAR_ENCODING_UTF8)))
2056 hr = This->error = S_OK;
2057 *isSuccessful = VARIANT_TRUE;
2058 TRACE("parsed document %p\n", xmldoc);
2060 else
2062 This->error = E_FAIL;
2063 TRACE("failed to parse document\n");
2066 SafeArrayUnaccessData(psa);
2068 if(xmldoc)
2070 xmldoc->_private = create_priv();
2071 return attach_xmldoc(This, xmldoc);
2073 break;
2074 default:
2075 FIXME("unhandled SAFEARRAY dim: %d\n", dim);
2076 hr = This->error = E_NOTIMPL;
2079 break;
2080 case VT_UNKNOWN:
2081 hr = IUnknown_QueryInterface(V_UNKNOWN(&source), &IID_IXMLDOMDocument3, (void**)&pNewDoc);
2082 if(hr == S_OK)
2084 if(pNewDoc)
2086 domdoc *newDoc = impl_from_IXMLDOMDocument3( pNewDoc );
2087 xmldoc = xmlCopyDoc(get_doc(newDoc), 1);
2088 hr = attach_xmldoc(This, xmldoc);
2090 if(SUCCEEDED(hr))
2091 *isSuccessful = VARIANT_TRUE;
2093 return hr;
2096 hr = IUnknown_QueryInterface(V_UNKNOWN(&source), &IID_IStream, (void**)&pStream);
2097 if(hr == S_OK)
2099 IPersistStream *pDocStream;
2100 hr = IUnknown_QueryInterface(iface, &IID_IPersistStream, (void**)&pDocStream);
2101 if(hr == S_OK)
2103 hr = IPersistStream_Load(pDocStream, pStream);
2104 IStream_Release(pStream);
2105 if(hr == S_OK)
2107 *isSuccessful = VARIANT_TRUE;
2109 TRACE("Using IStream to load Document\n");
2110 return S_OK;
2112 else
2114 ERR("xmldoc_IPersistStream_Load failed (%d)\n", hr);
2117 else
2119 ERR("QueryInterface IID_IPersistStream failed (%d)\n", hr);
2122 else
2124 /* ISequentialStream */
2125 FIXME("Unknown type not supported (%d) (%p)(%p)\n", hr, pNewDoc, V_UNKNOWN(&source)->lpVtbl);
2127 break;
2128 default:
2129 FIXME("VT type not supported (%d)\n", V_VT(&source));
2132 if ( filename )
2134 hr = doread( This, filename );
2136 if ( FAILED(hr) )
2137 This->error = E_FAIL;
2138 else
2140 hr = This->error = S_OK;
2141 *isSuccessful = VARIANT_TRUE;
2145 if(!filename || FAILED(hr)) {
2146 xmldoc = xmlNewDoc(NULL);
2147 xmldoc->_private = create_priv();
2148 hr = attach_xmldoc(This, xmldoc);
2149 if(SUCCEEDED(hr))
2150 hr = S_FALSE;
2153 TRACE("ret (%d)\n", hr);
2155 return hr;
2159 static HRESULT WINAPI domdoc_get_readyState(
2160 IXMLDOMDocument3 *iface,
2161 LONG *value )
2163 domdoc *This = impl_from_IXMLDOMDocument3(iface);
2164 FIXME("stub! (%p)->(%p)\n", This, value);
2166 if (!value)
2167 return E_INVALIDARG;
2169 *value = READYSTATE_COMPLETE;
2170 return S_OK;
2174 static HRESULT WINAPI domdoc_get_parseError(
2175 IXMLDOMDocument3 *iface,
2176 IXMLDOMParseError** errorObj )
2178 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2179 static const WCHAR err[] = {'e','r','r','o','r',0};
2180 BSTR error_string = NULL;
2182 FIXME("(%p)->(%p): creating a dummy parseError\n", iface, errorObj);
2184 if(This->error)
2185 error_string = SysAllocString(err);
2187 *errorObj = create_parseError(This->error, NULL, error_string, NULL, 0, 0, 0);
2188 if(!*errorObj) return E_OUTOFMEMORY;
2189 return S_OK;
2193 static HRESULT WINAPI domdoc_get_url(
2194 IXMLDOMDocument3 *iface,
2195 BSTR* urlString )
2197 domdoc *This = impl_from_IXMLDOMDocument3(iface);
2198 FIXME("(%p)->(%p)\n", This, urlString);
2199 return E_NOTIMPL;
2203 static HRESULT WINAPI domdoc_get_async(
2204 IXMLDOMDocument3 *iface,
2205 VARIANT_BOOL* isAsync )
2207 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2209 TRACE("(%p)->(%p: %d)\n", This, isAsync, This->async);
2210 *isAsync = This->async;
2211 return S_OK;
2215 static HRESULT WINAPI domdoc_put_async(
2216 IXMLDOMDocument3 *iface,
2217 VARIANT_BOOL isAsync )
2219 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2221 TRACE("(%p)->(%d)\n", This, isAsync);
2222 This->async = isAsync;
2223 return S_OK;
2227 static HRESULT WINAPI domdoc_abort(
2228 IXMLDOMDocument3 *iface )
2230 domdoc *This = impl_from_IXMLDOMDocument3(iface);
2231 FIXME("%p\n", This);
2232 return E_NOTIMPL;
2236 /* don't rely on data to be in BSTR format, treat it as WCHAR string */
2237 static HRESULT WINAPI domdoc_loadXML(
2238 IXMLDOMDocument3 *iface,
2239 BSTR bstrXML,
2240 VARIANT_BOOL* isSuccessful )
2242 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2243 xmlDocPtr xmldoc = NULL;
2244 HRESULT hr = S_FALSE, hr2;
2246 TRACE("(%p)->(%s %p)\n", This, debugstr_w( bstrXML ), isSuccessful );
2248 assert ( &This->node );
2250 if ( isSuccessful )
2252 *isSuccessful = VARIANT_FALSE;
2254 if ( bstrXML )
2256 xmldoc = doparse(This, (LPCSTR)bstrXML, lstrlenW(bstrXML) * sizeof(*bstrXML), XML_CHAR_ENCODING_UTF16LE);
2257 if ( !xmldoc )
2259 This->error = E_FAIL;
2260 TRACE("failed to parse document\n");
2262 else
2264 hr = This->error = S_OK;
2265 *isSuccessful = VARIANT_TRUE;
2266 TRACE("parsed document %p\n", xmldoc);
2270 if(!xmldoc)
2271 xmldoc = xmlNewDoc(NULL);
2273 xmldoc->_private = create_priv();
2275 hr2 = attach_xmldoc(This, xmldoc);
2276 if( FAILED(hr2) )
2277 hr = hr2;
2279 return hr;
2282 static int XMLCALL domdoc_save_writecallback(void *ctx, const char *buffer, int len)
2284 DWORD written = -1;
2286 if(!WriteFile(ctx, buffer, len, &written, NULL))
2288 WARN("write error\n");
2289 return -1;
2291 else
2292 return written;
2295 static int XMLCALL domdoc_save_closecallback(void *ctx)
2297 return CloseHandle(ctx) ? 0 : -1;
2300 static int XMLCALL domdoc_stream_save_writecallback(void *ctx, const char *buffer, int len)
2302 ULONG written = 0;
2303 HRESULT hr;
2305 hr = IStream_Write((IStream*)ctx, buffer, len, &written);
2306 if (hr != S_OK)
2308 WARN("stream write error: 0x%08x\n", hr);
2309 return -1;
2311 else
2312 return written;
2315 static int XMLCALL domdoc_stream_save_closecallback(void *ctx)
2317 IStream_Release((IStream*)ctx);
2318 return 0;
2321 static HRESULT WINAPI domdoc_save(
2322 IXMLDOMDocument3 *iface,
2323 VARIANT destination )
2325 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2326 xmlSaveCtxtPtr ctx = NULL;
2327 xmlNodePtr xmldecl;
2328 HRESULT ret = S_OK;
2330 TRACE("(%p)->(%s)\n", This, debugstr_variant(&destination));
2332 switch (V_VT(&destination))
2334 case VT_UNKNOWN:
2336 IUnknown *pUnk = V_UNKNOWN(&destination);
2337 IXMLDOMDocument3 *document;
2338 IStream *stream;
2340 ret = IUnknown_QueryInterface(pUnk, &IID_IXMLDOMDocument3, (void**)&document);
2341 if(ret == S_OK)
2343 VARIANT_BOOL success;
2344 BSTR xml;
2346 ret = IXMLDOMDocument3_get_xml(iface, &xml);
2347 if(ret == S_OK)
2349 ret = IXMLDOMDocument3_loadXML(document, xml, &success);
2350 SysFreeString(xml);
2353 IXMLDOMDocument3_Release(document);
2354 return ret;
2357 ret = IUnknown_QueryInterface(pUnk, &IID_IStream, (void**)&stream);
2358 if(ret == S_OK)
2360 ctx = xmlSaveToIO(domdoc_stream_save_writecallback,
2361 domdoc_stream_save_closecallback, stream, NULL, XML_SAVE_NO_DECL);
2363 if(!ctx)
2365 IStream_Release(stream);
2366 return E_FAIL;
2370 break;
2372 case VT_BSTR:
2373 case VT_BSTR | VT_BYREF:
2375 /* save with file path */
2376 HANDLE handle = CreateFileW( (V_VT(&destination) & VT_BYREF)? *V_BSTRREF(&destination) : V_BSTR(&destination),
2377 GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL );
2378 if( handle == INVALID_HANDLE_VALUE )
2380 WARN("failed to create file\n");
2381 return E_FAIL;
2384 /* disable top XML declaration */
2385 ctx = xmlSaveToIO(domdoc_save_writecallback, domdoc_save_closecallback,
2386 handle, NULL, XML_SAVE_NO_DECL);
2387 if (!ctx)
2389 CloseHandle(handle);
2390 return E_FAIL;
2393 break;
2395 default:
2396 FIXME("Unhandled VARIANT: %s\n", debugstr_variant(&destination));
2397 return S_FALSE;
2400 xmldecl = xmldoc_unlink_xmldecl(get_doc(This));
2401 if (xmlSaveDoc(ctx, get_doc(This)) == -1) ret = S_FALSE;
2402 xmldoc_link_xmldecl(get_doc(This), xmldecl);
2404 /* will release resources through close callback */
2405 xmlSaveClose(ctx);
2407 return ret;
2410 static HRESULT WINAPI domdoc_get_validateOnParse(
2411 IXMLDOMDocument3 *iface,
2412 VARIANT_BOOL* isValidating )
2414 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2415 TRACE("(%p)->(%p: %d)\n", This, isValidating, This->validating);
2416 *isValidating = This->validating;
2417 return S_OK;
2421 static HRESULT WINAPI domdoc_put_validateOnParse(
2422 IXMLDOMDocument3 *iface,
2423 VARIANT_BOOL isValidating )
2425 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2426 TRACE("(%p)->(%d)\n", This, isValidating);
2427 This->validating = isValidating;
2428 return S_OK;
2432 static HRESULT WINAPI domdoc_get_resolveExternals(
2433 IXMLDOMDocument3 *iface,
2434 VARIANT_BOOL* isResolving )
2436 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2437 TRACE("(%p)->(%p: %d)\n", This, isResolving, This->resolving);
2438 *isResolving = This->resolving;
2439 return S_OK;
2443 static HRESULT WINAPI domdoc_put_resolveExternals(
2444 IXMLDOMDocument3 *iface,
2445 VARIANT_BOOL isResolving )
2447 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2448 TRACE("(%p)->(%d)\n", This, isResolving);
2449 This->resolving = isResolving;
2450 return S_OK;
2454 static HRESULT WINAPI domdoc_get_preserveWhiteSpace(
2455 IXMLDOMDocument3 *iface,
2456 VARIANT_BOOL* isPreserving )
2458 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2459 TRACE("(%p)->(%p: %d)\n", This, isPreserving, This->properties->preserving);
2460 *isPreserving = This->properties->preserving;
2461 return S_OK;
2465 static HRESULT WINAPI domdoc_put_preserveWhiteSpace(
2466 IXMLDOMDocument3 *iface,
2467 VARIANT_BOOL isPreserving )
2469 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2470 TRACE("(%p)->(%d)\n", This, isPreserving);
2471 This->properties->preserving = isPreserving;
2472 return S_OK;
2476 static HRESULT WINAPI domdoc_put_onreadystatechange(
2477 IXMLDOMDocument3 *iface,
2478 VARIANT event )
2480 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2482 TRACE("(%p)->(%s)\n", This, debugstr_variant(&event));
2483 return set_doc_event(This, EVENTID_READYSTATECHANGE, &event);
2487 static HRESULT WINAPI domdoc_put_onDataAvailable(
2488 IXMLDOMDocument3 *iface,
2489 VARIANT onDataAvailableSink )
2491 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2492 FIXME("%p\n", This);
2493 return E_NOTIMPL;
2496 static HRESULT WINAPI domdoc_put_onTransformNode(
2497 IXMLDOMDocument3 *iface,
2498 VARIANT onTransformNodeSink )
2500 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2501 FIXME("%p\n", This);
2502 return E_NOTIMPL;
2505 static HRESULT WINAPI domdoc_get_namespaces(
2506 IXMLDOMDocument3* iface,
2507 IXMLDOMSchemaCollection** schemaCollection )
2509 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2510 FIXME("(%p)->(%p)\n", This, schemaCollection);
2511 return E_NOTIMPL;
2514 static HRESULT WINAPI domdoc_get_schemas(
2515 IXMLDOMDocument3* iface,
2516 VARIANT* var1 )
2518 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2519 HRESULT hr = S_FALSE;
2520 IXMLDOMSchemaCollection2* cur_schema = This->properties->schemaCache;
2522 TRACE("(%p)->(%p)\n", This, var1);
2524 VariantInit(var1); /* Test shows we don't call VariantClear here */
2525 V_VT(var1) = VT_NULL;
2527 if(cur_schema)
2529 hr = IXMLDOMSchemaCollection2_QueryInterface(cur_schema, &IID_IDispatch, (void**)&V_DISPATCH(var1));
2530 if(SUCCEEDED(hr))
2531 V_VT(var1) = VT_DISPATCH;
2533 return hr;
2536 static HRESULT WINAPI domdoc_putref_schemas(
2537 IXMLDOMDocument3* iface,
2538 VARIANT var1)
2540 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2541 HRESULT hr = E_FAIL;
2542 IXMLDOMSchemaCollection2* new_schema = NULL;
2544 FIXME("(%p): semi-stub\n", This);
2545 switch(V_VT(&var1))
2547 case VT_UNKNOWN:
2548 hr = IUnknown_QueryInterface(V_UNKNOWN(&var1), &IID_IXMLDOMSchemaCollection, (void**)&new_schema);
2549 break;
2551 case VT_DISPATCH:
2552 hr = IDispatch_QueryInterface(V_DISPATCH(&var1), &IID_IXMLDOMSchemaCollection, (void**)&new_schema);
2553 break;
2555 case VT_NULL:
2556 case VT_EMPTY:
2557 hr = S_OK;
2558 break;
2560 default:
2561 WARN("Can't get schema from vt %x\n", V_VT(&var1));
2564 if(SUCCEEDED(hr))
2566 IXMLDOMSchemaCollection2* old_schema = InterlockedExchangePointer((void**)&This->properties->schemaCache, new_schema);
2567 if(old_schema) IXMLDOMSchemaCollection2_Release(old_schema);
2570 return hr;
2573 static inline BOOL is_wellformed(xmlDocPtr doc)
2575 #ifdef HAVE_XMLDOC_PROPERTIES
2576 return doc->properties & XML_DOC_WELLFORMED;
2577 #else
2578 /* Not a full check, but catches the worst violations */
2579 xmlNodePtr child;
2580 int root = 0;
2582 for (child = doc->children; child != NULL; child = child->next)
2584 switch (child->type)
2586 case XML_ELEMENT_NODE:
2587 if (++root > 1)
2588 return FALSE;
2589 break;
2590 case XML_TEXT_NODE:
2591 case XML_CDATA_SECTION_NODE:
2592 return FALSE;
2593 break;
2594 default:
2595 break;
2599 return root == 1;
2600 #endif
2603 static void LIBXML2_LOG_CALLBACK validate_error(void* ctx, char const* msg, ...)
2605 va_list ap;
2606 va_start(ap, msg);
2607 LIBXML2_CALLBACK_ERR(domdoc_validateNode, msg, ap);
2608 va_end(ap);
2611 static void LIBXML2_LOG_CALLBACK validate_warning(void* ctx, char const* msg, ...)
2613 va_list ap;
2614 va_start(ap, msg);
2615 LIBXML2_CALLBACK_WARN(domdoc_validateNode, msg, ap);
2616 va_end(ap);
2619 static HRESULT WINAPI domdoc_validateNode(
2620 IXMLDOMDocument3* iface,
2621 IXMLDOMNode* node,
2622 IXMLDOMParseError** err)
2624 domdoc* This = impl_from_IXMLDOMDocument3(iface);
2625 LONG state, err_code = 0;
2626 HRESULT hr = S_OK;
2627 int validated = 0;
2629 TRACE("(%p)->(%p, %p)\n", This, node, err);
2630 domdoc_get_readyState(iface, &state);
2631 if (state != READYSTATE_COMPLETE)
2633 if (err)
2634 *err = create_parseError(err_code, NULL, NULL, NULL, 0, 0, 0);
2635 return E_PENDING;
2638 if (!node)
2640 if (err)
2641 *err = create_parseError(err_code, NULL, NULL, NULL, 0, 0, 0);
2642 return E_POINTER;
2645 if (!get_node_obj(node)->node || get_node_obj(node)->node->doc != get_doc(This))
2647 if (err)
2648 *err = create_parseError(err_code, NULL, NULL, NULL, 0, 0, 0);
2649 return E_FAIL;
2652 if (!is_wellformed(get_doc(This)))
2654 ERR("doc not well-formed\n");
2655 if (err)
2656 *err = create_parseError(E_XML_NOTWF, NULL, NULL, NULL, 0, 0, 0);
2657 return S_FALSE;
2660 /* DTD validation */
2661 if (get_doc(This)->intSubset || get_doc(This)->extSubset)
2663 xmlValidCtxtPtr vctx = xmlNewValidCtxt();
2664 vctx->error = validate_error;
2665 vctx->warning = validate_warning;
2666 ++validated;
2668 if (!((node == (IXMLDOMNode*)iface)?
2669 xmlValidateDocument(vctx, get_doc(This)) :
2670 xmlValidateElement(vctx, get_doc(This), get_node_obj(node)->node)))
2672 /* TODO: get a real error code here */
2673 TRACE("DTD validation failed\n");
2674 err_code = E_XML_INVALID;
2675 hr = S_FALSE;
2677 xmlFreeValidCtxt(vctx);
2680 /* Schema validation */
2681 if (hr == S_OK && This->properties->schemaCache != NULL)
2684 hr = SchemaCache_validate_tree(This->properties->schemaCache, get_node_obj(node)->node);
2685 if (SUCCEEDED(hr))
2687 ++validated;
2688 /* TODO: get a real error code here */
2689 if (hr == S_OK)
2691 TRACE("schema validation succeeded\n");
2693 else
2695 ERR("schema validation failed\n");
2696 err_code = E_XML_INVALID;
2699 else
2701 /* not really OK, just didn't find a schema for the ns */
2702 hr = S_OK;
2706 if (!validated)
2708 ERR("no DTD or schema found\n");
2709 err_code = E_XML_NODTD;
2710 hr = S_FALSE;
2713 if (err)
2714 *err = create_parseError(err_code, NULL, NULL, NULL, 0, 0, 0);
2716 return hr;
2719 static HRESULT WINAPI domdoc_validate(
2720 IXMLDOMDocument3* iface,
2721 IXMLDOMParseError** err)
2723 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2724 TRACE("(%p)->(%p)\n", This, err);
2725 return domdoc_validateNode(iface, (IXMLDOMNode*)iface, err);
2728 static HRESULT WINAPI domdoc_setProperty(
2729 IXMLDOMDocument3* iface,
2730 BSTR p,
2731 VARIANT var)
2733 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2735 TRACE("(%p)->(%s)\n", This, debugstr_w(p));
2737 if (lstrcmpiW(p, PropertySelectionLanguageW) == 0)
2739 VARIANT varStr;
2740 HRESULT hr;
2741 BSTR bstr;
2743 V_VT(&varStr) = VT_EMPTY;
2744 if (V_VT(&var) != VT_BSTR)
2746 if (FAILED(hr = VariantChangeType(&varStr, &var, 0, VT_BSTR)))
2747 return hr;
2748 bstr = V_BSTR(&varStr);
2750 else
2751 bstr = V_BSTR(&var);
2753 hr = S_OK;
2754 if (lstrcmpiW(bstr, PropValueXPathW) == 0)
2755 This->properties->XPath = TRUE;
2756 else if (lstrcmpiW(bstr, PropValueXSLPatternW) == 0)
2757 This->properties->XPath = FALSE;
2758 else
2759 hr = E_FAIL;
2761 VariantClear(&varStr);
2762 return hr;
2764 else if (lstrcmpiW(p, PropertySelectionNamespacesW) == 0)
2766 VARIANT varStr;
2767 HRESULT hr;
2768 BSTR bstr;
2769 xmlChar *pTokBegin, *pTokEnd, *pTokInner;
2770 xmlChar *nsStr = (xmlChar*)This->properties->selectNsStr;
2771 xmlXPathContextPtr ctx;
2772 struct list *pNsList;
2773 select_ns_entry* pNsEntry = NULL;
2775 V_VT(&varStr) = VT_EMPTY;
2776 if (V_VT(&var) != VT_BSTR)
2778 if (FAILED(hr = VariantChangeType(&varStr, &var, 0, VT_BSTR)))
2779 return hr;
2780 bstr = V_BSTR(&varStr);
2782 else
2783 bstr = V_BSTR(&var);
2785 hr = S_OK;
2787 pNsList = &(This->properties->selectNsList);
2788 clear_selectNsList(pNsList);
2789 heap_free(nsStr);
2790 nsStr = xmlchar_from_wchar(bstr);
2792 TRACE("Setting SelectionNamespaces property to: %s\n", nsStr);
2794 This->properties->selectNsStr = nsStr;
2795 This->properties->selectNsStr_len = xmlStrlen(nsStr);
2796 if (bstr && *bstr)
2798 ctx = xmlXPathNewContext(This->node.node->doc);
2799 pTokBegin = nsStr;
2800 for (; *pTokBegin; pTokBegin = pTokEnd)
2802 if (pNsEntry != NULL)
2803 memset(pNsEntry, 0, sizeof(select_ns_entry));
2804 else
2805 pNsEntry = heap_alloc_zero(sizeof(select_ns_entry));
2807 while (*pTokBegin == ' ')
2808 ++pTokBegin;
2809 pTokEnd = pTokBegin;
2810 while (*pTokEnd != ' ' && *pTokEnd != 0)
2811 ++pTokEnd;
2813 if (xmlStrncmp(pTokBegin, (xmlChar const*)"xmlns", 5) != 0)
2815 hr = E_FAIL;
2816 WARN("Syntax error in xmlns string: %s\n\tat token: %s\n",
2817 wine_dbgstr_w(bstr), wine_dbgstr_an((const char*)pTokBegin, pTokEnd-pTokBegin));
2818 continue;
2821 pTokBegin += 5;
2822 if (*pTokBegin == '=')
2824 /*valid for XSLPattern?*/
2825 FIXME("Setting default xmlns not supported - skipping.\n");
2826 continue;
2828 else if (*pTokBegin == ':')
2830 pNsEntry->prefix = ++pTokBegin;
2831 for (pTokInner = pTokBegin; pTokInner != pTokEnd && *pTokInner != '='; ++pTokInner)
2834 if (pTokInner == pTokEnd)
2836 hr = E_FAIL;
2837 WARN("Syntax error in xmlns string: %s\n\tat token: %s\n",
2838 wine_dbgstr_w(bstr), wine_dbgstr_an((const char*)pTokBegin, pTokEnd-pTokBegin));
2839 continue;
2842 pNsEntry->prefix_end = *pTokInner;
2843 *pTokInner = 0;
2844 ++pTokInner;
2846 if (pTokEnd-pTokInner > 1 &&
2847 ((*pTokInner == '\'' && *(pTokEnd-1) == '\'') ||
2848 (*pTokInner == '"' && *(pTokEnd-1) == '"')))
2850 pNsEntry->href = ++pTokInner;
2851 pNsEntry->href_end = *(pTokEnd-1);
2852 *(pTokEnd-1) = 0;
2853 list_add_tail(pNsList, &pNsEntry->entry);
2854 /*let libxml figure out if they're valid from here ;)*/
2855 if (xmlXPathRegisterNs(ctx, pNsEntry->prefix, pNsEntry->href) != 0)
2857 hr = E_FAIL;
2859 pNsEntry = NULL;
2860 continue;
2862 else
2864 WARN("Syntax error in xmlns string: %s\n\tat token: %s\n",
2865 wine_dbgstr_w(bstr), wine_dbgstr_an((const char*)pTokInner, pTokEnd-pTokInner));
2866 list_add_tail(pNsList, &pNsEntry->entry);
2868 pNsEntry = NULL;
2869 hr = E_FAIL;
2870 continue;
2873 else
2875 hr = E_FAIL;
2876 continue;
2879 heap_free(pNsEntry);
2880 xmlXPathFreeContext(ctx);
2883 VariantClear(&varStr);
2884 return hr;
2886 else if (lstrcmpiW(p, PropertyProhibitDTDW) == 0 ||
2887 lstrcmpiW(p, PropertyNewParserW) == 0 ||
2888 lstrcmpiW(p, PropertyResolveExternalsW) == 0)
2890 /* Ignore */
2891 FIXME("Ignoring property %s, value %d\n", debugstr_w(p), V_BOOL(&var));
2892 return S_OK;
2895 FIXME("Unknown property %s\n", wine_dbgstr_w(p));
2896 return E_FAIL;
2899 static HRESULT WINAPI domdoc_getProperty(
2900 IXMLDOMDocument3* iface,
2901 BSTR p,
2902 VARIANT* var)
2904 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2906 TRACE("(%p)->(%p)\n", This, debugstr_w(p));
2908 if (!var)
2909 return E_INVALIDARG;
2911 if (lstrcmpiW(p, PropertySelectionLanguageW) == 0)
2913 V_VT(var) = VT_BSTR;
2914 V_BSTR(var) = This->properties->XPath ?
2915 SysAllocString(PropValueXPathW) :
2916 SysAllocString(PropValueXSLPatternW);
2917 return V_BSTR(var) ? S_OK : E_OUTOFMEMORY;
2919 else if (lstrcmpiW(p, PropertySelectionNamespacesW) == 0)
2921 int lenA, lenW;
2922 BSTR rebuiltStr, cur;
2923 const xmlChar *nsStr;
2924 struct list *pNsList;
2925 select_ns_entry* pNsEntry;
2927 V_VT(var) = VT_BSTR;
2928 nsStr = This->properties->selectNsStr;
2929 pNsList = &This->properties->selectNsList;
2930 lenA = This->properties->selectNsStr_len;
2931 lenW = MultiByteToWideChar(CP_UTF8, 0, (LPCSTR)nsStr, lenA+1, NULL, 0);
2932 rebuiltStr = heap_alloc(lenW*sizeof(WCHAR));
2933 MultiByteToWideChar(CP_UTF8, 0, (LPCSTR)nsStr, lenA+1, rebuiltStr, lenW);
2934 cur = rebuiltStr;
2935 /* this is fine because all of the chars that end tokens are ASCII*/
2936 LIST_FOR_EACH_ENTRY(pNsEntry, pNsList, select_ns_entry, entry)
2938 while (*cur != 0) ++cur;
2939 if (pNsEntry->prefix_end)
2941 *cur = pNsEntry->prefix_end;
2942 while (*cur != 0) ++cur;
2945 if (pNsEntry->href_end)
2947 *cur = pNsEntry->href_end;
2950 V_BSTR(var) = SysAllocString(rebuiltStr);
2951 heap_free(rebuiltStr);
2952 return S_OK;
2955 FIXME("Unknown property %s\n", wine_dbgstr_w(p));
2956 return E_FAIL;
2959 static HRESULT WINAPI domdoc_importNode(
2960 IXMLDOMDocument3* iface,
2961 IXMLDOMNode* node,
2962 VARIANT_BOOL deep,
2963 IXMLDOMNode** clone)
2965 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2966 FIXME("(%p)->(%p %d %p): stub\n", This, node, deep, clone);
2967 return E_NOTIMPL;
2970 static const struct IXMLDOMDocument3Vtbl XMLDOMDocument3Vtbl =
2972 domdoc_QueryInterface,
2973 domdoc_AddRef,
2974 domdoc_Release,
2975 domdoc_GetTypeInfoCount,
2976 domdoc_GetTypeInfo,
2977 domdoc_GetIDsOfNames,
2978 domdoc_Invoke,
2979 domdoc_get_nodeName,
2980 domdoc_get_nodeValue,
2981 domdoc_put_nodeValue,
2982 domdoc_get_nodeType,
2983 domdoc_get_parentNode,
2984 domdoc_get_childNodes,
2985 domdoc_get_firstChild,
2986 domdoc_get_lastChild,
2987 domdoc_get_previousSibling,
2988 domdoc_get_nextSibling,
2989 domdoc_get_attributes,
2990 domdoc_insertBefore,
2991 domdoc_replaceChild,
2992 domdoc_removeChild,
2993 domdoc_appendChild,
2994 domdoc_hasChildNodes,
2995 domdoc_get_ownerDocument,
2996 domdoc_cloneNode,
2997 domdoc_get_nodeTypeString,
2998 domdoc_get_text,
2999 domdoc_put_text,
3000 domdoc_get_specified,
3001 domdoc_get_definition,
3002 domdoc_get_nodeTypedValue,
3003 domdoc_put_nodeTypedValue,
3004 domdoc_get_dataType,
3005 domdoc_put_dataType,
3006 domdoc_get_xml,
3007 domdoc_transformNode,
3008 domdoc_selectNodes,
3009 domdoc_selectSingleNode,
3010 domdoc_get_parsed,
3011 domdoc_get_namespaceURI,
3012 domdoc_get_prefix,
3013 domdoc_get_baseName,
3014 domdoc_transformNodeToObject,
3015 domdoc_get_doctype,
3016 domdoc_get_implementation,
3017 domdoc_get_documentElement,
3018 domdoc_put_documentElement,
3019 domdoc_createElement,
3020 domdoc_createDocumentFragment,
3021 domdoc_createTextNode,
3022 domdoc_createComment,
3023 domdoc_createCDATASection,
3024 domdoc_createProcessingInstruction,
3025 domdoc_createAttribute,
3026 domdoc_createEntityReference,
3027 domdoc_getElementsByTagName,
3028 domdoc_createNode,
3029 domdoc_nodeFromID,
3030 domdoc_load,
3031 domdoc_get_readyState,
3032 domdoc_get_parseError,
3033 domdoc_get_url,
3034 domdoc_get_async,
3035 domdoc_put_async,
3036 domdoc_abort,
3037 domdoc_loadXML,
3038 domdoc_save,
3039 domdoc_get_validateOnParse,
3040 domdoc_put_validateOnParse,
3041 domdoc_get_resolveExternals,
3042 domdoc_put_resolveExternals,
3043 domdoc_get_preserveWhiteSpace,
3044 domdoc_put_preserveWhiteSpace,
3045 domdoc_put_onreadystatechange,
3046 domdoc_put_onDataAvailable,
3047 domdoc_put_onTransformNode,
3048 domdoc_get_namespaces,
3049 domdoc_get_schemas,
3050 domdoc_putref_schemas,
3051 domdoc_validate,
3052 domdoc_setProperty,
3053 domdoc_getProperty,
3054 domdoc_validateNode,
3055 domdoc_importNode
3058 /* IConnectionPointContainer */
3059 static HRESULT WINAPI ConnectionPointContainer_QueryInterface(IConnectionPointContainer *iface,
3060 REFIID riid, void **ppv)
3062 domdoc *This = impl_from_IConnectionPointContainer(iface);
3063 return IXMLDOMDocument3_QueryInterface(&This->IXMLDOMDocument3_iface, riid, ppv);
3066 static ULONG WINAPI ConnectionPointContainer_AddRef(IConnectionPointContainer *iface)
3068 domdoc *This = impl_from_IConnectionPointContainer(iface);
3069 return IXMLDOMDocument3_AddRef(&This->IXMLDOMDocument3_iface);
3072 static ULONG WINAPI ConnectionPointContainer_Release(IConnectionPointContainer *iface)
3074 domdoc *This = impl_from_IConnectionPointContainer(iface);
3075 return IXMLDOMDocument3_Release(&This->IXMLDOMDocument3_iface);
3078 static HRESULT WINAPI ConnectionPointContainer_EnumConnectionPoints(IConnectionPointContainer *iface,
3079 IEnumConnectionPoints **ppEnum)
3081 domdoc *This = impl_from_IConnectionPointContainer(iface);
3082 FIXME("(%p)->(%p): stub\n", This, ppEnum);
3083 return E_NOTIMPL;
3086 static HRESULT WINAPI ConnectionPointContainer_FindConnectionPoint(IConnectionPointContainer *iface,
3087 REFIID riid, IConnectionPoint **cp)
3089 domdoc *This = impl_from_IConnectionPointContainer(iface);
3090 ConnectionPoint *iter;
3092 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), cp);
3094 *cp = NULL;
3096 for(iter = This->cp_list; iter; iter = iter->next)
3098 if (IsEqualGUID(iter->iid, riid))
3099 *cp = &iter->IConnectionPoint_iface;
3102 if (*cp)
3104 IConnectionPoint_AddRef(*cp);
3105 return S_OK;
3108 FIXME("unsupported riid %s\n", debugstr_guid(riid));
3109 return CONNECT_E_NOCONNECTION;
3113 static const struct IConnectionPointContainerVtbl ConnectionPointContainerVtbl =
3115 ConnectionPointContainer_QueryInterface,
3116 ConnectionPointContainer_AddRef,
3117 ConnectionPointContainer_Release,
3118 ConnectionPointContainer_EnumConnectionPoints,
3119 ConnectionPointContainer_FindConnectionPoint
3122 /* IConnectionPoint */
3123 static HRESULT WINAPI ConnectionPoint_QueryInterface(IConnectionPoint *iface,
3124 REFIID riid, void **ppv)
3126 ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3128 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv );
3130 *ppv = NULL;
3132 if (IsEqualGUID(&IID_IUnknown, riid) ||
3133 IsEqualGUID(&IID_IConnectionPoint, riid))
3135 *ppv = iface;
3138 if (*ppv)
3140 IConnectionPoint_AddRef(iface);
3141 return S_OK;
3144 WARN("Unsupported interface %s\n", debugstr_guid(riid));
3145 return E_NOINTERFACE;
3148 static ULONG WINAPI ConnectionPoint_AddRef(IConnectionPoint *iface)
3150 ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3151 return IConnectionPointContainer_AddRef(This->container);
3154 static ULONG WINAPI ConnectionPoint_Release(IConnectionPoint *iface)
3156 ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3157 return IConnectionPointContainer_Release(This->container);
3160 static HRESULT WINAPI ConnectionPoint_GetConnectionInterface(IConnectionPoint *iface, IID *iid)
3162 ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3164 TRACE("(%p)->(%p)\n", This, iid);
3166 if (!iid) return E_POINTER;
3168 *iid = *This->iid;
3169 return S_OK;
3172 static HRESULT WINAPI ConnectionPoint_GetConnectionPointContainer(IConnectionPoint *iface,
3173 IConnectionPointContainer **container)
3175 ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3177 TRACE("(%p)->(%p)\n", This, container);
3179 if (!container) return E_POINTER;
3181 *container = This->container;
3182 IConnectionPointContainer_AddRef(*container);
3183 return S_OK;
3186 static HRESULT WINAPI ConnectionPoint_Advise(IConnectionPoint *iface, IUnknown *pUnkSink,
3187 DWORD *pdwCookie)
3189 ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3190 FIXME("(%p)->(%p %p): stub\n", This, pUnkSink, pdwCookie);
3191 return E_NOTIMPL;
3194 static HRESULT WINAPI ConnectionPoint_Unadvise(IConnectionPoint *iface, DWORD cookie)
3196 ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3198 TRACE("(%p)->(%d)\n", This, cookie);
3200 if (cookie == 0 || cookie > This->sinks_size || !This->sinks[cookie-1].unk)
3201 return CONNECT_E_NOCONNECTION;
3203 IUnknown_Release(This->sinks[cookie-1].unk);
3204 This->sinks[cookie-1].unk = NULL;
3206 return S_OK;
3209 static HRESULT WINAPI ConnectionPoint_EnumConnections(IConnectionPoint *iface,
3210 IEnumConnections **ppEnum)
3212 ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3213 FIXME("(%p)->(%p): stub\n", This, ppEnum);
3214 return E_NOTIMPL;
3217 static const IConnectionPointVtbl ConnectionPointVtbl =
3219 ConnectionPoint_QueryInterface,
3220 ConnectionPoint_AddRef,
3221 ConnectionPoint_Release,
3222 ConnectionPoint_GetConnectionInterface,
3223 ConnectionPoint_GetConnectionPointContainer,
3224 ConnectionPoint_Advise,
3225 ConnectionPoint_Unadvise,
3226 ConnectionPoint_EnumConnections
3229 static void ConnectionPoint_Init(ConnectionPoint *cp, struct domdoc *doc, REFIID riid)
3231 cp->IConnectionPoint_iface.lpVtbl = &ConnectionPointVtbl;
3232 cp->doc = doc;
3233 cp->iid = riid;
3234 cp->sinks = NULL;
3235 cp->sinks_size = 0;
3237 cp->next = doc->cp_list;
3238 doc->cp_list = cp;
3240 cp->container = &doc->IConnectionPointContainer_iface;
3243 /* domdoc implementation of IObjectWithSite */
3244 static HRESULT WINAPI
3245 domdoc_ObjectWithSite_QueryInterface( IObjectWithSite* iface, REFIID riid, void** ppvObject )
3247 domdoc *This = impl_from_IObjectWithSite(iface);
3248 return IXMLDOMDocument3_QueryInterface(&This->IXMLDOMDocument3_iface, riid, ppvObject);
3251 static ULONG WINAPI domdoc_ObjectWithSite_AddRef( IObjectWithSite* iface )
3253 domdoc *This = impl_from_IObjectWithSite(iface);
3254 return IXMLDOMDocument3_AddRef(&This->IXMLDOMDocument3_iface);
3257 static ULONG WINAPI domdoc_ObjectWithSite_Release( IObjectWithSite* iface )
3259 domdoc *This = impl_from_IObjectWithSite(iface);
3260 return IXMLDOMDocument3_Release(&This->IXMLDOMDocument3_iface);
3263 static HRESULT WINAPI domdoc_ObjectWithSite_GetSite( IObjectWithSite *iface, REFIID iid, void **ppvSite )
3265 domdoc *This = impl_from_IObjectWithSite(iface);
3267 TRACE("(%p)->(%s %p)\n", This, debugstr_guid( iid ), ppvSite );
3269 if ( !This->site )
3270 return E_FAIL;
3272 return IUnknown_QueryInterface( This->site, iid, ppvSite );
3275 static HRESULT WINAPI domdoc_ObjectWithSite_SetSite( IObjectWithSite *iface, IUnknown *punk )
3277 domdoc *This = impl_from_IObjectWithSite(iface);
3279 TRACE("(%p)->(%p)\n", iface, punk);
3281 if(!punk)
3283 if(This->site)
3285 IUnknown_Release( This->site );
3286 This->site = NULL;
3289 return S_OK;
3292 IUnknown_AddRef( punk );
3294 if(This->site)
3295 IUnknown_Release( This->site );
3297 This->site = punk;
3299 return S_OK;
3302 static const IObjectWithSiteVtbl domdocObjectSite =
3304 domdoc_ObjectWithSite_QueryInterface,
3305 domdoc_ObjectWithSite_AddRef,
3306 domdoc_ObjectWithSite_Release,
3307 domdoc_ObjectWithSite_SetSite,
3308 domdoc_ObjectWithSite_GetSite
3311 static HRESULT WINAPI domdoc_Safety_QueryInterface(IObjectSafety *iface, REFIID riid, void **ppv)
3313 domdoc *This = impl_from_IObjectSafety(iface);
3314 return IXMLDOMDocument3_QueryInterface(&This->IXMLDOMDocument3_iface, riid, ppv);
3317 static ULONG WINAPI domdoc_Safety_AddRef(IObjectSafety *iface)
3319 domdoc *This = impl_from_IObjectSafety(iface);
3320 return IXMLDOMDocument3_AddRef(&This->IXMLDOMDocument3_iface);
3323 static ULONG WINAPI domdoc_Safety_Release(IObjectSafety *iface)
3325 domdoc *This = impl_from_IObjectSafety(iface);
3326 return IXMLDOMDocument3_Release(&This->IXMLDOMDocument3_iface);
3329 #define SAFETY_SUPPORTED_OPTIONS (INTERFACESAFE_FOR_UNTRUSTED_CALLER|INTERFACESAFE_FOR_UNTRUSTED_DATA|INTERFACE_USES_SECURITY_MANAGER)
3331 static HRESULT WINAPI domdoc_Safety_GetInterfaceSafetyOptions(IObjectSafety *iface, REFIID riid,
3332 DWORD *supported, DWORD *enabled)
3334 domdoc *This = impl_from_IObjectSafety(iface);
3336 TRACE("(%p)->(%s %p %p)\n", This, debugstr_guid(riid), supported, enabled);
3338 if(!supported || !enabled) return E_POINTER;
3340 *supported = SAFETY_SUPPORTED_OPTIONS;
3341 *enabled = This->safeopt;
3343 return S_OK;
3346 static HRESULT WINAPI domdoc_Safety_SetInterfaceSafetyOptions(IObjectSafety *iface, REFIID riid,
3347 DWORD mask, DWORD enabled)
3349 domdoc *This = impl_from_IObjectSafety(iface);
3350 TRACE("(%p)->(%s %x %x)\n", This, debugstr_guid(riid), mask, enabled);
3352 if ((mask & ~SAFETY_SUPPORTED_OPTIONS) != 0)
3353 return E_FAIL;
3355 This->safeopt = (This->safeopt & ~mask) | (mask & enabled);
3357 return S_OK;
3360 #undef SAFETY_SUPPORTED_OPTIONS
3362 static const IObjectSafetyVtbl domdocObjectSafetyVtbl = {
3363 domdoc_Safety_QueryInterface,
3364 domdoc_Safety_AddRef,
3365 domdoc_Safety_Release,
3366 domdoc_Safety_GetInterfaceSafetyOptions,
3367 domdoc_Safety_SetInterfaceSafetyOptions
3370 static const tid_t domdoc_iface_tids[] = {
3371 IXMLDOMDocument3_tid,
3375 static dispex_static_data_t domdoc_dispex = {
3376 NULL,
3377 IXMLDOMDocument3_tid,
3378 NULL,
3379 domdoc_iface_tids
3382 HRESULT get_domdoc_from_xmldoc(xmlDocPtr xmldoc, IXMLDOMDocument3 **document)
3384 domdoc *doc;
3386 doc = heap_alloc( sizeof (*doc) );
3387 if( !doc )
3388 return E_OUTOFMEMORY;
3390 doc->IXMLDOMDocument3_iface.lpVtbl = &XMLDOMDocument3Vtbl;
3391 doc->IPersistStreamInit_iface.lpVtbl = &xmldoc_IPersistStreamInit_VTable;
3392 doc->IObjectWithSite_iface.lpVtbl = &domdocObjectSite;
3393 doc->IObjectSafety_iface.lpVtbl = &domdocObjectSafetyVtbl;
3394 doc->IConnectionPointContainer_iface.lpVtbl = &ConnectionPointContainerVtbl;
3395 doc->ref = 1;
3396 doc->async = VARIANT_TRUE;
3397 doc->validating = 0;
3398 doc->resolving = 0;
3399 doc->properties = properties_from_xmlDocPtr(xmldoc);
3400 doc->error = S_OK;
3401 doc->stream = NULL;
3402 doc->site = NULL;
3403 doc->safeopt = 0;
3404 doc->bsc = NULL;
3405 doc->cp_list = NULL;
3406 memset(doc->events, 0, sizeof(doc->events));
3408 /* events connection points */
3409 ConnectionPoint_Init(&doc->cp_dispatch, doc, &IID_IDispatch);
3410 ConnectionPoint_Init(&doc->cp_propnotif, doc, &IID_IPropertyNotifySink);
3411 ConnectionPoint_Init(&doc->cp_domdocevents, doc, &DIID_XMLDOMDocumentEvents);
3413 init_xmlnode(&doc->node, (xmlNodePtr)xmldoc, (IXMLDOMNode*)&doc->IXMLDOMDocument3_iface,
3414 &domdoc_dispex);
3416 *document = &doc->IXMLDOMDocument3_iface;
3418 TRACE("returning iface %p\n", *document);
3419 return S_OK;
3422 HRESULT DOMDocument_create(MSXML_VERSION version, IUnknown *pUnkOuter, void **ppObj)
3424 xmlDocPtr xmldoc;
3425 HRESULT hr;
3427 TRACE("(%d, %p, %p)\n", version, pUnkOuter, ppObj);
3429 xmldoc = xmlNewDoc(NULL);
3430 if(!xmldoc)
3431 return E_OUTOFMEMORY;
3433 xmldoc->_private = create_priv();
3434 priv_from_xmlDocPtr(xmldoc)->properties = create_properties(version);
3436 hr = get_domdoc_from_xmldoc(xmldoc, (IXMLDOMDocument3**)ppObj);
3437 if(FAILED(hr))
3439 free_properties(properties_from_xmlDocPtr(xmldoc));
3440 heap_free(xmldoc->_private);
3441 xmlFreeDoc(xmldoc);
3442 return hr;
3445 return hr;
3448 IUnknown* create_domdoc( xmlNodePtr document )
3450 void* pObj = NULL;
3451 HRESULT hr;
3453 TRACE("(%p)\n", document);
3455 hr = get_domdoc_from_xmldoc((xmlDocPtr)document, (IXMLDOMDocument3**)&pObj);
3456 if (FAILED(hr))
3457 return NULL;
3459 return pObj;
3462 #else
3464 HRESULT DOMDocument_create(MSXML_VERSION version, IUnknown *pUnkOuter, void **ppObj)
3466 MESSAGE("This program tried to use a DOMDocument object, but\n"
3467 "libxml2 support was not present at compile time.\n");
3468 return E_NOTIMPL;
3471 #endif