ole32: Added IMoniker::BindToStorage proxy/stub implementation.
[wine.git] / dlls / msxml3 / domdoc.c
blob49e6168f9a8162effe83e6f179a0fc8ba6b40ecc
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 /* IObjectWithSite*/
136 IUnknown *site;
138 /* IObjectSafety */
139 DWORD safeopt;
141 /* connection list */
142 ConnectionPoint *cp_list;
143 ConnectionPoint cp_domdocevents;
144 ConnectionPoint cp_propnotif;
145 ConnectionPoint cp_dispatch;
147 /* events */
148 IDispatch *events[EVENTID_LAST];
150 IXMLDOMSchemaCollection2 *namespaces;
153 static HRESULT set_doc_event(domdoc *doc, eventid_t eid, const VARIANT *v)
155 IDispatch *disp;
157 switch (V_VT(v))
159 case VT_UNKNOWN:
160 if (V_UNKNOWN(v))
161 IUnknown_QueryInterface(V_UNKNOWN(v), &IID_IDispatch, (void**)&disp);
162 else
163 disp = NULL;
164 break;
165 case VT_DISPATCH:
166 disp = V_DISPATCH(v);
167 if (disp) IDispatch_AddRef(disp);
168 break;
169 default:
170 return DISP_E_TYPEMISMATCH;
173 if (doc->events[eid]) IDispatch_Release(doc->events[eid]);
174 doc->events[eid] = disp;
176 return S_OK;
179 static inline ConnectionPoint *impl_from_IConnectionPoint(IConnectionPoint *iface)
181 return CONTAINING_RECORD(iface, ConnectionPoint, IConnectionPoint_iface);
185 In native windows, the whole lifetime management of XMLDOMNodes is
186 managed automatically using reference counts. Wine emulates that by
187 maintaining a reference count to the document that is increased for
188 each IXMLDOMNode pointer passed out for this document. If all these
189 pointers are gone, the document is unreachable and gets freed, that
190 is, all nodes in the tree of the document get freed.
192 You are able to create nodes that are associated to a document (in
193 fact, in msxml's XMLDOM model, all nodes are associated to a document),
194 but not in the tree of that document, for example using the createFoo
195 functions from IXMLDOMDocument. These nodes do not get cleaned up
196 by libxml, so we have to do it ourselves.
198 To catch these nodes, a list of "orphan nodes" is introduced.
199 It contains pointers to all roots of node trees that are
200 associated with the document without being part of the document
201 tree. All nodes with parent==NULL (except for the document root nodes)
202 should be in the orphan node list of their document. All orphan nodes
203 get freed together with the document itself.
206 typedef struct _xmldoc_priv {
207 LONG refs;
208 struct list orphans;
209 domdoc_properties* properties;
210 } xmldoc_priv;
212 typedef struct _orphan_entry {
213 struct list entry;
214 xmlNode * node;
215 } orphan_entry;
217 typedef struct _select_ns_entry {
218 struct list entry;
219 xmlChar const* prefix;
220 xmlChar prefix_end;
221 xmlChar const* href;
222 xmlChar href_end;
223 } select_ns_entry;
225 static inline xmldoc_priv * priv_from_xmlDocPtr(const xmlDocPtr doc)
227 return doc->_private;
230 static inline domdoc_properties * properties_from_xmlDocPtr(xmlDocPtr doc)
232 return priv_from_xmlDocPtr(doc)->properties;
235 BOOL is_xpathmode(const xmlDocPtr doc)
237 return properties_from_xmlDocPtr(doc)->XPath;
240 void set_xpathmode(xmlDocPtr doc, BOOL xpath)
242 properties_from_xmlDocPtr(doc)->XPath = xpath;
245 int registerNamespaces(xmlXPathContextPtr ctxt)
247 int n = 0;
248 const select_ns_entry* ns = NULL;
249 const struct list* pNsList = &properties_from_xmlDocPtr(ctxt->doc)->selectNsList;
251 TRACE("(%p)\n", ctxt);
253 LIST_FOR_EACH_ENTRY( ns, pNsList, select_ns_entry, entry )
255 xmlXPathRegisterNs(ctxt, ns->prefix, ns->href);
256 ++n;
259 return n;
262 static inline void clear_selectNsList(struct list* pNsList)
264 select_ns_entry *ns, *ns2;
265 LIST_FOR_EACH_ENTRY_SAFE( ns, ns2, pNsList, select_ns_entry, entry )
267 heap_free( ns );
269 list_init(pNsList);
272 static xmldoc_priv * create_priv(void)
274 xmldoc_priv *priv;
275 priv = heap_alloc( sizeof (*priv) );
277 if (priv)
279 priv->refs = 0;
280 list_init( &priv->orphans );
281 priv->properties = NULL;
284 return priv;
287 static domdoc_properties *create_properties(MSXML_VERSION version)
289 domdoc_properties *properties = heap_alloc(sizeof(domdoc_properties));
291 list_init(&properties->selectNsList);
292 properties->preserving = VARIANT_FALSE;
293 properties->schemaCache = NULL;
294 properties->selectNsStr = heap_alloc_zero(sizeof(xmlChar));
295 properties->selectNsStr_len = 0;
297 /* properties that are dependent on object versions */
298 properties->version = version;
299 properties->XPath = (version == MSXML4 || version == MSXML6);
301 return properties;
304 static domdoc_properties* copy_properties(domdoc_properties const* properties)
306 domdoc_properties* pcopy = heap_alloc(sizeof(domdoc_properties));
307 select_ns_entry const* ns = NULL;
308 select_ns_entry* new_ns = NULL;
309 int len = (properties->selectNsStr_len+1)*sizeof(xmlChar);
310 ptrdiff_t offset;
312 if (pcopy)
314 pcopy->version = properties->version;
315 pcopy->preserving = properties->preserving;
316 pcopy->schemaCache = properties->schemaCache;
317 if (pcopy->schemaCache)
318 IXMLDOMSchemaCollection2_AddRef(pcopy->schemaCache);
319 pcopy->XPath = properties->XPath;
320 pcopy->selectNsStr_len = properties->selectNsStr_len;
321 list_init( &pcopy->selectNsList );
322 pcopy->selectNsStr = heap_alloc(len);
323 memcpy((xmlChar*)pcopy->selectNsStr, properties->selectNsStr, len);
324 offset = pcopy->selectNsStr - properties->selectNsStr;
326 LIST_FOR_EACH_ENTRY( ns, (&properties->selectNsList), select_ns_entry, entry )
328 new_ns = heap_alloc(sizeof(select_ns_entry));
329 memcpy(new_ns, ns, sizeof(select_ns_entry));
330 new_ns->href += offset;
331 new_ns->prefix += offset;
332 list_add_tail(&pcopy->selectNsList, &new_ns->entry);
337 return pcopy;
340 static void free_properties(domdoc_properties* properties)
342 if (properties)
344 if (properties->schemaCache)
345 IXMLDOMSchemaCollection2_Release(properties->schemaCache);
346 clear_selectNsList(&properties->selectNsList);
347 heap_free((xmlChar*)properties->selectNsStr);
348 heap_free(properties);
352 static void release_namespaces(domdoc *This)
354 if (This->namespaces)
356 IXMLDOMSchemaCollection2_Release(This->namespaces);
357 This->namespaces = NULL;
361 /* links a "<?xml" node as a first child */
362 void xmldoc_link_xmldecl(xmlDocPtr doc, xmlNodePtr node)
364 assert(doc != NULL);
365 if (doc->standalone != -1) xmlAddPrevSibling( doc->children, node );
368 /* unlinks a first "<?xml" child if it was created */
369 xmlNodePtr xmldoc_unlink_xmldecl(xmlDocPtr doc)
371 static const xmlChar xmlA[] = "xml";
372 xmlNodePtr node, first_child;
374 assert(doc != NULL);
376 /* xml declaration node could be created automatically after parsing or added
377 to a tree later */
378 first_child = doc->children;
379 if (first_child && first_child->type == XML_PI_NODE && xmlStrEqual(first_child->name, xmlA))
381 node = first_child;
382 xmlUnlinkNode( node );
384 else
385 node = NULL;
387 return node;
390 BOOL is_preserving_whitespace(xmlNodePtr node)
392 domdoc_properties* properties = NULL;
393 /* during parsing the xmlDoc._private stuff is not there */
394 if (priv_from_xmlDocPtr(node->doc))
395 properties = properties_from_xmlDocPtr(node->doc);
396 return ((properties && properties->preserving == VARIANT_TRUE) ||
397 xmlNodeGetSpacePreserve(node) == 1);
400 static inline BOOL strn_isspace(xmlChar const* str, int len)
402 for (; str && len > 0 && *str; ++str, --len)
403 if (!isspace(*str))
404 break;
406 return len == 0;
409 static void sax_characters(void *ctx, const xmlChar *ch, int len)
411 xmlParserCtxtPtr ctxt;
412 const domdoc *This;
414 ctxt = (xmlParserCtxtPtr) ctx;
415 This = (const domdoc*) ctxt->_private;
417 if (ctxt->node)
419 /* during domdoc_loadXML() the xmlDocPtr->_private data is not available */
420 if (!This->properties->preserving &&
421 !is_preserving_whitespace(ctxt->node) &&
422 strn_isspace(ch, len))
423 return;
426 xmlSAX2Characters(ctxt, ch, len);
429 static void LIBXML2_LOG_CALLBACK sax_error(void* ctx, char const* msg, ...)
431 va_list ap;
432 va_start(ap, msg);
433 LIBXML2_CALLBACK_ERR(doparse, msg, ap);
434 va_end(ap);
437 static void LIBXML2_LOG_CALLBACK sax_warning(void* ctx, char const* msg, ...)
439 va_list ap;
440 va_start(ap, msg);
441 LIBXML2_CALLBACK_WARN(doparse, msg, ap);
442 va_end(ap);
445 static void sax_serror(void* ctx, xmlErrorPtr err)
447 LIBXML2_CALLBACK_SERROR(doparse, err);
450 static xmlDocPtr doparse(domdoc* This, char const* ptr, int len, xmlCharEncoding encoding)
452 xmlDocPtr doc = NULL;
453 xmlParserCtxtPtr pctx;
454 static xmlSAXHandler sax_handler = {
455 xmlSAX2InternalSubset, /* internalSubset */
456 xmlSAX2IsStandalone, /* isStandalone */
457 xmlSAX2HasInternalSubset, /* hasInternalSubset */
458 xmlSAX2HasExternalSubset, /* hasExternalSubset */
459 xmlSAX2ResolveEntity, /* resolveEntity */
460 xmlSAX2GetEntity, /* getEntity */
461 xmlSAX2EntityDecl, /* entityDecl */
462 xmlSAX2NotationDecl, /* notationDecl */
463 xmlSAX2AttributeDecl, /* attributeDecl */
464 xmlSAX2ElementDecl, /* elementDecl */
465 xmlSAX2UnparsedEntityDecl, /* unparsedEntityDecl */
466 xmlSAX2SetDocumentLocator, /* setDocumentLocator */
467 xmlSAX2StartDocument, /* startDocument */
468 xmlSAX2EndDocument, /* endDocument */
469 xmlSAX2StartElement, /* startElement */
470 xmlSAX2EndElement, /* endElement */
471 xmlSAX2Reference, /* reference */
472 sax_characters, /* characters */
473 sax_characters, /* ignorableWhitespace */
474 xmlSAX2ProcessingInstruction, /* processingInstruction */
475 xmlSAX2Comment, /* comment */
476 sax_warning, /* warning */
477 sax_error, /* error */
478 sax_error, /* fatalError */
479 xmlSAX2GetParameterEntity, /* getParameterEntity */
480 xmlSAX2CDataBlock, /* cdataBlock */
481 xmlSAX2ExternalSubset, /* externalSubset */
482 0, /* initialized */
483 NULL, /* _private */
484 xmlSAX2StartElementNs, /* startElementNs */
485 xmlSAX2EndElementNs, /* endElementNs */
486 sax_serror /* serror */
489 pctx = xmlCreateMemoryParserCtxt(ptr, len);
490 if (!pctx)
492 ERR("Failed to create parser context\n");
493 return NULL;
496 if (pctx->sax) xmlFree(pctx->sax);
497 pctx->sax = &sax_handler;
498 pctx->_private = This;
499 pctx->recovery = 0;
501 if (encoding != XML_CHAR_ENCODING_NONE)
502 xmlSwitchEncoding(pctx, encoding);
504 xmlParseDocument(pctx);
506 if (pctx->wellFormed)
508 doc = pctx->myDoc;
510 else
512 xmlFreeDoc(pctx->myDoc);
513 pctx->myDoc = NULL;
515 pctx->sax = NULL;
516 xmlFreeParserCtxt(pctx);
518 /* TODO: put this in one of the SAX callbacks */
519 /* create first child as a <?xml...?> */
520 if (doc && doc->standalone != -1)
522 xmlNodePtr node;
523 char buff[30];
524 xmlChar *xmlbuff = (xmlChar*)buff;
526 node = xmlNewDocPI( doc, (xmlChar*)"xml", NULL );
528 /* version attribute can't be omitted */
529 sprintf(buff, "version=\"%s\"", doc->version ? (char*)doc->version : "1.0");
530 xmlNodeAddContent( node, xmlbuff );
532 if (doc->encoding)
534 sprintf(buff, " encoding=\"%s\"", doc->encoding);
535 xmlNodeAddContent( node, xmlbuff );
538 if (doc->standalone != -2)
540 sprintf(buff, " standalone=\"%s\"", doc->standalone == 0 ? "no" : "yes");
541 xmlNodeAddContent( node, xmlbuff );
544 xmldoc_link_xmldecl( doc, node );
547 return doc;
550 void xmldoc_init(xmlDocPtr doc, MSXML_VERSION version)
552 doc->_private = create_priv();
553 priv_from_xmlDocPtr(doc)->properties = create_properties(version);
556 LONG xmldoc_add_ref(xmlDocPtr doc)
558 LONG ref = InterlockedIncrement(&priv_from_xmlDocPtr(doc)->refs);
559 TRACE("(%p)->(%d)\n", doc, ref);
560 return ref;
563 LONG xmldoc_release(xmlDocPtr doc)
565 xmldoc_priv *priv = priv_from_xmlDocPtr(doc);
566 LONG ref = InterlockedDecrement(&priv->refs);
567 TRACE("(%p)->(%d)\n", doc, ref);
568 if(ref == 0)
570 orphan_entry *orphan, *orphan2;
571 TRACE("freeing docptr %p\n", doc);
573 LIST_FOR_EACH_ENTRY_SAFE( orphan, orphan2, &priv->orphans, orphan_entry, entry )
575 xmlFreeNode( orphan->node );
576 heap_free( orphan );
578 free_properties(priv->properties);
579 heap_free(doc->_private);
581 xmlFreeDoc(doc);
584 return ref;
587 HRESULT xmldoc_add_orphan(xmlDocPtr doc, xmlNodePtr node)
589 xmldoc_priv *priv = priv_from_xmlDocPtr(doc);
590 orphan_entry *entry;
592 entry = heap_alloc( sizeof (*entry) );
593 if(!entry)
594 return E_OUTOFMEMORY;
596 entry->node = node;
597 list_add_head( &priv->orphans, &entry->entry );
598 return S_OK;
601 HRESULT xmldoc_remove_orphan(xmlDocPtr doc, xmlNodePtr node)
603 xmldoc_priv *priv = priv_from_xmlDocPtr(doc);
604 orphan_entry *entry, *entry2;
606 LIST_FOR_EACH_ENTRY_SAFE( entry, entry2, &priv->orphans, orphan_entry, entry )
608 if( entry->node == node )
610 list_remove( &entry->entry );
611 heap_free( entry );
612 return S_OK;
616 return S_FALSE;
619 static inline xmlDocPtr get_doc( domdoc *This )
621 return (xmlDocPtr)This->node.node;
624 static HRESULT attach_xmldoc(domdoc *This, xmlDocPtr xml )
626 release_namespaces(This);
628 if(This->node.node)
630 priv_from_xmlDocPtr(get_doc(This))->properties = NULL;
631 if (xmldoc_release(get_doc(This)) != 0)
632 priv_from_xmlDocPtr(get_doc(This))->properties =
633 copy_properties(This->properties);
636 This->node.node = (xmlNodePtr) xml;
638 if(This->node.node)
640 xmldoc_add_ref(get_doc(This));
641 priv_from_xmlDocPtr(get_doc(This))->properties = This->properties;
644 return S_OK;
647 static inline domdoc *impl_from_IXMLDOMDocument3( IXMLDOMDocument3 *iface )
649 return CONTAINING_RECORD(iface, domdoc, IXMLDOMDocument3_iface);
652 static inline domdoc *impl_from_IPersistStreamInit(IPersistStreamInit *iface)
654 return CONTAINING_RECORD(iface, domdoc, IPersistStreamInit_iface);
657 static inline domdoc *impl_from_IObjectWithSite(IObjectWithSite *iface)
659 return CONTAINING_RECORD(iface, domdoc, IObjectWithSite_iface);
662 static inline domdoc *impl_from_IObjectSafety(IObjectSafety *iface)
664 return CONTAINING_RECORD(iface, domdoc, IObjectSafety_iface);
667 static inline domdoc *impl_from_IConnectionPointContainer(IConnectionPointContainer *iface)
669 return CONTAINING_RECORD(iface, domdoc, IConnectionPointContainer_iface);
672 /************************************************************************
673 * domdoc implementation of IPersistStream.
675 static HRESULT WINAPI PersistStreamInit_QueryInterface(
676 IPersistStreamInit *iface, REFIID riid, void **ppvObj)
678 domdoc* This = impl_from_IPersistStreamInit(iface);
679 return IXMLDOMDocument3_QueryInterface(&This->IXMLDOMDocument3_iface, riid, ppvObj);
682 static ULONG WINAPI PersistStreamInit_AddRef(
683 IPersistStreamInit *iface)
685 domdoc* This = impl_from_IPersistStreamInit(iface);
686 return IXMLDOMDocument3_AddRef(&This->IXMLDOMDocument3_iface);
689 static ULONG WINAPI PersistStreamInit_Release(
690 IPersistStreamInit *iface)
692 domdoc* This = impl_from_IPersistStreamInit(iface);
693 return IXMLDOMDocument3_Release(&This->IXMLDOMDocument3_iface);
696 static HRESULT WINAPI PersistStreamInit_GetClassID(
697 IPersistStreamInit *iface, CLSID *classid)
699 domdoc* This = impl_from_IPersistStreamInit(iface);
700 TRACE("(%p)->(%p)\n", This, classid);
702 if(!classid)
703 return E_POINTER;
705 *classid = *DOMDocument_version(This->properties->version);
707 return S_OK;
710 static HRESULT WINAPI PersistStreamInit_IsDirty(
711 IPersistStreamInit *iface)
713 domdoc *This = impl_from_IPersistStreamInit(iface);
714 FIXME("(%p): stub!\n", This);
715 return S_FALSE;
718 static HRESULT domdoc_load_from_stream(domdoc *doc, ISequentialStream *stream)
720 DWORD read, written, len;
721 xmlDocPtr xmldoc = NULL;
722 IStream *hstream;
723 HGLOBAL hglobal;
724 BYTE buf[4096];
725 HRESULT hr;
726 char *ptr;
728 hstream = NULL;
729 hr = CreateStreamOnHGlobal(NULL, TRUE, &hstream);
730 if (FAILED(hr))
731 return hr;
735 ISequentialStream_Read(stream, buf, sizeof(buf), &read);
736 hr = IStream_Write(hstream, buf, read, &written);
737 } while(SUCCEEDED(hr) && written != 0 && read != 0);
739 if (FAILED(hr))
741 ERR("failed to copy stream 0x%08x\n", hr);
742 IStream_Release(hstream);
743 return hr;
746 hr = GetHGlobalFromStream(hstream, &hglobal);
747 if (FAILED(hr))
748 return hr;
750 len = GlobalSize(hglobal);
751 ptr = GlobalLock(hglobal);
752 if (len)
753 xmldoc = doparse(doc, ptr, len, XML_CHAR_ENCODING_NONE);
754 GlobalUnlock(hglobal);
756 if (!xmldoc)
758 ERR("Failed to parse xml\n");
759 return E_FAIL;
762 xmldoc->_private = create_priv();
764 return attach_xmldoc(doc, xmldoc);
767 static HRESULT WINAPI PersistStreamInit_Load(IPersistStreamInit *iface, IStream *stream)
769 domdoc *This = impl_from_IPersistStreamInit(iface);
771 TRACE("(%p)->(%p)\n", This, stream);
773 if (!stream)
774 return E_INVALIDARG;
776 return domdoc_load_from_stream(This, (ISequentialStream*)stream);
779 static HRESULT WINAPI PersistStreamInit_Save(
780 IPersistStreamInit *iface, IStream *stream, BOOL clr_dirty)
782 domdoc *This = impl_from_IPersistStreamInit(iface);
783 BSTR xmlString;
784 HRESULT hr;
786 TRACE("(%p)->(%p %d)\n", This, stream, clr_dirty);
788 hr = IXMLDOMDocument3_get_xml(&This->IXMLDOMDocument3_iface, &xmlString);
789 if(hr == S_OK)
791 DWORD len = SysStringLen(xmlString) * sizeof(WCHAR);
793 hr = IStream_Write( stream, xmlString, len, NULL );
794 SysFreeString(xmlString);
797 TRACE("ret 0x%08x\n", hr);
799 return hr;
802 static HRESULT WINAPI PersistStreamInit_GetSizeMax(
803 IPersistStreamInit *iface, ULARGE_INTEGER *pcbSize)
805 domdoc *This = impl_from_IPersistStreamInit(iface);
806 TRACE("(%p)->(%p)\n", This, pcbSize);
807 return E_NOTIMPL;
810 static HRESULT WINAPI PersistStreamInit_InitNew(
811 IPersistStreamInit *iface)
813 domdoc *This = impl_from_IPersistStreamInit(iface);
814 TRACE("(%p)\n", This);
815 return S_OK;
818 static const IPersistStreamInitVtbl xmldoc_IPersistStreamInit_VTable =
820 PersistStreamInit_QueryInterface,
821 PersistStreamInit_AddRef,
822 PersistStreamInit_Release,
823 PersistStreamInit_GetClassID,
824 PersistStreamInit_IsDirty,
825 PersistStreamInit_Load,
826 PersistStreamInit_Save,
827 PersistStreamInit_GetSizeMax,
828 PersistStreamInit_InitNew
831 /* IXMLDOMDocument3 interface */
833 static const tid_t domdoc_se_tids[] = {
834 IXMLDOMNode_tid,
835 IXMLDOMDocument_tid,
836 IXMLDOMDocument2_tid,
837 IXMLDOMDocument3_tid,
841 static HRESULT WINAPI domdoc_QueryInterface( IXMLDOMDocument3 *iface, REFIID riid, void** ppvObject )
843 domdoc *This = impl_from_IXMLDOMDocument3( iface );
845 TRACE("(%p)->(%s %p)\n", This, debugstr_guid( riid ), ppvObject );
847 *ppvObject = NULL;
849 if ( IsEqualGUID( riid, &IID_IUnknown ) ||
850 IsEqualGUID( riid, &IID_IDispatch ) ||
851 IsEqualGUID( riid, &IID_IXMLDOMNode ) ||
852 IsEqualGUID( riid, &IID_IXMLDOMDocument ) ||
853 IsEqualGUID( riid, &IID_IXMLDOMDocument2 )||
854 IsEqualGUID( riid, &IID_IXMLDOMDocument3 ))
856 *ppvObject = iface;
858 else if (IsEqualGUID(&IID_IPersistStream, riid) ||
859 IsEqualGUID(&IID_IPersistStreamInit, riid))
861 *ppvObject = &This->IPersistStreamInit_iface;
863 else if (IsEqualGUID(&IID_IObjectWithSite, riid))
865 *ppvObject = &This->IObjectWithSite_iface;
867 else if (IsEqualGUID(&IID_IObjectSafety, riid))
869 *ppvObject = &This->IObjectSafety_iface;
871 else if( IsEqualGUID( riid, &IID_ISupportErrorInfo ))
873 return node_create_supporterrorinfo(domdoc_se_tids, ppvObject);
875 else if(node_query_interface(&This->node, riid, ppvObject))
877 return *ppvObject ? S_OK : E_NOINTERFACE;
879 else if (IsEqualGUID( riid, &IID_IConnectionPointContainer ))
881 *ppvObject = &This->IConnectionPointContainer_iface;
883 else
885 TRACE("interface %s not implemented\n", debugstr_guid(riid));
886 return E_NOINTERFACE;
889 IUnknown_AddRef((IUnknown*)*ppvObject);
891 return S_OK;
894 static ULONG WINAPI domdoc_AddRef( IXMLDOMDocument3 *iface )
896 domdoc *This = impl_from_IXMLDOMDocument3( iface );
897 ULONG ref = InterlockedIncrement( &This->ref );
898 TRACE("(%p)->(%d)\n", This, ref );
899 return ref;
902 static ULONG WINAPI domdoc_Release( IXMLDOMDocument3 *iface )
904 domdoc *This = impl_from_IXMLDOMDocument3( iface );
905 LONG ref = InterlockedDecrement( &This->ref );
907 TRACE("(%p)->(%d)\n", This, ref );
909 if ( ref == 0 )
911 int eid;
913 if(This->bsc)
914 detach_bsc(This->bsc);
916 if (This->site)
917 IUnknown_Release( This->site );
918 destroy_xmlnode(&This->node);
920 for (eid = 0; eid < EVENTID_LAST; eid++)
921 if (This->events[eid]) IDispatch_Release(This->events[eid]);
923 release_namespaces(This);
924 heap_free(This);
927 return ref;
930 static HRESULT WINAPI domdoc_GetTypeInfoCount( IXMLDOMDocument3 *iface, UINT* pctinfo )
932 domdoc *This = impl_from_IXMLDOMDocument3( iface );
933 return IDispatchEx_GetTypeInfoCount(&This->node.dispex.IDispatchEx_iface, pctinfo);
936 static HRESULT WINAPI domdoc_GetTypeInfo(
937 IXMLDOMDocument3 *iface,
938 UINT iTInfo, LCID lcid, ITypeInfo** ppTInfo )
940 domdoc *This = impl_from_IXMLDOMDocument3( iface );
941 return IDispatchEx_GetTypeInfo(&This->node.dispex.IDispatchEx_iface, iTInfo, lcid, ppTInfo);
944 static HRESULT WINAPI domdoc_GetIDsOfNames(
945 IXMLDOMDocument3 *iface,
946 REFIID riid,
947 LPOLESTR* rgszNames,
948 UINT cNames,
949 LCID lcid,
950 DISPID* rgDispId)
952 domdoc *This = impl_from_IXMLDOMDocument3( iface );
953 return IDispatchEx_GetIDsOfNames(&This->node.dispex.IDispatchEx_iface,
954 riid, rgszNames, cNames, lcid, rgDispId);
957 static HRESULT WINAPI domdoc_Invoke(
958 IXMLDOMDocument3 *iface,
959 DISPID dispIdMember,
960 REFIID riid,
961 LCID lcid,
962 WORD wFlags,
963 DISPPARAMS* pDispParams,
964 VARIANT* pVarResult,
965 EXCEPINFO* pExcepInfo,
966 UINT* puArgErr)
968 domdoc *This = impl_from_IXMLDOMDocument3( iface );
969 return IDispatchEx_Invoke(&This->node.dispex.IDispatchEx_iface,
970 dispIdMember, riid, lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
973 static HRESULT WINAPI domdoc_get_nodeName(
974 IXMLDOMDocument3 *iface,
975 BSTR* name )
977 domdoc *This = impl_from_IXMLDOMDocument3( iface );
979 static const WCHAR documentW[] = {'#','d','o','c','u','m','e','n','t',0};
981 TRACE("(%p)->(%p)\n", This, name);
983 return return_bstr(documentW, name);
987 static HRESULT WINAPI domdoc_get_nodeValue(
988 IXMLDOMDocument3 *iface,
989 VARIANT* value )
991 domdoc *This = impl_from_IXMLDOMDocument3( iface );
993 TRACE("(%p)->(%p)\n", This, value);
995 if(!value)
996 return E_INVALIDARG;
998 V_VT(value) = VT_NULL;
999 V_BSTR(value) = NULL; /* tests show that we should do this */
1000 return S_FALSE;
1004 static HRESULT WINAPI domdoc_put_nodeValue(
1005 IXMLDOMDocument3 *iface,
1006 VARIANT value)
1008 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1009 TRACE("(%p)->(%s)\n", This, debugstr_variant(&value));
1010 return E_FAIL;
1014 static HRESULT WINAPI domdoc_get_nodeType(
1015 IXMLDOMDocument3 *iface,
1016 DOMNodeType* type )
1018 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1020 TRACE("(%p)->(%p)\n", This, type);
1022 *type = NODE_DOCUMENT;
1023 return S_OK;
1027 static HRESULT WINAPI domdoc_get_parentNode(
1028 IXMLDOMDocument3 *iface,
1029 IXMLDOMNode** parent )
1031 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1033 TRACE("(%p)->(%p)\n", This, parent);
1035 return node_get_parent(&This->node, parent);
1039 static HRESULT WINAPI domdoc_get_childNodes(
1040 IXMLDOMDocument3 *iface,
1041 IXMLDOMNodeList** childList )
1043 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1045 TRACE("(%p)->(%p)\n", This, childList);
1047 return node_get_child_nodes(&This->node, childList);
1051 static HRESULT WINAPI domdoc_get_firstChild(
1052 IXMLDOMDocument3 *iface,
1053 IXMLDOMNode** firstChild )
1055 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1057 TRACE("(%p)->(%p)\n", This, firstChild);
1059 return node_get_first_child(&This->node, firstChild);
1063 static HRESULT WINAPI domdoc_get_lastChild(
1064 IXMLDOMDocument3 *iface,
1065 IXMLDOMNode** lastChild )
1067 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1069 TRACE("(%p)->(%p)\n", This, lastChild);
1071 return node_get_last_child(&This->node, lastChild);
1075 static HRESULT WINAPI domdoc_get_previousSibling(
1076 IXMLDOMDocument3 *iface,
1077 IXMLDOMNode** previousSibling )
1079 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1081 TRACE("(%p)->(%p)\n", This, previousSibling);
1083 return return_null_node(previousSibling);
1087 static HRESULT WINAPI domdoc_get_nextSibling(
1088 IXMLDOMDocument3 *iface,
1089 IXMLDOMNode** nextSibling )
1091 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1093 TRACE("(%p)->(%p)\n", This, nextSibling);
1095 return return_null_node(nextSibling);
1099 static HRESULT WINAPI domdoc_get_attributes(
1100 IXMLDOMDocument3 *iface,
1101 IXMLDOMNamedNodeMap** attributeMap )
1103 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1105 TRACE("(%p)->(%p)\n", This, attributeMap);
1107 return return_null_ptr((void**)attributeMap);
1111 static HRESULT WINAPI domdoc_insertBefore(
1112 IXMLDOMDocument3 *iface,
1113 IXMLDOMNode* newChild,
1114 VARIANT refChild,
1115 IXMLDOMNode** outNewChild )
1117 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1119 TRACE("(%p)->(%p %s %p)\n", This, newChild, debugstr_variant(&refChild), outNewChild);
1121 return node_insert_before(&This->node, newChild, &refChild, outNewChild);
1125 static HRESULT WINAPI domdoc_replaceChild(
1126 IXMLDOMDocument3 *iface,
1127 IXMLDOMNode* newChild,
1128 IXMLDOMNode* oldChild,
1129 IXMLDOMNode** outOldChild)
1131 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1133 TRACE("(%p)->(%p %p %p)\n", This, newChild, oldChild, outOldChild);
1135 return node_replace_child(&This->node, newChild, oldChild, outOldChild);
1139 static HRESULT WINAPI domdoc_removeChild(
1140 IXMLDOMDocument3 *iface,
1141 IXMLDOMNode *child,
1142 IXMLDOMNode **oldChild)
1144 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1145 TRACE("(%p)->(%p %p)\n", This, child, oldChild);
1146 return node_remove_child(&This->node, child, oldChild);
1150 static HRESULT WINAPI domdoc_appendChild(
1151 IXMLDOMDocument3 *iface,
1152 IXMLDOMNode *child,
1153 IXMLDOMNode **outChild)
1155 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1156 TRACE("(%p)->(%p %p)\n", This, child, outChild);
1157 return node_append_child(&This->node, child, outChild);
1161 static HRESULT WINAPI domdoc_hasChildNodes(
1162 IXMLDOMDocument3 *iface,
1163 VARIANT_BOOL *ret)
1165 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1166 TRACE("(%p)->(%p)\n", This, ret);
1167 return node_has_childnodes(&This->node, ret);
1171 static HRESULT WINAPI domdoc_get_ownerDocument(
1172 IXMLDOMDocument3 *iface,
1173 IXMLDOMDocument **doc)
1175 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1176 TRACE("(%p)->(%p)\n", This, doc);
1177 return node_get_owner_doc(&This->node, doc);
1181 static HRESULT WINAPI domdoc_cloneNode(
1182 IXMLDOMDocument3 *iface,
1183 VARIANT_BOOL deep,
1184 IXMLDOMNode** outNode)
1186 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1187 TRACE("(%p)->(%d %p)\n", This, deep, outNode);
1188 return node_clone( &This->node, deep, outNode );
1192 static HRESULT WINAPI domdoc_get_nodeTypeString(
1193 IXMLDOMDocument3 *iface,
1194 BSTR *p)
1196 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1197 static const WCHAR documentW[] = {'d','o','c','u','m','e','n','t',0};
1199 TRACE("(%p)->(%p)\n", This, p);
1201 return return_bstr(documentW, p);
1205 static HRESULT WINAPI domdoc_get_text(
1206 IXMLDOMDocument3 *iface,
1207 BSTR *p)
1209 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1210 TRACE("(%p)->(%p)\n", This, p);
1211 return node_get_text(&This->node, p);
1215 static HRESULT WINAPI domdoc_put_text(
1216 IXMLDOMDocument3 *iface,
1217 BSTR text )
1219 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1220 TRACE("(%p)->(%s)\n", This, debugstr_w(text));
1221 return E_FAIL;
1225 static HRESULT WINAPI domdoc_get_specified(
1226 IXMLDOMDocument3 *iface,
1227 VARIANT_BOOL* isSpecified )
1229 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1230 FIXME("(%p)->(%p) stub!\n", This, isSpecified);
1231 *isSpecified = VARIANT_TRUE;
1232 return S_OK;
1236 static HRESULT WINAPI domdoc_get_definition(
1237 IXMLDOMDocument3 *iface,
1238 IXMLDOMNode** definitionNode )
1240 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1241 FIXME("(%p)->(%p)\n", This, definitionNode);
1242 return E_NOTIMPL;
1246 static HRESULT WINAPI domdoc_get_nodeTypedValue(
1247 IXMLDOMDocument3 *iface,
1248 VARIANT* v )
1250 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1251 TRACE("(%p)->(%p)\n", This, v);
1252 return return_null_var(v);
1255 static HRESULT WINAPI domdoc_put_nodeTypedValue(
1256 IXMLDOMDocument3 *iface,
1257 VARIANT typedValue )
1259 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1260 FIXME("(%p)->(%s)\n", This, debugstr_variant(&typedValue));
1261 return E_NOTIMPL;
1265 static HRESULT WINAPI domdoc_get_dataType(
1266 IXMLDOMDocument3 *iface,
1267 VARIANT* typename )
1269 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1270 TRACE("(%p)->(%p)\n", This, typename);
1271 return return_null_var( typename );
1275 static HRESULT WINAPI domdoc_put_dataType(
1276 IXMLDOMDocument3 *iface,
1277 BSTR dataTypeName )
1279 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1281 FIXME("(%p)->(%s)\n", This, debugstr_w(dataTypeName));
1283 if(!dataTypeName)
1284 return E_INVALIDARG;
1286 return E_FAIL;
1289 static int XMLCALL domdoc_get_xml_writecallback(void *ctx, const char *data, int len)
1291 return xmlBufferAdd((xmlBufferPtr)ctx, (xmlChar*)data, len) == 0 ? len : 0;
1294 static HRESULT WINAPI domdoc_get_xml(
1295 IXMLDOMDocument3 *iface,
1296 BSTR* p)
1298 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1299 xmlSaveCtxtPtr ctxt;
1300 xmlBufferPtr buf;
1301 int options;
1302 long ret;
1304 TRACE("(%p)->(%p)\n", This, p);
1306 if(!p)
1307 return E_INVALIDARG;
1309 *p = NULL;
1311 buf = xmlBufferCreate();
1312 if(!buf)
1313 return E_OUTOFMEMORY;
1315 options = XML_SAVE_FORMAT | XML_SAVE_NO_DECL;
1316 ctxt = xmlSaveToIO(domdoc_get_xml_writecallback, NULL, buf, "UTF-8", options);
1318 if(!ctxt)
1320 xmlBufferFree(buf);
1321 return E_OUTOFMEMORY;
1324 ret = xmlSaveDoc(ctxt, get_doc(This));
1325 /* flushes on close */
1326 xmlSaveClose(ctxt);
1328 TRACE("%ld, len=%d\n", ret, xmlBufferLength(buf));
1329 if(ret != -1 && xmlBufferLength(buf) > 0)
1331 BSTR content;
1333 content = bstr_from_xmlChar(xmlBufferContent(buf));
1334 content = EnsureCorrectEOL(content);
1336 *p = content;
1338 else
1340 *p = SysAllocStringLen(NULL, 0);
1343 xmlBufferFree(buf);
1345 return *p ? S_OK : E_OUTOFMEMORY;
1349 static HRESULT WINAPI domdoc_transformNode(
1350 IXMLDOMDocument3 *iface,
1351 IXMLDOMNode *node,
1352 BSTR *p)
1354 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1355 TRACE("(%p)->(%p %p)\n", This, node, p);
1356 return node_transform_node(&This->node, node, p);
1360 static HRESULT WINAPI domdoc_selectNodes(
1361 IXMLDOMDocument3 *iface,
1362 BSTR p,
1363 IXMLDOMNodeList **outList)
1365 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1366 TRACE("(%p)->(%s %p)\n", This, debugstr_w(p), outList);
1367 return node_select_nodes(&This->node, p, outList);
1371 static HRESULT WINAPI domdoc_selectSingleNode(
1372 IXMLDOMDocument3 *iface,
1373 BSTR p,
1374 IXMLDOMNode **outNode)
1376 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1377 TRACE("(%p)->(%s %p)\n", This, debugstr_w(p), outNode);
1378 return node_select_singlenode(&This->node, p, outNode);
1382 static HRESULT WINAPI domdoc_get_parsed(
1383 IXMLDOMDocument3 *iface,
1384 VARIANT_BOOL* isParsed )
1386 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1387 FIXME("(%p)->(%p) stub!\n", This, isParsed);
1388 *isParsed = VARIANT_TRUE;
1389 return S_OK;
1392 static HRESULT WINAPI domdoc_get_namespaceURI(
1393 IXMLDOMDocument3 *iface,
1394 BSTR* namespaceURI )
1396 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1397 TRACE("(%p)->(%p)\n", This, namespaceURI);
1398 return return_null_bstr( namespaceURI );
1401 static HRESULT WINAPI domdoc_get_prefix(
1402 IXMLDOMDocument3 *iface,
1403 BSTR* prefix )
1405 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1406 TRACE("(%p)->(%p)\n", This, prefix);
1407 return return_null_bstr( prefix );
1411 static HRESULT WINAPI domdoc_get_baseName(
1412 IXMLDOMDocument3 *iface,
1413 BSTR* name )
1415 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1416 TRACE("(%p)->(%p)\n", This, name);
1417 return return_null_bstr( name );
1421 static HRESULT WINAPI domdoc_transformNodeToObject(
1422 IXMLDOMDocument3 *iface,
1423 IXMLDOMNode* stylesheet,
1424 VARIANT outputObject)
1426 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1427 FIXME("(%p)->(%p %s)\n", This, stylesheet, debugstr_variant(&outputObject));
1428 return E_NOTIMPL;
1432 static HRESULT WINAPI domdoc_get_doctype(
1433 IXMLDOMDocument3 *iface,
1434 IXMLDOMDocumentType** doctype )
1436 domdoc *This = impl_from_IXMLDOMDocument3(iface);
1437 IXMLDOMNode *node;
1438 xmlDtdPtr dtd;
1439 HRESULT hr;
1441 TRACE("(%p)->(%p)\n", This, doctype);
1443 if (!doctype) return E_INVALIDARG;
1445 *doctype = NULL;
1447 dtd = xmlGetIntSubset(get_doc(This));
1448 if (!dtd) return S_FALSE;
1450 node = create_node((xmlNodePtr)dtd);
1451 if (!node) return S_FALSE;
1453 hr = IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMDocumentType, (void**)doctype);
1454 IXMLDOMNode_Release(node);
1456 return hr;
1460 static HRESULT WINAPI domdoc_get_implementation(
1461 IXMLDOMDocument3 *iface,
1462 IXMLDOMImplementation** impl )
1464 domdoc *This = impl_from_IXMLDOMDocument3(iface);
1466 TRACE("(%p)->(%p)\n", This, impl);
1468 if(!impl)
1469 return E_INVALIDARG;
1471 *impl = (IXMLDOMImplementation*)create_doc_Implementation();
1473 return S_OK;
1476 static HRESULT WINAPI domdoc_get_documentElement(
1477 IXMLDOMDocument3 *iface,
1478 IXMLDOMElement** DOMElement )
1480 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1481 IXMLDOMNode *element_node;
1482 xmlNodePtr root;
1483 HRESULT hr;
1485 TRACE("(%p)->(%p)\n", This, DOMElement);
1487 if(!DOMElement)
1488 return E_INVALIDARG;
1490 *DOMElement = NULL;
1492 root = xmlDocGetRootElement( get_doc(This) );
1493 if ( !root )
1494 return S_FALSE;
1496 element_node = create_node( root );
1497 if(!element_node) return S_FALSE;
1499 hr = IXMLDOMNode_QueryInterface(element_node, &IID_IXMLDOMElement, (void**)DOMElement);
1500 IXMLDOMNode_Release(element_node);
1502 return hr;
1506 static HRESULT WINAPI domdoc_put_documentElement(
1507 IXMLDOMDocument3 *iface,
1508 IXMLDOMElement* DOMElement )
1510 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1511 IXMLDOMNode *elementNode;
1512 xmlNodePtr oldRoot;
1513 xmlnode *xmlNode;
1514 HRESULT hr;
1516 TRACE("(%p)->(%p)\n", This, DOMElement);
1518 hr = IXMLDOMElement_QueryInterface( DOMElement, &IID_IXMLDOMNode, (void**)&elementNode );
1519 if(FAILED(hr))
1520 return hr;
1522 xmlNode = get_node_obj( elementNode );
1523 if(!xmlNode) return E_FAIL;
1525 if(!xmlNode->node->parent)
1526 if(xmldoc_remove_orphan(xmlNode->node->doc, xmlNode->node) != S_OK)
1527 WARN("%p is not an orphan of %p\n", xmlNode->node->doc, xmlNode->node);
1529 oldRoot = xmlDocSetRootElement( get_doc(This), xmlNode->node);
1530 IXMLDOMNode_Release( elementNode );
1532 if(oldRoot)
1533 xmldoc_add_orphan(oldRoot->doc, oldRoot);
1535 return S_OK;
1539 static HRESULT WINAPI domdoc_createElement(
1540 IXMLDOMDocument3 *iface,
1541 BSTR tagname,
1542 IXMLDOMElement** element )
1544 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1545 IXMLDOMNode *node;
1546 VARIANT type;
1547 HRESULT hr;
1549 TRACE("(%p)->(%s %p)\n", This, debugstr_w(tagname), element);
1551 if (!element || !tagname) return E_INVALIDARG;
1553 V_VT(&type) = VT_I1;
1554 V_I1(&type) = NODE_ELEMENT;
1556 hr = IXMLDOMDocument3_createNode(iface, type, tagname, NULL, &node);
1557 if (hr == S_OK)
1559 IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMElement, (void**)element);
1560 IXMLDOMNode_Release(node);
1563 return hr;
1567 static HRESULT WINAPI domdoc_createDocumentFragment(
1568 IXMLDOMDocument3 *iface,
1569 IXMLDOMDocumentFragment** frag )
1571 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1572 IXMLDOMNode *node;
1573 VARIANT type;
1574 HRESULT hr;
1576 TRACE("(%p)->(%p)\n", This, frag);
1578 if (!frag) return E_INVALIDARG;
1580 *frag = NULL;
1582 V_VT(&type) = VT_I1;
1583 V_I1(&type) = NODE_DOCUMENT_FRAGMENT;
1585 hr = IXMLDOMDocument3_createNode(iface, type, NULL, NULL, &node);
1586 if (hr == S_OK)
1588 IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMDocumentFragment, (void**)frag);
1589 IXMLDOMNode_Release(node);
1592 return hr;
1596 static HRESULT WINAPI domdoc_createTextNode(
1597 IXMLDOMDocument3 *iface,
1598 BSTR data,
1599 IXMLDOMText** text )
1601 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1602 IXMLDOMNode *node;
1603 VARIANT type;
1604 HRESULT hr;
1606 TRACE("(%p)->(%s %p)\n", This, debugstr_w(data), text);
1608 if (!text) return E_INVALIDARG;
1610 *text = NULL;
1612 V_VT(&type) = VT_I1;
1613 V_I1(&type) = NODE_TEXT;
1615 hr = IXMLDOMDocument3_createNode(iface, type, NULL, NULL, &node);
1616 if (hr == S_OK)
1618 IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMText, (void**)text);
1619 IXMLDOMNode_Release(node);
1620 hr = IXMLDOMText_put_data(*text, data);
1623 return hr;
1627 static HRESULT WINAPI domdoc_createComment(
1628 IXMLDOMDocument3 *iface,
1629 BSTR data,
1630 IXMLDOMComment** comment )
1632 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1633 VARIANT type;
1634 HRESULT hr;
1635 IXMLDOMNode *node;
1637 TRACE("(%p)->(%s %p)\n", This, debugstr_w(data), comment);
1639 if (!comment) return E_INVALIDARG;
1641 *comment = NULL;
1643 V_VT(&type) = VT_I1;
1644 V_I1(&type) = NODE_COMMENT;
1646 hr = IXMLDOMDocument3_createNode(iface, type, NULL, NULL, &node);
1647 if (hr == S_OK)
1649 IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMComment, (void**)comment);
1650 IXMLDOMNode_Release(node);
1651 hr = IXMLDOMComment_put_data(*comment, data);
1654 return hr;
1658 static HRESULT WINAPI domdoc_createCDATASection(
1659 IXMLDOMDocument3 *iface,
1660 BSTR data,
1661 IXMLDOMCDATASection** cdata )
1663 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1664 IXMLDOMNode *node;
1665 VARIANT type;
1666 HRESULT hr;
1668 TRACE("(%p)->(%s %p)\n", This, debugstr_w(data), cdata);
1670 if (!cdata) return E_INVALIDARG;
1672 *cdata = NULL;
1674 V_VT(&type) = VT_I1;
1675 V_I1(&type) = NODE_CDATA_SECTION;
1677 hr = IXMLDOMDocument3_createNode(iface, type, NULL, NULL, &node);
1678 if (hr == S_OK)
1680 IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMCDATASection, (void**)cdata);
1681 IXMLDOMNode_Release(node);
1682 hr = IXMLDOMCDATASection_put_data(*cdata, data);
1685 return hr;
1689 static HRESULT WINAPI domdoc_createProcessingInstruction(
1690 IXMLDOMDocument3 *iface,
1691 BSTR target,
1692 BSTR data,
1693 IXMLDOMProcessingInstruction** pi )
1695 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1696 IXMLDOMNode *node;
1697 VARIANT type;
1698 HRESULT hr;
1700 TRACE("(%p)->(%s %s %p)\n", This, debugstr_w(target), debugstr_w(data), pi);
1702 if (!pi) return E_INVALIDARG;
1704 *pi = NULL;
1706 V_VT(&type) = VT_I1;
1707 V_I1(&type) = NODE_PROCESSING_INSTRUCTION;
1709 hr = IXMLDOMDocument3_createNode(iface, type, target, NULL, &node);
1710 if (hr == S_OK)
1712 xmlnode *node_obj;
1714 /* this is to bypass check in ::put_data() that blocks "<?xml" PIs */
1715 node_obj = get_node_obj(node);
1716 hr = node_set_content(node_obj, data);
1718 IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMProcessingInstruction, (void**)pi);
1719 IXMLDOMNode_Release(node);
1722 return hr;
1726 static HRESULT WINAPI domdoc_createAttribute(
1727 IXMLDOMDocument3 *iface,
1728 BSTR name,
1729 IXMLDOMAttribute** attribute )
1731 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1732 IXMLDOMNode *node;
1733 VARIANT type;
1734 HRESULT hr;
1736 TRACE("(%p)->(%s %p)\n", This, debugstr_w(name), attribute);
1738 if (!attribute || !name) return E_INVALIDARG;
1740 V_VT(&type) = VT_I1;
1741 V_I1(&type) = NODE_ATTRIBUTE;
1743 hr = IXMLDOMDocument3_createNode(iface, type, name, NULL, &node);
1744 if (hr == S_OK)
1746 IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMAttribute, (void**)attribute);
1747 IXMLDOMNode_Release(node);
1750 return hr;
1754 static HRESULT WINAPI domdoc_createEntityReference(
1755 IXMLDOMDocument3 *iface,
1756 BSTR name,
1757 IXMLDOMEntityReference** entityref )
1759 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1760 IXMLDOMNode *node;
1761 VARIANT type;
1762 HRESULT hr;
1764 TRACE("(%p)->(%s %p)\n", This, debugstr_w(name), entityref);
1766 if (!entityref) return E_INVALIDARG;
1768 *entityref = NULL;
1770 V_VT(&type) = VT_I1;
1771 V_I1(&type) = NODE_ENTITY_REFERENCE;
1773 hr = IXMLDOMDocument3_createNode(iface, type, name, NULL, &node);
1774 if (hr == S_OK)
1776 IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMEntityReference, (void**)entityref);
1777 IXMLDOMNode_Release(node);
1780 return hr;
1783 xmlChar* tagName_to_XPath(const BSTR tagName)
1785 xmlChar *query, *tmp;
1786 static const xmlChar mod_pre[] = "*[local-name()='";
1787 static const xmlChar mod_post[] = "']";
1788 static const xmlChar prefix[] = "descendant::";
1789 const WCHAR *tokBegin, *tokEnd;
1790 int len;
1792 query = xmlStrdup(prefix);
1794 tokBegin = tagName;
1795 while (tokBegin && *tokBegin)
1797 switch (*tokBegin)
1799 case '/':
1800 query = xmlStrcat(query, BAD_CAST "/");
1801 ++tokBegin;
1802 break;
1803 case '*':
1804 query = xmlStrcat(query, BAD_CAST "*");
1805 ++tokBegin;
1806 break;
1807 default:
1808 query = xmlStrcat(query, mod_pre);
1809 tokEnd = tokBegin;
1810 while (*tokEnd && *tokEnd != '/')
1811 ++tokEnd;
1812 len = WideCharToMultiByte(CP_UTF8, 0, tokBegin, tokEnd-tokBegin, NULL, 0, NULL, NULL);
1813 tmp = xmlMalloc(len);
1814 WideCharToMultiByte(CP_UTF8, 0, tokBegin, tokEnd-tokBegin, (char*)tmp, len, NULL, NULL);
1815 query = xmlStrncat(query, tmp, len);
1816 xmlFree(tmp);
1817 tokBegin = tokEnd;
1818 query = xmlStrcat(query, mod_post);
1822 return query;
1825 static HRESULT WINAPI domdoc_getElementsByTagName(
1826 IXMLDOMDocument3 *iface,
1827 BSTR tagName,
1828 IXMLDOMNodeList** resultList )
1830 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1831 xmlChar *query;
1832 HRESULT hr;
1833 BOOL XPath;
1835 TRACE("(%p)->(%s, %p)\n", This, debugstr_w(tagName), resultList);
1837 if (!tagName || !resultList) return E_INVALIDARG;
1839 XPath = This->properties->XPath;
1840 This->properties->XPath = TRUE;
1841 query = tagName_to_XPath(tagName);
1842 hr = create_selection((xmlNodePtr)get_doc(This), query, resultList);
1843 xmlFree(query);
1844 This->properties->XPath = XPath;
1846 return hr;
1849 static HRESULT get_node_type(VARIANT Type, DOMNodeType * type)
1851 VARIANT tmp;
1852 HRESULT hr;
1854 VariantInit(&tmp);
1855 hr = VariantChangeType(&tmp, &Type, 0, VT_I4);
1856 if(FAILED(hr))
1857 return E_INVALIDARG;
1859 *type = V_I4(&tmp);
1861 return S_OK;
1864 static HRESULT WINAPI domdoc_createNode(
1865 IXMLDOMDocument3 *iface,
1866 VARIANT Type,
1867 BSTR name,
1868 BSTR namespaceURI,
1869 IXMLDOMNode** node )
1871 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1872 DOMNodeType node_type;
1873 xmlNodePtr xmlnode;
1874 xmlChar *xml_name, *href;
1875 HRESULT hr;
1877 TRACE("(%p)->(%s %s %s %p)\n", This, debugstr_variant(&Type), debugstr_w(name), debugstr_w(namespaceURI), node);
1879 if(!node) return E_INVALIDARG;
1881 hr = get_node_type(Type, &node_type);
1882 if(FAILED(hr)) return hr;
1884 if(namespaceURI && namespaceURI[0] && node_type != NODE_ELEMENT)
1885 FIXME("nodes with namespaces currently not supported.\n");
1887 TRACE("node_type %d\n", node_type);
1889 /* exit earlier for types that need name */
1890 switch(node_type)
1892 case NODE_ELEMENT:
1893 case NODE_ATTRIBUTE:
1894 case NODE_ENTITY_REFERENCE:
1895 case NODE_PROCESSING_INSTRUCTION:
1896 if (!name || *name == 0) return E_FAIL;
1897 break;
1898 default:
1899 break;
1902 xml_name = xmlchar_from_wchar(name);
1903 /* prevent empty href to be allocated */
1904 href = namespaceURI ? xmlchar_from_wchar(namespaceURI) : NULL;
1906 switch(node_type)
1908 case NODE_ELEMENT:
1910 xmlChar *local, *prefix;
1912 local = xmlSplitQName2(xml_name, &prefix);
1914 xmlnode = xmlNewDocNode(get_doc(This), NULL, local ? local : xml_name, NULL);
1916 /* allow to create default namespace xmlns= */
1917 if (local || (href && *href))
1919 xmlNsPtr ns = xmlNewNs(xmlnode, href, prefix);
1920 xmlSetNs(xmlnode, ns);
1923 xmlFree(local);
1924 xmlFree(prefix);
1926 break;
1928 case NODE_ATTRIBUTE:
1929 xmlnode = (xmlNodePtr)xmlNewDocProp(get_doc(This), xml_name, NULL);
1930 break;
1931 case NODE_TEXT:
1932 xmlnode = (xmlNodePtr)xmlNewDocText(get_doc(This), NULL);
1933 break;
1934 case NODE_CDATA_SECTION:
1935 xmlnode = xmlNewCDataBlock(get_doc(This), NULL, 0);
1936 break;
1937 case NODE_ENTITY_REFERENCE:
1938 xmlnode = xmlNewReference(get_doc(This), xml_name);
1939 break;
1940 case NODE_PROCESSING_INSTRUCTION:
1941 #ifdef HAVE_XMLNEWDOCPI
1942 xmlnode = xmlNewDocPI(get_doc(This), xml_name, NULL);
1943 #else
1944 FIXME("xmlNewDocPI() not supported, use libxml2 2.6.15 or greater\n");
1945 xmlnode = NULL;
1946 #endif
1947 break;
1948 case NODE_COMMENT:
1949 xmlnode = xmlNewDocComment(get_doc(This), NULL);
1950 break;
1951 case NODE_DOCUMENT_FRAGMENT:
1952 xmlnode = xmlNewDocFragment(get_doc(This));
1953 break;
1954 /* unsupported types */
1955 case NODE_DOCUMENT:
1956 case NODE_DOCUMENT_TYPE:
1957 case NODE_ENTITY:
1958 case NODE_NOTATION:
1959 heap_free(xml_name);
1960 return E_INVALIDARG;
1961 default:
1962 FIXME("unhandled node type %d\n", node_type);
1963 xmlnode = NULL;
1964 break;
1967 *node = create_node(xmlnode);
1968 heap_free(xml_name);
1969 heap_free(href);
1971 if(*node)
1973 TRACE("created node (%d, %p, %p)\n", node_type, *node, xmlnode);
1974 xmldoc_add_orphan(xmlnode->doc, xmlnode);
1975 return S_OK;
1978 return E_FAIL;
1981 static HRESULT WINAPI domdoc_nodeFromID(
1982 IXMLDOMDocument3 *iface,
1983 BSTR idString,
1984 IXMLDOMNode** node )
1986 domdoc *This = impl_from_IXMLDOMDocument3(iface);
1987 FIXME("(%p)->(%s %p)\n", This, debugstr_w(idString), node);
1988 return E_NOTIMPL;
1991 static HRESULT domdoc_onDataAvailable(void *obj, char *ptr, DWORD len)
1993 domdoc *This = obj;
1994 xmlDocPtr xmldoc;
1996 xmldoc = doparse(This, ptr, len, XML_CHAR_ENCODING_NONE);
1997 if(xmldoc) {
1998 xmldoc->_private = create_priv();
1999 return attach_xmldoc(This, xmldoc);
2002 return S_OK;
2005 static HRESULT domdoc_load_moniker(domdoc *This, IMoniker *mon)
2007 bsc_t *bsc;
2008 HRESULT hr;
2010 hr = bind_url(mon, domdoc_onDataAvailable, This, &bsc);
2011 if(FAILED(hr))
2012 return hr;
2014 if(This->bsc) {
2015 hr = detach_bsc(This->bsc);
2016 if(FAILED(hr))
2017 return hr;
2020 This->bsc = bsc;
2021 return S_OK;
2024 static HRESULT WINAPI domdoc_load(
2025 IXMLDOMDocument3 *iface,
2026 VARIANT source,
2027 VARIANT_BOOL* isSuccessful )
2029 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2030 LPWSTR filename = NULL;
2031 HRESULT hr = S_FALSE;
2032 xmlDocPtr xmldoc;
2034 TRACE("(%p)->(%s)\n", This, debugstr_variant(&source));
2036 if (!isSuccessful)
2037 return E_POINTER;
2038 *isSuccessful = VARIANT_FALSE;
2040 assert( &This->node );
2042 switch( V_VT(&source) )
2044 case VT_BSTR:
2045 filename = V_BSTR(&source);
2046 break;
2047 case VT_BSTR|VT_BYREF:
2048 if (!V_BSTRREF(&source)) return E_INVALIDARG;
2049 filename = *V_BSTRREF(&source);
2050 break;
2051 case VT_ARRAY|VT_UI1:
2053 SAFEARRAY *psa = V_ARRAY(&source);
2054 char *str;
2055 LONG len;
2056 UINT dim = SafeArrayGetDim(psa);
2058 switch (dim)
2060 case 0:
2061 ERR("SAFEARRAY == NULL\n");
2062 hr = This->error = E_INVALIDARG;
2063 break;
2064 case 1:
2065 /* Only takes UTF-8 strings.
2066 * NOT NULL-terminated. */
2067 SafeArrayAccessData(psa, (void**)&str);
2068 SafeArrayGetUBound(psa, 1, &len);
2070 if ((xmldoc = doparse(This, str, ++len, XML_CHAR_ENCODING_UTF8)))
2072 hr = This->error = S_OK;
2073 *isSuccessful = VARIANT_TRUE;
2074 TRACE("parsed document %p\n", xmldoc);
2076 else
2078 This->error = E_FAIL;
2079 TRACE("failed to parse document\n");
2082 SafeArrayUnaccessData(psa);
2084 if(xmldoc)
2086 xmldoc->_private = create_priv();
2087 return attach_xmldoc(This, xmldoc);
2089 break;
2090 default:
2091 FIXME("unhandled SAFEARRAY dim: %d\n", dim);
2092 hr = This->error = E_NOTIMPL;
2095 break;
2096 case VT_UNKNOWN:
2098 ISequentialStream *stream = NULL;
2099 IXMLDOMDocument3 *newdoc = NULL;
2101 if (!V_UNKNOWN(&source)) return E_INVALIDARG;
2103 hr = IUnknown_QueryInterface(V_UNKNOWN(&source), &IID_IXMLDOMDocument3, (void**)&newdoc);
2104 if(hr == S_OK)
2106 if(newdoc)
2108 domdoc *newDoc = impl_from_IXMLDOMDocument3( newdoc );
2110 xmldoc = xmlCopyDoc(get_doc(newDoc), 1);
2111 xmldoc->_private = create_priv();
2112 hr = attach_xmldoc(This, xmldoc);
2114 if(SUCCEEDED(hr))
2115 *isSuccessful = VARIANT_TRUE;
2117 return hr;
2121 hr = IUnknown_QueryInterface(V_UNKNOWN(&source), &IID_IStream, (void**)&stream);
2122 if (FAILED(hr))
2123 hr = IUnknown_QueryInterface(V_UNKNOWN(&source), &IID_ISequentialStream, (void**)&stream);
2125 if (hr == S_OK)
2127 hr = domdoc_load_from_stream(This, stream);
2128 if (hr == S_OK)
2129 *isSuccessful = VARIANT_TRUE;
2130 ISequentialStream_Release(stream);
2131 return hr;
2134 FIXME("unsupported IUnknown type (0x%08x) (%p)\n", hr, V_UNKNOWN(&source)->lpVtbl);
2135 break;
2137 default:
2138 FIXME("VT type not supported (%d)\n", V_VT(&source));
2141 if ( filename )
2143 IMoniker *mon;
2145 hr = create_moniker_from_url( filename, &mon);
2146 if ( SUCCEEDED(hr) )
2148 hr = domdoc_load_moniker( This, mon );
2149 IMoniker_Release(mon);
2152 if ( FAILED(hr) )
2153 This->error = E_FAIL;
2154 else
2156 hr = This->error = S_OK;
2157 *isSuccessful = VARIANT_TRUE;
2161 if(!filename || FAILED(hr)) {
2162 xmldoc = xmlNewDoc(NULL);
2163 xmldoc->_private = create_priv();
2164 hr = attach_xmldoc(This, xmldoc);
2165 if(SUCCEEDED(hr))
2166 hr = S_FALSE;
2169 TRACE("ret (%d)\n", hr);
2171 return hr;
2175 static HRESULT WINAPI domdoc_get_readyState(
2176 IXMLDOMDocument3 *iface,
2177 LONG *value )
2179 domdoc *This = impl_from_IXMLDOMDocument3(iface);
2180 FIXME("stub! (%p)->(%p)\n", This, value);
2182 if (!value)
2183 return E_INVALIDARG;
2185 *value = READYSTATE_COMPLETE;
2186 return S_OK;
2190 static HRESULT WINAPI domdoc_get_parseError(
2191 IXMLDOMDocument3 *iface,
2192 IXMLDOMParseError** errorObj )
2194 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2195 static const WCHAR err[] = {'e','r','r','o','r',0};
2196 BSTR error_string = NULL;
2198 FIXME("(%p)->(%p): creating a dummy parseError\n", iface, errorObj);
2200 if(This->error)
2201 error_string = SysAllocString(err);
2203 *errorObj = create_parseError(This->error, NULL, error_string, NULL, 0, 0, 0);
2204 if(!*errorObj) return E_OUTOFMEMORY;
2205 return S_OK;
2209 static HRESULT WINAPI domdoc_get_url(
2210 IXMLDOMDocument3 *iface,
2211 BSTR* urlString )
2213 domdoc *This = impl_from_IXMLDOMDocument3(iface);
2214 FIXME("(%p)->(%p)\n", This, urlString);
2215 return E_NOTIMPL;
2219 static HRESULT WINAPI domdoc_get_async(
2220 IXMLDOMDocument3 *iface,
2221 VARIANT_BOOL* isAsync )
2223 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2225 TRACE("(%p)->(%p: %d)\n", This, isAsync, This->async);
2226 *isAsync = This->async;
2227 return S_OK;
2231 static HRESULT WINAPI domdoc_put_async(
2232 IXMLDOMDocument3 *iface,
2233 VARIANT_BOOL isAsync )
2235 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2237 TRACE("(%p)->(%d)\n", This, isAsync);
2238 This->async = isAsync;
2239 return S_OK;
2243 static HRESULT WINAPI domdoc_abort(
2244 IXMLDOMDocument3 *iface )
2246 domdoc *This = impl_from_IXMLDOMDocument3(iface);
2247 FIXME("%p\n", This);
2248 return E_NOTIMPL;
2251 /* don't rely on data to be in BSTR format, treat it as WCHAR string */
2252 static HRESULT WINAPI domdoc_loadXML(
2253 IXMLDOMDocument3 *iface,
2254 BSTR data,
2255 VARIANT_BOOL* isSuccessful )
2257 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2258 xmlDocPtr xmldoc = NULL;
2259 HRESULT hr = S_FALSE, hr2;
2261 TRACE("(%p)->(%s %p)\n", This, debugstr_w(data), isSuccessful );
2263 assert ( &This->node );
2265 if ( isSuccessful )
2267 *isSuccessful = VARIANT_FALSE;
2269 if (data)
2271 WCHAR *ptr = data;
2273 /* skip leading spaces if needed */
2274 if (This->properties->version == MSXML_DEFAULT || This->properties->version == MSXML26)
2275 while (*ptr && isspaceW(*ptr)) ptr++;
2277 xmldoc = doparse(This, (char*)ptr, strlenW(ptr)*sizeof(WCHAR), XML_CHAR_ENCODING_UTF16LE);
2278 if ( !xmldoc )
2280 This->error = E_FAIL;
2281 TRACE("failed to parse document\n");
2283 else
2285 hr = This->error = S_OK;
2286 *isSuccessful = VARIANT_TRUE;
2287 TRACE("parsed document %p\n", xmldoc);
2292 if(!xmldoc)
2293 xmldoc = xmlNewDoc(NULL);
2294 xmldoc->_private = create_priv();
2295 hr2 = attach_xmldoc(This, xmldoc);
2296 if( FAILED(hr2) )
2297 hr = hr2;
2299 return hr;
2302 static int XMLCALL domdoc_save_writecallback(void *ctx, const char *buffer, int len)
2304 DWORD written = -1;
2306 if(!WriteFile(ctx, buffer, len, &written, NULL))
2308 WARN("write error\n");
2309 return -1;
2311 else
2312 return written;
2315 static int XMLCALL domdoc_save_closecallback(void *ctx)
2317 return CloseHandle(ctx) ? 0 : -1;
2320 static int XMLCALL domdoc_stream_save_writecallback(void *ctx, const char *buffer, int len)
2322 ULONG written = 0;
2323 HRESULT hr;
2325 hr = IStream_Write((IStream*)ctx, buffer, len, &written);
2326 TRACE("0x%08x %p %d %u\n", hr, buffer, len, written);
2327 if (hr != S_OK)
2329 WARN("stream write error: 0x%08x\n", hr);
2330 return -1;
2332 else
2333 return len;
2336 static int XMLCALL domdoc_stream_save_closecallback(void *ctx)
2338 IStream_Release((IStream*)ctx);
2339 return 0;
2342 static HRESULT WINAPI domdoc_save(
2343 IXMLDOMDocument3 *iface,
2344 VARIANT destination )
2346 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2347 xmlSaveCtxtPtr ctx = NULL;
2348 xmlNodePtr xmldecl;
2349 HRESULT ret = S_OK;
2351 TRACE("(%p)->(%s)\n", This, debugstr_variant(&destination));
2353 switch (V_VT(&destination))
2355 case VT_UNKNOWN:
2357 IUnknown *pUnk = V_UNKNOWN(&destination);
2358 IXMLDOMDocument3 *document;
2359 IStream *stream;
2361 ret = IUnknown_QueryInterface(pUnk, &IID_IXMLDOMDocument3, (void**)&document);
2362 if(ret == S_OK)
2364 VARIANT_BOOL success;
2365 BSTR xml;
2367 ret = IXMLDOMDocument3_get_xml(iface, &xml);
2368 if(ret == S_OK)
2370 ret = IXMLDOMDocument3_loadXML(document, xml, &success);
2371 SysFreeString(xml);
2374 IXMLDOMDocument3_Release(document);
2375 return ret;
2378 ret = IUnknown_QueryInterface(pUnk, &IID_IStream, (void**)&stream);
2379 if(ret == S_OK)
2381 int options = get_doc(This)->standalone == -1 ? XML_SAVE_NO_DECL : 0;
2382 ctx = xmlSaveToIO(domdoc_stream_save_writecallback,
2383 domdoc_stream_save_closecallback, stream, NULL, options);
2385 if(!ctx)
2387 IStream_Release(stream);
2388 return E_FAIL;
2392 break;
2394 case VT_BSTR:
2395 case VT_BSTR | VT_BYREF:
2397 int options = get_doc(This)->standalone == -1 ? XML_SAVE_NO_DECL : 0;
2399 /* save with file path */
2400 HANDLE handle = CreateFileW( (V_VT(&destination) & VT_BYREF)? *V_BSTRREF(&destination) : V_BSTR(&destination),
2401 GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL );
2402 if( handle == INVALID_HANDLE_VALUE )
2404 WARN("failed to create file\n");
2405 return E_FAIL;
2408 /* disable top XML declaration */
2409 ctx = xmlSaveToIO(domdoc_save_writecallback, domdoc_save_closecallback,
2410 handle, NULL, options);
2411 if (!ctx)
2413 CloseHandle(handle);
2414 return E_FAIL;
2417 break;
2419 default:
2420 FIXME("Unhandled VARIANT: %s\n", debugstr_variant(&destination));
2421 return S_FALSE;
2424 xmldecl = xmldoc_unlink_xmldecl(get_doc(This));
2425 if (xmlSaveDoc(ctx, get_doc(This)) == -1) ret = S_FALSE;
2426 xmldoc_link_xmldecl(get_doc(This), xmldecl);
2428 /* will release resources through close callback */
2429 xmlSaveClose(ctx);
2431 return ret;
2434 static HRESULT WINAPI domdoc_get_validateOnParse(
2435 IXMLDOMDocument3 *iface,
2436 VARIANT_BOOL* isValidating )
2438 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2439 TRACE("(%p)->(%p: %d)\n", This, isValidating, This->validating);
2440 *isValidating = This->validating;
2441 return S_OK;
2445 static HRESULT WINAPI domdoc_put_validateOnParse(
2446 IXMLDOMDocument3 *iface,
2447 VARIANT_BOOL isValidating )
2449 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2450 TRACE("(%p)->(%d)\n", This, isValidating);
2451 This->validating = isValidating;
2452 return S_OK;
2456 static HRESULT WINAPI domdoc_get_resolveExternals(
2457 IXMLDOMDocument3 *iface,
2458 VARIANT_BOOL* isResolving )
2460 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2461 TRACE("(%p)->(%p: %d)\n", This, isResolving, This->resolving);
2462 *isResolving = This->resolving;
2463 return S_OK;
2467 static HRESULT WINAPI domdoc_put_resolveExternals(
2468 IXMLDOMDocument3 *iface,
2469 VARIANT_BOOL isResolving )
2471 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2472 TRACE("(%p)->(%d)\n", This, isResolving);
2473 This->resolving = isResolving;
2474 return S_OK;
2478 static HRESULT WINAPI domdoc_get_preserveWhiteSpace(
2479 IXMLDOMDocument3 *iface,
2480 VARIANT_BOOL* isPreserving )
2482 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2483 TRACE("(%p)->(%p: %d)\n", This, isPreserving, This->properties->preserving);
2484 *isPreserving = This->properties->preserving;
2485 return S_OK;
2489 static HRESULT WINAPI domdoc_put_preserveWhiteSpace(
2490 IXMLDOMDocument3 *iface,
2491 VARIANT_BOOL isPreserving )
2493 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2494 TRACE("(%p)->(%d)\n", This, isPreserving);
2495 This->properties->preserving = isPreserving;
2496 return S_OK;
2500 static HRESULT WINAPI domdoc_put_onreadystatechange(
2501 IXMLDOMDocument3 *iface,
2502 VARIANT event )
2504 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2506 TRACE("(%p)->(%s)\n", This, debugstr_variant(&event));
2507 return set_doc_event(This, EVENTID_READYSTATECHANGE, &event);
2511 static HRESULT WINAPI domdoc_put_onDataAvailable(IXMLDOMDocument3 *iface, VARIANT sink)
2513 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2514 FIXME("(%p)->(%s): stub\n", This, debugstr_variant(&sink));
2515 return E_NOTIMPL;
2518 static HRESULT WINAPI domdoc_put_onTransformNode(IXMLDOMDocument3 *iface, VARIANT sink )
2520 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2521 FIXME("(%p)->(%s): stub\n", This, debugstr_variant(&sink));
2522 return E_NOTIMPL;
2525 static HRESULT WINAPI domdoc_get_namespaces(
2526 IXMLDOMDocument3* iface,
2527 IXMLDOMSchemaCollection** collection )
2529 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2530 HRESULT hr;
2532 FIXME("(%p)->(%p): semi-stub\n", This, collection);
2534 if (!collection) return E_POINTER;
2536 if (!This->namespaces)
2538 hr = SchemaCache_create(This->properties->version, NULL, (void**)&This->namespaces);
2539 if (hr != S_OK) return hr;
2541 hr = cache_from_doc_ns(This->namespaces, &This->node);
2542 if (hr != S_OK)
2543 release_namespaces(This);
2546 if (This->namespaces)
2547 return IXMLDOMSchemaCollection2_QueryInterface(This->namespaces,
2548 &IID_IXMLDOMSchemaCollection, (void**)collection);
2550 return hr;
2553 static HRESULT WINAPI domdoc_get_schemas(
2554 IXMLDOMDocument3* iface,
2555 VARIANT* schema )
2557 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2558 IXMLDOMSchemaCollection2* cur_schema = This->properties->schemaCache;
2559 HRESULT hr = S_FALSE;
2561 TRACE("(%p)->(%p)\n", This, schema);
2563 V_VT(schema) = VT_NULL;
2564 /* just to reset pointer part, cause that's what application is expected to use */
2565 V_DISPATCH(schema) = NULL;
2567 if(cur_schema)
2569 hr = IXMLDOMSchemaCollection2_QueryInterface(cur_schema, &IID_IDispatch, (void**)&V_DISPATCH(schema));
2570 if(SUCCEEDED(hr))
2571 V_VT(schema) = VT_DISPATCH;
2573 return hr;
2576 static HRESULT WINAPI domdoc_putref_schemas(
2577 IXMLDOMDocument3* iface,
2578 VARIANT schema)
2580 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2581 HRESULT hr = E_FAIL;
2582 IXMLDOMSchemaCollection2* new_schema = NULL;
2584 FIXME("(%p)->(%s): semi-stub\n", This, debugstr_variant(&schema));
2585 switch(V_VT(&schema))
2587 case VT_UNKNOWN:
2588 if (V_UNKNOWN(&schema))
2590 hr = IUnknown_QueryInterface(V_UNKNOWN(&schema), &IID_IXMLDOMSchemaCollection, (void**)&new_schema);
2591 break;
2593 /* fallthrough */
2594 case VT_DISPATCH:
2595 if (V_DISPATCH(&schema))
2597 hr = IDispatch_QueryInterface(V_DISPATCH(&schema), &IID_IXMLDOMSchemaCollection, (void**)&new_schema);
2598 break;
2600 /* fallthrough */
2601 case VT_NULL:
2602 case VT_EMPTY:
2603 hr = S_OK;
2604 break;
2606 default:
2607 WARN("Can't get schema from vt %x\n", V_VT(&schema));
2610 if(SUCCEEDED(hr))
2612 IXMLDOMSchemaCollection2* old_schema = InterlockedExchangePointer((void**)&This->properties->schemaCache, new_schema);
2613 if(old_schema) IXMLDOMSchemaCollection2_Release(old_schema);
2616 return hr;
2619 static inline BOOL is_wellformed(xmlDocPtr doc)
2621 #ifdef HAVE_XMLDOC_PROPERTIES
2622 return doc->properties & XML_DOC_WELLFORMED;
2623 #else
2624 /* Not a full check, but catches the worst violations */
2625 xmlNodePtr child;
2626 int root = 0;
2628 for (child = doc->children; child != NULL; child = child->next)
2630 switch (child->type)
2632 case XML_ELEMENT_NODE:
2633 if (++root > 1)
2634 return FALSE;
2635 break;
2636 case XML_TEXT_NODE:
2637 case XML_CDATA_SECTION_NODE:
2638 return FALSE;
2639 break;
2640 default:
2641 break;
2645 return root == 1;
2646 #endif
2649 static void LIBXML2_LOG_CALLBACK validate_error(void* ctx, char const* msg, ...)
2651 va_list ap;
2652 va_start(ap, msg);
2653 LIBXML2_CALLBACK_ERR(domdoc_validateNode, msg, ap);
2654 va_end(ap);
2657 static void LIBXML2_LOG_CALLBACK validate_warning(void* ctx, char const* msg, ...)
2659 va_list ap;
2660 va_start(ap, msg);
2661 LIBXML2_CALLBACK_WARN(domdoc_validateNode, msg, ap);
2662 va_end(ap);
2665 static HRESULT WINAPI domdoc_validateNode(
2666 IXMLDOMDocument3* iface,
2667 IXMLDOMNode* node,
2668 IXMLDOMParseError** err)
2670 domdoc* This = impl_from_IXMLDOMDocument3(iface);
2671 LONG state, err_code = 0;
2672 HRESULT hr = S_OK;
2673 int validated = 0;
2675 TRACE("(%p)->(%p, %p)\n", This, node, err);
2676 IXMLDOMDocument3_get_readyState(iface, &state);
2677 if (state != READYSTATE_COMPLETE)
2679 if (err)
2680 *err = create_parseError(err_code, NULL, NULL, NULL, 0, 0, 0);
2681 return E_PENDING;
2684 if (!node)
2686 if (err)
2687 *err = create_parseError(err_code, NULL, NULL, NULL, 0, 0, 0);
2688 return E_POINTER;
2691 if (!get_node_obj(node)->node || get_node_obj(node)->node->doc != get_doc(This))
2693 if (err)
2694 *err = create_parseError(err_code, NULL, NULL, NULL, 0, 0, 0);
2695 return E_FAIL;
2698 if (!is_wellformed(get_doc(This)))
2700 ERR("doc not well-formed\n");
2701 if (err)
2702 *err = create_parseError(E_XML_NOTWF, NULL, NULL, NULL, 0, 0, 0);
2703 return S_FALSE;
2706 /* DTD validation */
2707 if (get_doc(This)->intSubset || get_doc(This)->extSubset)
2709 xmlValidCtxtPtr vctx = xmlNewValidCtxt();
2710 vctx->error = validate_error;
2711 vctx->warning = validate_warning;
2712 ++validated;
2714 if (!((node == (IXMLDOMNode*)iface)?
2715 xmlValidateDocument(vctx, get_doc(This)) :
2716 xmlValidateElement(vctx, get_doc(This), get_node_obj(node)->node)))
2718 /* TODO: get a real error code here */
2719 TRACE("DTD validation failed\n");
2720 err_code = E_XML_INVALID;
2721 hr = S_FALSE;
2723 xmlFreeValidCtxt(vctx);
2726 /* Schema validation */
2727 if (hr == S_OK && This->properties->schemaCache != NULL)
2730 hr = SchemaCache_validate_tree(This->properties->schemaCache, get_node_obj(node)->node);
2731 if (SUCCEEDED(hr))
2733 ++validated;
2734 /* TODO: get a real error code here */
2735 if (hr == S_OK)
2737 TRACE("schema validation succeeded\n");
2739 else
2741 ERR("schema validation failed\n");
2742 err_code = E_XML_INVALID;
2745 else
2747 /* not really OK, just didn't find a schema for the ns */
2748 hr = S_OK;
2752 if (!validated)
2754 ERR("no DTD or schema found\n");
2755 err_code = E_XML_NODTD;
2756 hr = S_FALSE;
2759 if (err)
2760 *err = create_parseError(err_code, NULL, NULL, NULL, 0, 0, 0);
2762 return hr;
2765 static HRESULT WINAPI domdoc_validate(
2766 IXMLDOMDocument3* iface,
2767 IXMLDOMParseError** err)
2769 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2770 TRACE("(%p)->(%p)\n", This, err);
2771 return IXMLDOMDocument3_validateNode(iface, (IXMLDOMNode*)iface, err);
2774 static HRESULT WINAPI domdoc_setProperty(
2775 IXMLDOMDocument3* iface,
2776 BSTR p,
2777 VARIANT value)
2779 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2781 TRACE("(%p)->(%s %s)\n", This, debugstr_w(p), debugstr_variant(&value));
2783 if (lstrcmpiW(p, PropertySelectionLanguageW) == 0)
2785 VARIANT varStr;
2786 HRESULT hr;
2787 BSTR bstr;
2789 V_VT(&varStr) = VT_EMPTY;
2790 if (V_VT(&value) != VT_BSTR)
2792 if (FAILED(hr = VariantChangeType(&varStr, &value, 0, VT_BSTR)))
2793 return hr;
2794 bstr = V_BSTR(&varStr);
2796 else
2797 bstr = V_BSTR(&value);
2799 hr = S_OK;
2800 if (lstrcmpiW(bstr, PropValueXPathW) == 0)
2801 This->properties->XPath = TRUE;
2802 else if (lstrcmpiW(bstr, PropValueXSLPatternW) == 0)
2803 This->properties->XPath = FALSE;
2804 else
2805 hr = E_FAIL;
2807 VariantClear(&varStr);
2808 return hr;
2810 else if (lstrcmpiW(p, PropertySelectionNamespacesW) == 0)
2812 xmlChar *nsStr = (xmlChar*)This->properties->selectNsStr;
2813 struct list *pNsList;
2814 VARIANT varStr;
2815 HRESULT hr;
2816 BSTR bstr;
2818 V_VT(&varStr) = VT_EMPTY;
2819 if (V_VT(&value) != VT_BSTR)
2821 if (FAILED(hr = VariantChangeType(&varStr, &value, 0, VT_BSTR)))
2822 return hr;
2823 bstr = V_BSTR(&varStr);
2825 else
2826 bstr = V_BSTR(&value);
2828 hr = S_OK;
2830 pNsList = &(This->properties->selectNsList);
2831 clear_selectNsList(pNsList);
2832 heap_free(nsStr);
2833 nsStr = xmlchar_from_wchar(bstr);
2835 TRACE("property value: \"%s\"\n", debugstr_w(bstr));
2837 This->properties->selectNsStr = nsStr;
2838 This->properties->selectNsStr_len = xmlStrlen(nsStr);
2839 if (bstr && *bstr)
2841 xmlChar *pTokBegin, *pTokEnd, *pTokInner;
2842 select_ns_entry* ns_entry = NULL;
2843 xmlXPathContextPtr ctx;
2845 ctx = xmlXPathNewContext(This->node.node->doc);
2846 pTokBegin = nsStr;
2848 /* skip leading spaces */
2849 while (*pTokBegin == ' ' || *pTokBegin == '\n' ||
2850 *pTokBegin == '\t' || *pTokBegin == '\r')
2851 ++pTokBegin;
2853 for (; *pTokBegin; pTokBegin = pTokEnd)
2855 if (ns_entry)
2856 memset(ns_entry, 0, sizeof(select_ns_entry));
2857 else
2858 ns_entry = heap_alloc_zero(sizeof(select_ns_entry));
2860 while (*pTokBegin == ' ')
2861 ++pTokBegin;
2862 pTokEnd = pTokBegin;
2863 while (*pTokEnd != ' ' && *pTokEnd != 0)
2864 ++pTokEnd;
2866 /* so it failed to advance which means we've got some trailing spaces */
2867 if (pTokEnd == pTokBegin) break;
2869 if (xmlStrncmp(pTokBegin, (xmlChar const*)"xmlns", 5) != 0)
2871 hr = E_FAIL;
2872 WARN("Syntax error in xmlns string: %s\n\tat token: %s\n",
2873 debugstr_w(bstr), debugstr_an((const char*)pTokBegin, pTokEnd-pTokBegin));
2874 continue;
2877 pTokBegin += 5;
2878 if (*pTokBegin == '=')
2880 /*valid for XSLPattern?*/
2881 FIXME("Setting default xmlns not supported - skipping.\n");
2882 continue;
2884 else if (*pTokBegin == ':')
2886 ns_entry->prefix = ++pTokBegin;
2887 for (pTokInner = pTokBegin; pTokInner != pTokEnd && *pTokInner != '='; ++pTokInner)
2890 if (pTokInner == pTokEnd)
2892 hr = E_FAIL;
2893 WARN("Syntax error in xmlns string: %s\n\tat token: %s\n",
2894 debugstr_w(bstr), debugstr_an((const char*)pTokBegin, pTokEnd-pTokBegin));
2895 continue;
2898 ns_entry->prefix_end = *pTokInner;
2899 *pTokInner = 0;
2900 ++pTokInner;
2902 if (pTokEnd-pTokInner > 1 &&
2903 ((*pTokInner == '\'' && *(pTokEnd-1) == '\'') ||
2904 (*pTokInner == '"' && *(pTokEnd-1) == '"')))
2906 ns_entry->href = ++pTokInner;
2907 ns_entry->href_end = *(pTokEnd-1);
2908 *(pTokEnd-1) = 0;
2909 list_add_tail(pNsList, &ns_entry->entry);
2910 /*let libxml figure out if they're valid from here ;)*/
2911 if (xmlXPathRegisterNs(ctx, ns_entry->prefix, ns_entry->href) != 0)
2913 hr = E_FAIL;
2915 ns_entry = NULL;
2916 continue;
2918 else
2920 WARN("Syntax error in xmlns string: %s\n\tat token: %s\n",
2921 debugstr_w(bstr), debugstr_an((const char*)pTokInner, pTokEnd-pTokInner));
2922 list_add_tail(pNsList, &ns_entry->entry);
2924 ns_entry = NULL;
2925 hr = E_FAIL;
2926 continue;
2929 else
2931 hr = E_FAIL;
2932 continue;
2935 heap_free(ns_entry);
2936 xmlXPathFreeContext(ctx);
2939 VariantClear(&varStr);
2940 return hr;
2942 else if (lstrcmpiW(p, PropertyProhibitDTDW) == 0 ||
2943 lstrcmpiW(p, PropertyNewParserW) == 0 ||
2944 lstrcmpiW(p, PropertyResolveExternalsW) == 0)
2946 /* Ignore */
2947 FIXME("Ignoring property %s, value %d\n", debugstr_w(p), V_BOOL(&value));
2948 return S_OK;
2951 FIXME("Unknown property %s\n", debugstr_w(p));
2952 return E_FAIL;
2955 static HRESULT WINAPI domdoc_getProperty(
2956 IXMLDOMDocument3* iface,
2957 BSTR p,
2958 VARIANT* var)
2960 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2962 TRACE("(%p)->(%s)\n", This, debugstr_w(p));
2964 if (!var)
2965 return E_INVALIDARG;
2967 if (lstrcmpiW(p, PropertySelectionLanguageW) == 0)
2969 V_VT(var) = VT_BSTR;
2970 V_BSTR(var) = This->properties->XPath ?
2971 SysAllocString(PropValueXPathW) :
2972 SysAllocString(PropValueXSLPatternW);
2973 return V_BSTR(var) ? S_OK : E_OUTOFMEMORY;
2975 else if (lstrcmpiW(p, PropertySelectionNamespacesW) == 0)
2977 int lenA, lenW;
2978 BSTR rebuiltStr, cur;
2979 const xmlChar *nsStr;
2980 struct list *pNsList;
2981 select_ns_entry* pNsEntry;
2983 V_VT(var) = VT_BSTR;
2984 nsStr = This->properties->selectNsStr;
2985 pNsList = &This->properties->selectNsList;
2986 lenA = This->properties->selectNsStr_len;
2987 lenW = MultiByteToWideChar(CP_UTF8, 0, (LPCSTR)nsStr, lenA+1, NULL, 0);
2988 rebuiltStr = heap_alloc(lenW*sizeof(WCHAR));
2989 MultiByteToWideChar(CP_UTF8, 0, (LPCSTR)nsStr, lenA+1, rebuiltStr, lenW);
2990 cur = rebuiltStr;
2991 /* this is fine because all of the chars that end tokens are ASCII*/
2992 LIST_FOR_EACH_ENTRY(pNsEntry, pNsList, select_ns_entry, entry)
2994 while (*cur != 0) ++cur;
2995 if (pNsEntry->prefix_end)
2997 *cur = pNsEntry->prefix_end;
2998 while (*cur != 0) ++cur;
3001 if (pNsEntry->href_end)
3003 *cur = pNsEntry->href_end;
3006 V_BSTR(var) = SysAllocString(rebuiltStr);
3007 heap_free(rebuiltStr);
3008 return S_OK;
3011 FIXME("Unknown property %s\n", debugstr_w(p));
3012 return E_FAIL;
3015 static HRESULT WINAPI domdoc_importNode(
3016 IXMLDOMDocument3* iface,
3017 IXMLDOMNode* node,
3018 VARIANT_BOOL deep,
3019 IXMLDOMNode** clone)
3021 domdoc *This = impl_from_IXMLDOMDocument3( iface );
3022 FIXME("(%p)->(%p %d %p): stub\n", This, node, deep, clone);
3023 return E_NOTIMPL;
3026 static const struct IXMLDOMDocument3Vtbl XMLDOMDocument3Vtbl =
3028 domdoc_QueryInterface,
3029 domdoc_AddRef,
3030 domdoc_Release,
3031 domdoc_GetTypeInfoCount,
3032 domdoc_GetTypeInfo,
3033 domdoc_GetIDsOfNames,
3034 domdoc_Invoke,
3035 domdoc_get_nodeName,
3036 domdoc_get_nodeValue,
3037 domdoc_put_nodeValue,
3038 domdoc_get_nodeType,
3039 domdoc_get_parentNode,
3040 domdoc_get_childNodes,
3041 domdoc_get_firstChild,
3042 domdoc_get_lastChild,
3043 domdoc_get_previousSibling,
3044 domdoc_get_nextSibling,
3045 domdoc_get_attributes,
3046 domdoc_insertBefore,
3047 domdoc_replaceChild,
3048 domdoc_removeChild,
3049 domdoc_appendChild,
3050 domdoc_hasChildNodes,
3051 domdoc_get_ownerDocument,
3052 domdoc_cloneNode,
3053 domdoc_get_nodeTypeString,
3054 domdoc_get_text,
3055 domdoc_put_text,
3056 domdoc_get_specified,
3057 domdoc_get_definition,
3058 domdoc_get_nodeTypedValue,
3059 domdoc_put_nodeTypedValue,
3060 domdoc_get_dataType,
3061 domdoc_put_dataType,
3062 domdoc_get_xml,
3063 domdoc_transformNode,
3064 domdoc_selectNodes,
3065 domdoc_selectSingleNode,
3066 domdoc_get_parsed,
3067 domdoc_get_namespaceURI,
3068 domdoc_get_prefix,
3069 domdoc_get_baseName,
3070 domdoc_transformNodeToObject,
3071 domdoc_get_doctype,
3072 domdoc_get_implementation,
3073 domdoc_get_documentElement,
3074 domdoc_put_documentElement,
3075 domdoc_createElement,
3076 domdoc_createDocumentFragment,
3077 domdoc_createTextNode,
3078 domdoc_createComment,
3079 domdoc_createCDATASection,
3080 domdoc_createProcessingInstruction,
3081 domdoc_createAttribute,
3082 domdoc_createEntityReference,
3083 domdoc_getElementsByTagName,
3084 domdoc_createNode,
3085 domdoc_nodeFromID,
3086 domdoc_load,
3087 domdoc_get_readyState,
3088 domdoc_get_parseError,
3089 domdoc_get_url,
3090 domdoc_get_async,
3091 domdoc_put_async,
3092 domdoc_abort,
3093 domdoc_loadXML,
3094 domdoc_save,
3095 domdoc_get_validateOnParse,
3096 domdoc_put_validateOnParse,
3097 domdoc_get_resolveExternals,
3098 domdoc_put_resolveExternals,
3099 domdoc_get_preserveWhiteSpace,
3100 domdoc_put_preserveWhiteSpace,
3101 domdoc_put_onreadystatechange,
3102 domdoc_put_onDataAvailable,
3103 domdoc_put_onTransformNode,
3104 domdoc_get_namespaces,
3105 domdoc_get_schemas,
3106 domdoc_putref_schemas,
3107 domdoc_validate,
3108 domdoc_setProperty,
3109 domdoc_getProperty,
3110 domdoc_validateNode,
3111 domdoc_importNode
3114 /* IConnectionPointContainer */
3115 static HRESULT WINAPI ConnectionPointContainer_QueryInterface(IConnectionPointContainer *iface,
3116 REFIID riid, void **ppv)
3118 domdoc *This = impl_from_IConnectionPointContainer(iface);
3119 return IXMLDOMDocument3_QueryInterface(&This->IXMLDOMDocument3_iface, riid, ppv);
3122 static ULONG WINAPI ConnectionPointContainer_AddRef(IConnectionPointContainer *iface)
3124 domdoc *This = impl_from_IConnectionPointContainer(iface);
3125 return IXMLDOMDocument3_AddRef(&This->IXMLDOMDocument3_iface);
3128 static ULONG WINAPI ConnectionPointContainer_Release(IConnectionPointContainer *iface)
3130 domdoc *This = impl_from_IConnectionPointContainer(iface);
3131 return IXMLDOMDocument3_Release(&This->IXMLDOMDocument3_iface);
3134 static HRESULT WINAPI ConnectionPointContainer_EnumConnectionPoints(IConnectionPointContainer *iface,
3135 IEnumConnectionPoints **ppEnum)
3137 domdoc *This = impl_from_IConnectionPointContainer(iface);
3138 FIXME("(%p)->(%p): stub\n", This, ppEnum);
3139 return E_NOTIMPL;
3142 static HRESULT WINAPI ConnectionPointContainer_FindConnectionPoint(IConnectionPointContainer *iface,
3143 REFIID riid, IConnectionPoint **cp)
3145 domdoc *This = impl_from_IConnectionPointContainer(iface);
3146 ConnectionPoint *iter;
3148 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), cp);
3150 *cp = NULL;
3152 for(iter = This->cp_list; iter; iter = iter->next)
3154 if (IsEqualGUID(iter->iid, riid))
3155 *cp = &iter->IConnectionPoint_iface;
3158 if (*cp)
3160 IConnectionPoint_AddRef(*cp);
3161 return S_OK;
3164 FIXME("unsupported riid %s\n", debugstr_guid(riid));
3165 return CONNECT_E_NOCONNECTION;
3169 static const struct IConnectionPointContainerVtbl ConnectionPointContainerVtbl =
3171 ConnectionPointContainer_QueryInterface,
3172 ConnectionPointContainer_AddRef,
3173 ConnectionPointContainer_Release,
3174 ConnectionPointContainer_EnumConnectionPoints,
3175 ConnectionPointContainer_FindConnectionPoint
3178 /* IConnectionPoint */
3179 static HRESULT WINAPI ConnectionPoint_QueryInterface(IConnectionPoint *iface,
3180 REFIID riid, void **ppv)
3182 ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3184 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv );
3186 *ppv = NULL;
3188 if (IsEqualGUID(&IID_IUnknown, riid) ||
3189 IsEqualGUID(&IID_IConnectionPoint, riid))
3191 *ppv = iface;
3194 if (*ppv)
3196 IConnectionPoint_AddRef(iface);
3197 return S_OK;
3200 WARN("Unsupported interface %s\n", debugstr_guid(riid));
3201 return E_NOINTERFACE;
3204 static ULONG WINAPI ConnectionPoint_AddRef(IConnectionPoint *iface)
3206 ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3207 return IConnectionPointContainer_AddRef(This->container);
3210 static ULONG WINAPI ConnectionPoint_Release(IConnectionPoint *iface)
3212 ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3213 return IConnectionPointContainer_Release(This->container);
3216 static HRESULT WINAPI ConnectionPoint_GetConnectionInterface(IConnectionPoint *iface, IID *iid)
3218 ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3220 TRACE("(%p)->(%p)\n", This, iid);
3222 if (!iid) return E_POINTER;
3224 *iid = *This->iid;
3225 return S_OK;
3228 static HRESULT WINAPI ConnectionPoint_GetConnectionPointContainer(IConnectionPoint *iface,
3229 IConnectionPointContainer **container)
3231 ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3233 TRACE("(%p)->(%p)\n", This, container);
3235 if (!container) return E_POINTER;
3237 *container = This->container;
3238 IConnectionPointContainer_AddRef(*container);
3239 return S_OK;
3242 static HRESULT WINAPI ConnectionPoint_Advise(IConnectionPoint *iface, IUnknown *unk_sink,
3243 DWORD *cookie)
3245 ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3246 IUnknown *sink;
3247 HRESULT hr;
3248 int i;
3250 TRACE("(%p)->(%p %p)\n", This, unk_sink, cookie);
3252 hr = IUnknown_QueryInterface(unk_sink, This->iid, (void**)&sink);
3253 if(FAILED(hr) && !IsEqualGUID(&IID_IPropertyNotifySink, This->iid))
3254 hr = IUnknown_QueryInterface(unk_sink, &IID_IDispatch, (void**)&sink);
3255 if(FAILED(hr))
3256 return CONNECT_E_CANNOTCONNECT;
3258 if(This->sinks)
3260 for (i = 0; i < This->sinks_size; i++)
3261 if (!This->sinks[i].unk)
3262 break;
3264 if (i == This->sinks_size)
3265 This->sinks = heap_realloc(This->sinks,(++This->sinks_size)*sizeof(*This->sinks));
3267 else
3269 This->sinks = heap_alloc(sizeof(*This->sinks));
3270 This->sinks_size = 1;
3271 i = 0;
3274 This->sinks[i].unk = sink;
3275 if (cookie)
3276 *cookie = i+1;
3278 return S_OK;
3281 static HRESULT WINAPI ConnectionPoint_Unadvise(IConnectionPoint *iface, DWORD cookie)
3283 ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3285 TRACE("(%p)->(%d)\n", This, cookie);
3287 if (cookie == 0 || cookie > This->sinks_size || !This->sinks[cookie-1].unk)
3288 return CONNECT_E_NOCONNECTION;
3290 IUnknown_Release(This->sinks[cookie-1].unk);
3291 This->sinks[cookie-1].unk = NULL;
3293 return S_OK;
3296 static HRESULT WINAPI ConnectionPoint_EnumConnections(IConnectionPoint *iface,
3297 IEnumConnections **ppEnum)
3299 ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3300 FIXME("(%p)->(%p): stub\n", This, ppEnum);
3301 return E_NOTIMPL;
3304 static const IConnectionPointVtbl ConnectionPointVtbl =
3306 ConnectionPoint_QueryInterface,
3307 ConnectionPoint_AddRef,
3308 ConnectionPoint_Release,
3309 ConnectionPoint_GetConnectionInterface,
3310 ConnectionPoint_GetConnectionPointContainer,
3311 ConnectionPoint_Advise,
3312 ConnectionPoint_Unadvise,
3313 ConnectionPoint_EnumConnections
3316 static void ConnectionPoint_Init(ConnectionPoint *cp, struct domdoc *doc, REFIID riid)
3318 cp->IConnectionPoint_iface.lpVtbl = &ConnectionPointVtbl;
3319 cp->doc = doc;
3320 cp->iid = riid;
3321 cp->sinks = NULL;
3322 cp->sinks_size = 0;
3324 cp->next = doc->cp_list;
3325 doc->cp_list = cp;
3327 cp->container = &doc->IConnectionPointContainer_iface;
3330 /* domdoc implementation of IObjectWithSite */
3331 static HRESULT WINAPI
3332 domdoc_ObjectWithSite_QueryInterface( IObjectWithSite* iface, REFIID riid, void** ppvObject )
3334 domdoc *This = impl_from_IObjectWithSite(iface);
3335 return IXMLDOMDocument3_QueryInterface(&This->IXMLDOMDocument3_iface, riid, ppvObject);
3338 static ULONG WINAPI domdoc_ObjectWithSite_AddRef( IObjectWithSite* iface )
3340 domdoc *This = impl_from_IObjectWithSite(iface);
3341 return IXMLDOMDocument3_AddRef(&This->IXMLDOMDocument3_iface);
3344 static ULONG WINAPI domdoc_ObjectWithSite_Release( IObjectWithSite* iface )
3346 domdoc *This = impl_from_IObjectWithSite(iface);
3347 return IXMLDOMDocument3_Release(&This->IXMLDOMDocument3_iface);
3350 static HRESULT WINAPI domdoc_ObjectWithSite_GetSite( IObjectWithSite *iface, REFIID iid, void **ppvSite )
3352 domdoc *This = impl_from_IObjectWithSite(iface);
3354 TRACE("(%p)->(%s %p)\n", This, debugstr_guid( iid ), ppvSite );
3356 if ( !This->site )
3357 return E_FAIL;
3359 return IUnknown_QueryInterface( This->site, iid, ppvSite );
3362 static HRESULT WINAPI domdoc_ObjectWithSite_SetSite( IObjectWithSite *iface, IUnknown *punk )
3364 domdoc *This = impl_from_IObjectWithSite(iface);
3366 TRACE("(%p)->(%p)\n", iface, punk);
3368 if(!punk)
3370 if(This->site)
3372 IUnknown_Release( This->site );
3373 This->site = NULL;
3376 return S_OK;
3379 IUnknown_AddRef( punk );
3381 if(This->site)
3382 IUnknown_Release( This->site );
3384 This->site = punk;
3386 return S_OK;
3389 static const IObjectWithSiteVtbl domdocObjectSite =
3391 domdoc_ObjectWithSite_QueryInterface,
3392 domdoc_ObjectWithSite_AddRef,
3393 domdoc_ObjectWithSite_Release,
3394 domdoc_ObjectWithSite_SetSite,
3395 domdoc_ObjectWithSite_GetSite
3398 static HRESULT WINAPI domdoc_Safety_QueryInterface(IObjectSafety *iface, REFIID riid, void **ppv)
3400 domdoc *This = impl_from_IObjectSafety(iface);
3401 return IXMLDOMDocument3_QueryInterface(&This->IXMLDOMDocument3_iface, riid, ppv);
3404 static ULONG WINAPI domdoc_Safety_AddRef(IObjectSafety *iface)
3406 domdoc *This = impl_from_IObjectSafety(iface);
3407 return IXMLDOMDocument3_AddRef(&This->IXMLDOMDocument3_iface);
3410 static ULONG WINAPI domdoc_Safety_Release(IObjectSafety *iface)
3412 domdoc *This = impl_from_IObjectSafety(iface);
3413 return IXMLDOMDocument3_Release(&This->IXMLDOMDocument3_iface);
3416 #define SAFETY_SUPPORTED_OPTIONS (INTERFACESAFE_FOR_UNTRUSTED_CALLER|INTERFACESAFE_FOR_UNTRUSTED_DATA|INTERFACE_USES_SECURITY_MANAGER)
3418 static HRESULT WINAPI domdoc_Safety_GetInterfaceSafetyOptions(IObjectSafety *iface, REFIID riid,
3419 DWORD *supported, DWORD *enabled)
3421 domdoc *This = impl_from_IObjectSafety(iface);
3423 TRACE("(%p)->(%s %p %p)\n", This, debugstr_guid(riid), supported, enabled);
3425 if(!supported || !enabled) return E_POINTER;
3427 *supported = SAFETY_SUPPORTED_OPTIONS;
3428 *enabled = This->safeopt;
3430 return S_OK;
3433 static HRESULT WINAPI domdoc_Safety_SetInterfaceSafetyOptions(IObjectSafety *iface, REFIID riid,
3434 DWORD mask, DWORD enabled)
3436 domdoc *This = impl_from_IObjectSafety(iface);
3437 TRACE("(%p)->(%s %x %x)\n", This, debugstr_guid(riid), mask, enabled);
3439 if ((mask & ~SAFETY_SUPPORTED_OPTIONS) != 0)
3440 return E_FAIL;
3442 This->safeopt = (This->safeopt & ~mask) | (mask & enabled);
3444 return S_OK;
3447 #undef SAFETY_SUPPORTED_OPTIONS
3449 static const IObjectSafetyVtbl domdocObjectSafetyVtbl = {
3450 domdoc_Safety_QueryInterface,
3451 domdoc_Safety_AddRef,
3452 domdoc_Safety_Release,
3453 domdoc_Safety_GetInterfaceSafetyOptions,
3454 domdoc_Safety_SetInterfaceSafetyOptions
3457 static const tid_t domdoc_iface_tids[] = {
3458 IXMLDOMDocument3_tid,
3462 static dispex_static_data_t domdoc_dispex = {
3463 NULL,
3464 IXMLDOMDocument3_tid,
3465 NULL,
3466 domdoc_iface_tids
3469 HRESULT get_domdoc_from_xmldoc(xmlDocPtr xmldoc, IXMLDOMDocument3 **document)
3471 domdoc *doc;
3473 doc = heap_alloc( sizeof (*doc) );
3474 if( !doc )
3475 return E_OUTOFMEMORY;
3477 doc->IXMLDOMDocument3_iface.lpVtbl = &XMLDOMDocument3Vtbl;
3478 doc->IPersistStreamInit_iface.lpVtbl = &xmldoc_IPersistStreamInit_VTable;
3479 doc->IObjectWithSite_iface.lpVtbl = &domdocObjectSite;
3480 doc->IObjectSafety_iface.lpVtbl = &domdocObjectSafetyVtbl;
3481 doc->IConnectionPointContainer_iface.lpVtbl = &ConnectionPointContainerVtbl;
3482 doc->ref = 1;
3483 doc->async = VARIANT_TRUE;
3484 doc->validating = 0;
3485 doc->resolving = 0;
3486 doc->properties = properties_from_xmlDocPtr(xmldoc);
3487 doc->error = S_OK;
3488 doc->site = NULL;
3489 doc->safeopt = 0;
3490 doc->bsc = NULL;
3491 doc->cp_list = NULL;
3492 doc->namespaces = NULL;
3493 memset(doc->events, 0, sizeof(doc->events));
3495 /* events connection points */
3496 ConnectionPoint_Init(&doc->cp_dispatch, doc, &IID_IDispatch);
3497 ConnectionPoint_Init(&doc->cp_propnotif, doc, &IID_IPropertyNotifySink);
3498 ConnectionPoint_Init(&doc->cp_domdocevents, doc, &DIID_XMLDOMDocumentEvents);
3500 init_xmlnode(&doc->node, (xmlNodePtr)xmldoc, (IXMLDOMNode*)&doc->IXMLDOMDocument3_iface,
3501 &domdoc_dispex);
3503 *document = &doc->IXMLDOMDocument3_iface;
3505 TRACE("returning iface %p\n", *document);
3506 return S_OK;
3509 HRESULT DOMDocument_create(MSXML_VERSION version, IUnknown *pUnkOuter, void **ppObj)
3511 xmlDocPtr xmldoc;
3512 HRESULT hr;
3514 TRACE("(%d, %p, %p)\n", version, pUnkOuter, ppObj);
3516 xmldoc = xmlNewDoc(NULL);
3517 if(!xmldoc)
3518 return E_OUTOFMEMORY;
3520 xmldoc_init(xmldoc, version);
3522 hr = get_domdoc_from_xmldoc(xmldoc, (IXMLDOMDocument3**)ppObj);
3523 if(FAILED(hr))
3525 free_properties(properties_from_xmlDocPtr(xmldoc));
3526 heap_free(xmldoc->_private);
3527 xmlFreeDoc(xmldoc);
3528 return hr;
3531 return hr;
3534 IUnknown* create_domdoc( xmlNodePtr document )
3536 void* pObj = NULL;
3537 HRESULT hr;
3539 TRACE("(%p)\n", document);
3541 hr = get_domdoc_from_xmldoc((xmlDocPtr)document, (IXMLDOMDocument3**)&pObj);
3542 if (FAILED(hr))
3543 return NULL;
3545 return pObj;
3548 #else
3550 HRESULT DOMDocument_create(MSXML_VERSION version, IUnknown *pUnkOuter, void **ppObj)
3552 MESSAGE("This program tried to use a DOMDocument object, but\n"
3553 "libxml2 support was not present at compile time.\n");
3554 return E_NOTIMPL;
3557 #endif