msxml3: Remove unneeded xmlInitParser call.
[wine/multimedia.git] / dlls / msxml3 / domdoc.c
blobcbbebf2f84ad74b97c285e4fc1882a0ea2d75ec6
1 /*
2 * DOM Document implementation
4 * Copyright 2005 Mike McCormack
5 * Copyright 2010-2011 Adam Martinson for CodeWeavers
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
22 #define COBJMACROS
23 #define NONAMELESSUNION
25 #include "config.h"
27 #include <stdarg.h>
28 #include <assert.h>
29 #ifdef HAVE_LIBXML2
30 # include <libxml/parser.h>
31 # include <libxml/xmlerror.h>
32 # include <libxml/xpathInternals.h>
33 # include <libxml/xmlsave.h>
34 # include <libxml/SAX2.h>
35 # include <libxml/parserInternals.h>
36 #endif
38 #include "windef.h"
39 #include "winbase.h"
40 #include "winuser.h"
41 #include "winnls.h"
42 #include "ole2.h"
43 #include "olectl.h"
44 #include "msxml6.h"
45 #include "wininet.h"
46 #include "winreg.h"
47 #include "shlwapi.h"
48 #include "ocidl.h"
49 #include "objsafe.h"
51 #include "wine/debug.h"
52 #include "wine/list.h"
54 #include "msxml_private.h"
56 WINE_DEFAULT_DEBUG_CHANNEL(msxml);
58 #ifdef HAVE_LIBXML2
60 /* not defined in older versions */
61 #define XML_SAVE_FORMAT 1
62 #define XML_SAVE_NO_DECL 2
63 #define XML_SAVE_NO_EMPTY 4
64 #define XML_SAVE_NO_XHTML 8
65 #define XML_SAVE_XHTML 16
66 #define XML_SAVE_AS_XML 32
67 #define XML_SAVE_AS_HTML 64
69 static const WCHAR PropertySelectionLanguageW[] = {'S','e','l','e','c','t','i','o','n','L','a','n','g','u','a','g','e',0};
70 static const WCHAR PropertySelectionNamespacesW[] = {'S','e','l','e','c','t','i','o','n','N','a','m','e','s','p','a','c','e','s',0};
71 static const WCHAR PropertyProhibitDTDW[] = {'P','r','o','h','i','b','i','t','D','T','D',0};
72 static const WCHAR PropertyNewParserW[] = {'N','e','w','P','a','r','s','e','r',0};
73 static const WCHAR PropValueXPathW[] = {'X','P','a','t','h',0};
74 static const WCHAR PropValueXSLPatternW[] = {'X','S','L','P','a','t','t','e','r','n',0};
75 static const WCHAR PropertyResolveExternalsW[] = {'R','e','s','o','l','v','e','E','x','t','e','r','n','a','l','s',0};
77 /* Anything that passes the test_get_ownerDocument()
78 * tests can go here (data shared between all instances).
79 * We need to preserve this when reloading a document,
80 * and also need access to it from the libxml backend. */
81 typedef struct {
82 MSXML_VERSION version;
83 VARIANT_BOOL preserving;
84 IXMLDOMSchemaCollection2* schemaCache;
85 struct list selectNsList;
86 xmlChar const* selectNsStr;
87 LONG selectNsStr_len;
88 BOOL XPath;
89 } domdoc_properties;
91 typedef struct ConnectionPoint ConnectionPoint;
92 typedef struct domdoc domdoc;
94 struct ConnectionPoint
96 IConnectionPoint IConnectionPoint_iface;
97 const IID *iid;
99 ConnectionPoint *next;
100 IConnectionPointContainer *container;
101 domdoc *doc;
103 union
105 IUnknown *unk;
106 IDispatch *disp;
107 IPropertyNotifySink *propnotif;
108 } *sinks;
109 DWORD sinks_size;
112 typedef enum {
113 EVENTID_READYSTATECHANGE = 0,
114 EVENTID_DATAAVAILABLE,
115 EVENTID_TRANSFORMNODE,
116 EVENTID_LAST
117 } eventid_t;
119 struct domdoc
121 xmlnode node;
122 IXMLDOMDocument3 IXMLDOMDocument3_iface;
123 IPersistStreamInit IPersistStreamInit_iface;
124 IObjectWithSite IObjectWithSite_iface;
125 IObjectSafety IObjectSafety_iface;
126 IConnectionPointContainer IConnectionPointContainer_iface;
127 LONG ref;
128 VARIANT_BOOL async;
129 VARIANT_BOOL validating;
130 VARIANT_BOOL resolving;
131 domdoc_properties* properties;
132 bsc_t *bsc;
133 HRESULT error;
135 /* IPersistStream */
136 IStream *stream;
138 /* IObjectWithSite*/
139 IUnknown *site;
141 /* IObjectSafety */
142 DWORD safeopt;
144 /* connection list */
145 ConnectionPoint *cp_list;
146 ConnectionPoint cp_domdocevents;
147 ConnectionPoint cp_propnotif;
148 ConnectionPoint cp_dispatch;
150 /* events */
151 IDispatch *events[EVENTID_LAST];
153 IXMLDOMSchemaCollection2 *namespaces;
156 static HRESULT set_doc_event(domdoc *doc, eventid_t eid, const VARIANT *v)
158 IDispatch *disp;
160 switch (V_VT(v))
162 case VT_UNKNOWN:
163 if (V_UNKNOWN(v))
164 IUnknown_QueryInterface(V_UNKNOWN(v), &IID_IDispatch, (void**)&disp);
165 else
166 disp = NULL;
167 break;
168 case VT_DISPATCH:
169 disp = V_DISPATCH(v);
170 if (disp) IDispatch_AddRef(disp);
171 break;
172 default:
173 return DISP_E_TYPEMISMATCH;
176 if (doc->events[eid]) IDispatch_Release(doc->events[eid]);
177 doc->events[eid] = disp;
179 return S_OK;
182 static inline ConnectionPoint *impl_from_IConnectionPoint(IConnectionPoint *iface)
184 return CONTAINING_RECORD(iface, ConnectionPoint, IConnectionPoint_iface);
188 In native windows, the whole lifetime management of XMLDOMNodes is
189 managed automatically using reference counts. Wine emulates that by
190 maintaining a reference count to the document that is increased for
191 each IXMLDOMNode pointer passed out for this document. If all these
192 pointers are gone, the document is unreachable and gets freed, that
193 is, all nodes in the tree of the document get freed.
195 You are able to create nodes that are associated to a document (in
196 fact, in msxml's XMLDOM model, all nodes are associated to a document),
197 but not in the tree of that document, for example using the createFoo
198 functions from IXMLDOMDocument. These nodes do not get cleaned up
199 by libxml, so we have to do it ourselves.
201 To catch these nodes, a list of "orphan nodes" is introduced.
202 It contains pointers to all roots of node trees that are
203 associated with the document without being part of the document
204 tree. All nodes with parent==NULL (except for the document root nodes)
205 should be in the orphan node list of their document. All orphan nodes
206 get freed together with the document itself.
209 typedef struct _xmldoc_priv {
210 LONG refs;
211 struct list orphans;
212 domdoc_properties* properties;
213 } xmldoc_priv;
215 typedef struct _orphan_entry {
216 struct list entry;
217 xmlNode * node;
218 } orphan_entry;
220 typedef struct _select_ns_entry {
221 struct list entry;
222 xmlChar const* prefix;
223 xmlChar prefix_end;
224 xmlChar const* href;
225 xmlChar href_end;
226 } select_ns_entry;
228 static inline xmldoc_priv * priv_from_xmlDocPtr(const xmlDocPtr doc)
230 return doc->_private;
233 static inline domdoc_properties * properties_from_xmlDocPtr(xmlDocPtr doc)
235 return priv_from_xmlDocPtr(doc)->properties;
238 BOOL is_xpathmode(const xmlDocPtr doc)
240 return properties_from_xmlDocPtr(doc)->XPath;
243 void set_xpathmode(xmlDocPtr doc, BOOL xpath)
245 properties_from_xmlDocPtr(doc)->XPath = xpath;
248 int registerNamespaces(xmlXPathContextPtr ctxt)
250 int n = 0;
251 const select_ns_entry* ns = NULL;
252 const struct list* pNsList = &properties_from_xmlDocPtr(ctxt->doc)->selectNsList;
254 TRACE("(%p)\n", ctxt);
256 LIST_FOR_EACH_ENTRY( ns, pNsList, select_ns_entry, entry )
258 xmlXPathRegisterNs(ctxt, ns->prefix, ns->href);
259 ++n;
262 return n;
265 static inline void clear_selectNsList(struct list* pNsList)
267 select_ns_entry *ns, *ns2;
268 LIST_FOR_EACH_ENTRY_SAFE( ns, ns2, pNsList, select_ns_entry, entry )
270 heap_free( ns );
272 list_init(pNsList);
275 static xmldoc_priv * create_priv(void)
277 xmldoc_priv *priv;
278 priv = heap_alloc( sizeof (*priv) );
280 if (priv)
282 priv->refs = 0;
283 list_init( &priv->orphans );
284 priv->properties = NULL;
287 return priv;
290 static domdoc_properties *create_properties(MSXML_VERSION version)
292 domdoc_properties *properties = heap_alloc(sizeof(domdoc_properties));
294 list_init(&properties->selectNsList);
295 properties->preserving = VARIANT_FALSE;
296 properties->schemaCache = NULL;
297 properties->selectNsStr = heap_alloc_zero(sizeof(xmlChar));
298 properties->selectNsStr_len = 0;
300 /* properties that are dependent on object versions */
301 properties->version = version;
302 properties->XPath = (version == MSXML4 || version == MSXML6);
304 return properties;
307 static domdoc_properties* copy_properties(domdoc_properties const* properties)
309 domdoc_properties* pcopy = heap_alloc(sizeof(domdoc_properties));
310 select_ns_entry const* ns = NULL;
311 select_ns_entry* new_ns = NULL;
312 int len = (properties->selectNsStr_len+1)*sizeof(xmlChar);
313 ptrdiff_t offset;
315 if (pcopy)
317 pcopy->version = properties->version;
318 pcopy->preserving = properties->preserving;
319 pcopy->schemaCache = properties->schemaCache;
320 if (pcopy->schemaCache)
321 IXMLDOMSchemaCollection2_AddRef(pcopy->schemaCache);
322 pcopy->XPath = properties->XPath;
323 pcopy->selectNsStr_len = properties->selectNsStr_len;
324 list_init( &pcopy->selectNsList );
325 pcopy->selectNsStr = heap_alloc(len);
326 memcpy((xmlChar*)pcopy->selectNsStr, properties->selectNsStr, len);
327 offset = pcopy->selectNsStr - properties->selectNsStr;
329 LIST_FOR_EACH_ENTRY( ns, (&properties->selectNsList), select_ns_entry, entry )
331 new_ns = heap_alloc(sizeof(select_ns_entry));
332 memcpy(new_ns, ns, sizeof(select_ns_entry));
333 new_ns->href += offset;
334 new_ns->prefix += offset;
335 list_add_tail(&pcopy->selectNsList, &new_ns->entry);
340 return pcopy;
343 static void free_properties(domdoc_properties* properties)
345 if (properties)
347 if (properties->schemaCache)
348 IXMLDOMSchemaCollection2_Release(properties->schemaCache);
349 clear_selectNsList(&properties->selectNsList);
350 heap_free((xmlChar*)properties->selectNsStr);
351 heap_free(properties);
355 static void release_namespaces(domdoc *This)
357 if (This->namespaces)
359 IXMLDOMSchemaCollection2_Release(This->namespaces);
360 This->namespaces = NULL;
364 /* links a "<?xml" node as a first child */
365 void xmldoc_link_xmldecl(xmlDocPtr doc, xmlNodePtr node)
367 assert(doc != NULL);
368 if (doc->standalone != -1) xmlAddPrevSibling( doc->children, node );
371 /* unlinks a first "<?xml" child if it was created */
372 xmlNodePtr xmldoc_unlink_xmldecl(xmlDocPtr doc)
374 static const xmlChar xmlA[] = "xml";
375 xmlNodePtr node, first_child;
377 assert(doc != NULL);
379 /* xml declaration node could be created automatically after parsing or added
380 to a tree later */
381 first_child = doc->children;
382 if (first_child && first_child->type == XML_PI_NODE && xmlStrEqual(first_child->name, xmlA))
384 node = first_child;
385 xmlUnlinkNode( node );
387 else
388 node = NULL;
390 return node;
393 BOOL is_preserving_whitespace(xmlNodePtr node)
395 domdoc_properties* properties = NULL;
396 /* during parsing the xmlDoc._private stuff is not there */
397 if (priv_from_xmlDocPtr(node->doc))
398 properties = properties_from_xmlDocPtr(node->doc);
399 return ((properties && properties->preserving == VARIANT_TRUE) ||
400 xmlNodeGetSpacePreserve(node) == 1);
403 static inline BOOL strn_isspace(xmlChar const* str, int len)
405 for (; str && len > 0 && *str; ++str, --len)
406 if (!isspace(*str))
407 break;
409 return len == 0;
412 static void sax_characters(void *ctx, const xmlChar *ch, int len)
414 xmlParserCtxtPtr ctxt;
415 const domdoc *This;
417 ctxt = (xmlParserCtxtPtr) ctx;
418 This = (const domdoc*) ctxt->_private;
420 if (ctxt->node)
422 /* during domdoc_loadXML() the xmlDocPtr->_private data is not available */
423 if (!This->properties->preserving &&
424 !is_preserving_whitespace(ctxt->node) &&
425 strn_isspace(ch, len))
426 return;
429 xmlSAX2Characters(ctxt, ch, len);
432 static void LIBXML2_LOG_CALLBACK sax_error(void* ctx, char const* msg, ...)
434 va_list ap;
435 va_start(ap, msg);
436 LIBXML2_CALLBACK_ERR(doparse, msg, ap);
437 va_end(ap);
440 static void LIBXML2_LOG_CALLBACK sax_warning(void* ctx, char const* msg, ...)
442 va_list ap;
443 va_start(ap, msg);
444 LIBXML2_CALLBACK_WARN(doparse, msg, ap);
445 va_end(ap);
448 static void sax_serror(void* ctx, xmlErrorPtr err)
450 LIBXML2_CALLBACK_SERROR(doparse, err);
453 static xmlDocPtr doparse(domdoc* This, char const* ptr, int len, xmlCharEncoding encoding)
455 xmlDocPtr doc = NULL;
456 xmlParserCtxtPtr pctx;
457 static xmlSAXHandler sax_handler = {
458 xmlSAX2InternalSubset, /* internalSubset */
459 xmlSAX2IsStandalone, /* isStandalone */
460 xmlSAX2HasInternalSubset, /* hasInternalSubset */
461 xmlSAX2HasExternalSubset, /* hasExternalSubset */
462 xmlSAX2ResolveEntity, /* resolveEntity */
463 xmlSAX2GetEntity, /* getEntity */
464 xmlSAX2EntityDecl, /* entityDecl */
465 xmlSAX2NotationDecl, /* notationDecl */
466 xmlSAX2AttributeDecl, /* attributeDecl */
467 xmlSAX2ElementDecl, /* elementDecl */
468 xmlSAX2UnparsedEntityDecl, /* unparsedEntityDecl */
469 xmlSAX2SetDocumentLocator, /* setDocumentLocator */
470 xmlSAX2StartDocument, /* startDocument */
471 xmlSAX2EndDocument, /* endDocument */
472 xmlSAX2StartElement, /* startElement */
473 xmlSAX2EndElement, /* endElement */
474 xmlSAX2Reference, /* reference */
475 sax_characters, /* characters */
476 sax_characters, /* ignorableWhitespace */
477 xmlSAX2ProcessingInstruction, /* processingInstruction */
478 xmlSAX2Comment, /* comment */
479 sax_warning, /* warning */
480 sax_error, /* error */
481 sax_error, /* fatalError */
482 xmlSAX2GetParameterEntity, /* getParameterEntity */
483 xmlSAX2CDataBlock, /* cdataBlock */
484 xmlSAX2ExternalSubset, /* externalSubset */
485 0, /* initialized */
486 NULL, /* _private */
487 xmlSAX2StartElementNs, /* startElementNs */
488 xmlSAX2EndElementNs, /* endElementNs */
489 sax_serror /* serror */
492 pctx = xmlCreateMemoryParserCtxt(ptr, len);
493 if (!pctx)
495 ERR("Failed to create parser context\n");
496 return NULL;
499 if (pctx->sax) xmlFree(pctx->sax);
500 pctx->sax = &sax_handler;
501 pctx->_private = This;
502 pctx->recovery = 0;
504 if (encoding != XML_CHAR_ENCODING_NONE)
505 xmlSwitchEncoding(pctx, encoding);
507 xmlParseDocument(pctx);
509 if (pctx->wellFormed)
511 doc = pctx->myDoc;
513 else
515 xmlFreeDoc(pctx->myDoc);
516 pctx->myDoc = NULL;
518 pctx->sax = NULL;
519 xmlFreeParserCtxt(pctx);
521 /* TODO: put this in one of the SAX callbacks */
522 /* create first child as a <?xml...?> */
523 if (doc && doc->standalone != -1)
525 xmlNodePtr node;
526 char buff[30];
527 xmlChar *xmlbuff = (xmlChar*)buff;
529 node = xmlNewDocPI( doc, (xmlChar*)"xml", NULL );
531 /* version attribute can't be omitted */
532 sprintf(buff, "version=\"%s\"", doc->version ? (char*)doc->version : "1.0");
533 xmlNodeAddContent( node, xmlbuff );
535 if (doc->encoding)
537 sprintf(buff, " encoding=\"%s\"", doc->encoding);
538 xmlNodeAddContent( node, xmlbuff );
541 if (doc->standalone != -2)
543 sprintf(buff, " standalone=\"%s\"", doc->standalone == 0 ? "no" : "yes");
544 xmlNodeAddContent( node, xmlbuff );
547 xmldoc_link_xmldecl( doc, node );
550 return doc;
553 void xmldoc_init(xmlDocPtr doc, MSXML_VERSION version)
555 doc->_private = create_priv();
556 priv_from_xmlDocPtr(doc)->properties = create_properties(version);
559 LONG xmldoc_add_ref(xmlDocPtr doc)
561 LONG ref = InterlockedIncrement(&priv_from_xmlDocPtr(doc)->refs);
562 TRACE("(%p)->(%d)\n", doc, ref);
563 return ref;
566 LONG xmldoc_release(xmlDocPtr doc)
568 xmldoc_priv *priv = priv_from_xmlDocPtr(doc);
569 LONG ref = InterlockedDecrement(&priv->refs);
570 TRACE("(%p)->(%d)\n", doc, ref);
571 if(ref == 0)
573 orphan_entry *orphan, *orphan2;
574 TRACE("freeing docptr %p\n", doc);
576 LIST_FOR_EACH_ENTRY_SAFE( orphan, orphan2, &priv->orphans, orphan_entry, entry )
578 xmlFreeNode( orphan->node );
579 heap_free( orphan );
581 free_properties(priv->properties);
582 heap_free(doc->_private);
584 xmlFreeDoc(doc);
587 return ref;
590 HRESULT xmldoc_add_orphan(xmlDocPtr doc, xmlNodePtr node)
592 xmldoc_priv *priv = priv_from_xmlDocPtr(doc);
593 orphan_entry *entry;
595 entry = heap_alloc( sizeof (*entry) );
596 if(!entry)
597 return E_OUTOFMEMORY;
599 entry->node = node;
600 list_add_head( &priv->orphans, &entry->entry );
601 return S_OK;
604 HRESULT xmldoc_remove_orphan(xmlDocPtr doc, xmlNodePtr node)
606 xmldoc_priv *priv = priv_from_xmlDocPtr(doc);
607 orphan_entry *entry, *entry2;
609 LIST_FOR_EACH_ENTRY_SAFE( entry, entry2, &priv->orphans, orphan_entry, entry )
611 if( entry->node == node )
613 list_remove( &entry->entry );
614 heap_free( entry );
615 return S_OK;
619 return S_FALSE;
622 static inline xmlDocPtr get_doc( domdoc *This )
624 return (xmlDocPtr)This->node.node;
627 static HRESULT attach_xmldoc(domdoc *This, xmlDocPtr xml )
629 release_namespaces(This);
631 if(This->node.node)
633 priv_from_xmlDocPtr(get_doc(This))->properties = NULL;
634 if (xmldoc_release(get_doc(This)) != 0)
635 priv_from_xmlDocPtr(get_doc(This))->properties =
636 copy_properties(This->properties);
639 This->node.node = (xmlNodePtr) xml;
641 if(This->node.node)
643 xmldoc_add_ref(get_doc(This));
644 priv_from_xmlDocPtr(get_doc(This))->properties = This->properties;
647 return S_OK;
650 static inline domdoc *impl_from_IXMLDOMDocument3( IXMLDOMDocument3 *iface )
652 return CONTAINING_RECORD(iface, domdoc, IXMLDOMDocument3_iface);
655 static inline domdoc *impl_from_IPersistStreamInit(IPersistStreamInit *iface)
657 return CONTAINING_RECORD(iface, domdoc, IPersistStreamInit_iface);
660 static inline domdoc *impl_from_IObjectWithSite(IObjectWithSite *iface)
662 return CONTAINING_RECORD(iface, domdoc, IObjectWithSite_iface);
665 static inline domdoc *impl_from_IObjectSafety(IObjectSafety *iface)
667 return CONTAINING_RECORD(iface, domdoc, IObjectSafety_iface);
670 static inline domdoc *impl_from_IConnectionPointContainer(IConnectionPointContainer *iface)
672 return CONTAINING_RECORD(iface, domdoc, IConnectionPointContainer_iface);
675 /************************************************************************
676 * domdoc implementation of IPersistStream.
678 static HRESULT WINAPI PersistStreamInit_QueryInterface(
679 IPersistStreamInit *iface, REFIID riid, void **ppvObj)
681 domdoc* This = impl_from_IPersistStreamInit(iface);
682 return IXMLDOMDocument3_QueryInterface(&This->IXMLDOMDocument3_iface, riid, ppvObj);
685 static ULONG WINAPI PersistStreamInit_AddRef(
686 IPersistStreamInit *iface)
688 domdoc* This = impl_from_IPersistStreamInit(iface);
689 return IXMLDOMDocument3_AddRef(&This->IXMLDOMDocument3_iface);
692 static ULONG WINAPI PersistStreamInit_Release(
693 IPersistStreamInit *iface)
695 domdoc* This = impl_from_IPersistStreamInit(iface);
696 return IXMLDOMDocument3_Release(&This->IXMLDOMDocument3_iface);
699 static HRESULT WINAPI PersistStreamInit_GetClassID(
700 IPersistStreamInit *iface, CLSID *classid)
702 domdoc* This = impl_from_IPersistStreamInit(iface);
703 TRACE("(%p)->(%p)\n", This, classid);
705 if(!classid)
706 return E_POINTER;
708 *classid = *DOMDocument_version(This->properties->version);
710 return S_OK;
713 static HRESULT WINAPI PersistStreamInit_IsDirty(
714 IPersistStreamInit *iface)
716 domdoc *This = impl_from_IPersistStreamInit(iface);
717 FIXME("(%p): stub!\n", This);
718 return S_FALSE;
721 static HRESULT WINAPI PersistStreamInit_Load(
722 IPersistStreamInit *iface, LPSTREAM pStm)
724 domdoc *This = impl_from_IPersistStreamInit(iface);
725 HRESULT hr;
726 HGLOBAL hglobal;
727 DWORD read, written, len;
728 BYTE buf[4096];
729 char *ptr;
730 xmlDocPtr xmldoc = NULL;
732 TRACE("(%p)->(%p)\n", This, pStm);
734 if (!pStm)
735 return E_INVALIDARG;
737 hr = CreateStreamOnHGlobal(NULL, TRUE, &This->stream);
738 if (FAILED(hr))
739 return hr;
743 IStream_Read(pStm, buf, sizeof(buf), &read);
744 hr = IStream_Write(This->stream, buf, read, &written);
745 } while(SUCCEEDED(hr) && written != 0 && read != 0);
747 if (FAILED(hr))
749 ERR("Failed to copy stream\n");
750 return hr;
753 hr = GetHGlobalFromStream(This->stream, &hglobal);
754 if (FAILED(hr))
755 return hr;
757 len = GlobalSize(hglobal);
758 ptr = GlobalLock(hglobal);
759 if (len != 0)
760 xmldoc = doparse(This, ptr, len, XML_CHAR_ENCODING_NONE);
761 GlobalUnlock(hglobal);
763 if (!xmldoc)
765 ERR("Failed to parse xml\n");
766 return E_FAIL;
769 xmldoc->_private = create_priv();
771 return attach_xmldoc(This, xmldoc);
774 static HRESULT WINAPI PersistStreamInit_Save(
775 IPersistStreamInit *iface, IStream *stream, BOOL clr_dirty)
777 domdoc *This = impl_from_IPersistStreamInit(iface);
778 BSTR xmlString;
779 HRESULT hr;
781 TRACE("(%p)->(%p %d)\n", This, stream, clr_dirty);
783 hr = IXMLDOMDocument3_get_xml(&This->IXMLDOMDocument3_iface, &xmlString);
784 if(hr == S_OK)
786 DWORD len = SysStringLen(xmlString) * sizeof(WCHAR);
788 hr = IStream_Write( stream, xmlString, len, NULL );
789 SysFreeString(xmlString);
792 TRACE("ret 0x%08x\n", hr);
794 return hr;
797 static HRESULT WINAPI PersistStreamInit_GetSizeMax(
798 IPersistStreamInit *iface, ULARGE_INTEGER *pcbSize)
800 domdoc *This = impl_from_IPersistStreamInit(iface);
801 TRACE("(%p)->(%p): stub!\n", This, pcbSize);
802 return E_NOTIMPL;
805 static HRESULT WINAPI PersistStreamInit_InitNew(
806 IPersistStreamInit *iface)
808 domdoc *This = impl_from_IPersistStreamInit(iface);
809 TRACE("(%p)\n", This);
810 return S_OK;
813 static const IPersistStreamInitVtbl xmldoc_IPersistStreamInit_VTable =
815 PersistStreamInit_QueryInterface,
816 PersistStreamInit_AddRef,
817 PersistStreamInit_Release,
818 PersistStreamInit_GetClassID,
819 PersistStreamInit_IsDirty,
820 PersistStreamInit_Load,
821 PersistStreamInit_Save,
822 PersistStreamInit_GetSizeMax,
823 PersistStreamInit_InitNew
826 /* IXMLDOMDocument3 interface */
828 static const tid_t domdoc_se_tids[] = {
829 IXMLDOMNode_tid,
830 IXMLDOMDocument_tid,
831 IXMLDOMDocument2_tid,
832 IXMLDOMDocument3_tid,
836 static HRESULT WINAPI domdoc_QueryInterface( IXMLDOMDocument3 *iface, REFIID riid, void** ppvObject )
838 domdoc *This = impl_from_IXMLDOMDocument3( iface );
840 TRACE("(%p)->(%s %p)\n", This, debugstr_guid( riid ), ppvObject );
842 *ppvObject = NULL;
844 if ( IsEqualGUID( riid, &IID_IUnknown ) ||
845 IsEqualGUID( riid, &IID_IDispatch ) ||
846 IsEqualGUID( riid, &IID_IXMLDOMNode ) ||
847 IsEqualGUID( riid, &IID_IXMLDOMDocument ) ||
848 IsEqualGUID( riid, &IID_IXMLDOMDocument2 )||
849 IsEqualGUID( riid, &IID_IXMLDOMDocument3 ))
851 *ppvObject = iface;
853 else if (IsEqualGUID(&IID_IPersistStream, riid) ||
854 IsEqualGUID(&IID_IPersistStreamInit, riid))
856 *ppvObject = &This->IPersistStreamInit_iface;
858 else if (IsEqualGUID(&IID_IObjectWithSite, riid))
860 *ppvObject = &This->IObjectWithSite_iface;
862 else if (IsEqualGUID(&IID_IObjectSafety, riid))
864 *ppvObject = &This->IObjectSafety_iface;
866 else if( IsEqualGUID( riid, &IID_ISupportErrorInfo ))
868 return node_create_supporterrorinfo(domdoc_se_tids, ppvObject);
870 else if(node_query_interface(&This->node, riid, ppvObject))
872 return *ppvObject ? S_OK : E_NOINTERFACE;
874 else if (IsEqualGUID( riid, &IID_IConnectionPointContainer ))
876 *ppvObject = &This->IConnectionPointContainer_iface;
878 else
880 TRACE("interface %s not implemented\n", debugstr_guid(riid));
881 return E_NOINTERFACE;
884 IUnknown_AddRef((IUnknown*)*ppvObject);
886 return S_OK;
889 static ULONG WINAPI domdoc_AddRef( IXMLDOMDocument3 *iface )
891 domdoc *This = impl_from_IXMLDOMDocument3( iface );
892 ULONG ref = InterlockedIncrement( &This->ref );
893 TRACE("(%p)->(%d)\n", This, ref );
894 return ref;
897 static ULONG WINAPI domdoc_Release( IXMLDOMDocument3 *iface )
899 domdoc *This = impl_from_IXMLDOMDocument3( iface );
900 LONG ref = InterlockedDecrement( &This->ref );
902 TRACE("(%p)->(%d)\n", This, ref );
904 if ( ref == 0 )
906 int eid;
908 if(This->bsc)
909 detach_bsc(This->bsc);
911 if (This->site)
912 IUnknown_Release( This->site );
913 destroy_xmlnode(&This->node);
914 if (This->stream)
915 IStream_Release(This->stream);
917 for (eid = 0; eid < EVENTID_LAST; eid++)
918 if (This->events[eid]) IDispatch_Release(This->events[eid]);
920 release_namespaces(This);
921 heap_free(This);
924 return ref;
927 static HRESULT WINAPI domdoc_GetTypeInfoCount( IXMLDOMDocument3 *iface, UINT* pctinfo )
929 domdoc *This = impl_from_IXMLDOMDocument3( iface );
930 return IDispatchEx_GetTypeInfoCount(&This->node.dispex.IDispatchEx_iface, pctinfo);
933 static HRESULT WINAPI domdoc_GetTypeInfo(
934 IXMLDOMDocument3 *iface,
935 UINT iTInfo, LCID lcid, ITypeInfo** ppTInfo )
937 domdoc *This = impl_from_IXMLDOMDocument3( iface );
938 return IDispatchEx_GetTypeInfo(&This->node.dispex.IDispatchEx_iface, iTInfo, lcid, ppTInfo);
941 static HRESULT WINAPI domdoc_GetIDsOfNames(
942 IXMLDOMDocument3 *iface,
943 REFIID riid,
944 LPOLESTR* rgszNames,
945 UINT cNames,
946 LCID lcid,
947 DISPID* rgDispId)
949 domdoc *This = impl_from_IXMLDOMDocument3( iface );
950 return IDispatchEx_GetIDsOfNames(&This->node.dispex.IDispatchEx_iface,
951 riid, rgszNames, cNames, lcid, rgDispId);
954 static HRESULT WINAPI domdoc_Invoke(
955 IXMLDOMDocument3 *iface,
956 DISPID dispIdMember,
957 REFIID riid,
958 LCID lcid,
959 WORD wFlags,
960 DISPPARAMS* pDispParams,
961 VARIANT* pVarResult,
962 EXCEPINFO* pExcepInfo,
963 UINT* puArgErr)
965 domdoc *This = impl_from_IXMLDOMDocument3( iface );
966 return IDispatchEx_Invoke(&This->node.dispex.IDispatchEx_iface,
967 dispIdMember, riid, lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
970 static HRESULT WINAPI domdoc_get_nodeName(
971 IXMLDOMDocument3 *iface,
972 BSTR* name )
974 domdoc *This = impl_from_IXMLDOMDocument3( iface );
976 static const WCHAR documentW[] = {'#','d','o','c','u','m','e','n','t',0};
978 TRACE("(%p)->(%p)\n", This, name);
980 return return_bstr(documentW, name);
984 static HRESULT WINAPI domdoc_get_nodeValue(
985 IXMLDOMDocument3 *iface,
986 VARIANT* value )
988 domdoc *This = impl_from_IXMLDOMDocument3( iface );
990 TRACE("(%p)->(%p)\n", This, value);
992 if(!value)
993 return E_INVALIDARG;
995 V_VT(value) = VT_NULL;
996 V_BSTR(value) = NULL; /* tests show that we should do this */
997 return S_FALSE;
1001 static HRESULT WINAPI domdoc_put_nodeValue(
1002 IXMLDOMDocument3 *iface,
1003 VARIANT value)
1005 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1006 TRACE("(%p)->(%s)\n", This, debugstr_variant(&value));
1007 return E_FAIL;
1011 static HRESULT WINAPI domdoc_get_nodeType(
1012 IXMLDOMDocument3 *iface,
1013 DOMNodeType* type )
1015 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1017 TRACE("(%p)->(%p)\n", This, type);
1019 *type = NODE_DOCUMENT;
1020 return S_OK;
1024 static HRESULT WINAPI domdoc_get_parentNode(
1025 IXMLDOMDocument3 *iface,
1026 IXMLDOMNode** parent )
1028 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1030 TRACE("(%p)->(%p)\n", This, parent);
1032 return node_get_parent(&This->node, parent);
1036 static HRESULT WINAPI domdoc_get_childNodes(
1037 IXMLDOMDocument3 *iface,
1038 IXMLDOMNodeList** childList )
1040 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1042 TRACE("(%p)->(%p)\n", This, childList);
1044 return node_get_child_nodes(&This->node, childList);
1048 static HRESULT WINAPI domdoc_get_firstChild(
1049 IXMLDOMDocument3 *iface,
1050 IXMLDOMNode** firstChild )
1052 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1054 TRACE("(%p)->(%p)\n", This, firstChild);
1056 return node_get_first_child(&This->node, firstChild);
1060 static HRESULT WINAPI domdoc_get_lastChild(
1061 IXMLDOMDocument3 *iface,
1062 IXMLDOMNode** lastChild )
1064 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1066 TRACE("(%p)->(%p)\n", This, lastChild);
1068 return node_get_last_child(&This->node, lastChild);
1072 static HRESULT WINAPI domdoc_get_previousSibling(
1073 IXMLDOMDocument3 *iface,
1074 IXMLDOMNode** previousSibling )
1076 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1078 TRACE("(%p)->(%p)\n", This, previousSibling);
1080 return return_null_node(previousSibling);
1084 static HRESULT WINAPI domdoc_get_nextSibling(
1085 IXMLDOMDocument3 *iface,
1086 IXMLDOMNode** nextSibling )
1088 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1090 TRACE("(%p)->(%p)\n", This, nextSibling);
1092 return return_null_node(nextSibling);
1096 static HRESULT WINAPI domdoc_get_attributes(
1097 IXMLDOMDocument3 *iface,
1098 IXMLDOMNamedNodeMap** attributeMap )
1100 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1102 TRACE("(%p)->(%p)\n", This, attributeMap);
1104 return return_null_ptr((void**)attributeMap);
1108 static HRESULT WINAPI domdoc_insertBefore(
1109 IXMLDOMDocument3 *iface,
1110 IXMLDOMNode* newChild,
1111 VARIANT refChild,
1112 IXMLDOMNode** outNewChild )
1114 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1116 TRACE("(%p)->(%p %s %p)\n", This, newChild, debugstr_variant(&refChild), outNewChild);
1118 return node_insert_before(&This->node, newChild, &refChild, outNewChild);
1122 static HRESULT WINAPI domdoc_replaceChild(
1123 IXMLDOMDocument3 *iface,
1124 IXMLDOMNode* newChild,
1125 IXMLDOMNode* oldChild,
1126 IXMLDOMNode** outOldChild)
1128 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1130 TRACE("(%p)->(%p %p %p)\n", This, newChild, oldChild, outOldChild);
1132 return node_replace_child(&This->node, newChild, oldChild, outOldChild);
1136 static HRESULT WINAPI domdoc_removeChild(
1137 IXMLDOMDocument3 *iface,
1138 IXMLDOMNode *child,
1139 IXMLDOMNode **oldChild)
1141 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1142 TRACE("(%p)->(%p %p)\n", This, child, oldChild);
1143 return node_remove_child(&This->node, child, oldChild);
1147 static HRESULT WINAPI domdoc_appendChild(
1148 IXMLDOMDocument3 *iface,
1149 IXMLDOMNode *child,
1150 IXMLDOMNode **outChild)
1152 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1153 TRACE("(%p)->(%p %p)\n", This, child, outChild);
1154 return node_append_child(&This->node, child, outChild);
1158 static HRESULT WINAPI domdoc_hasChildNodes(
1159 IXMLDOMDocument3 *iface,
1160 VARIANT_BOOL *ret)
1162 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1163 TRACE("(%p)->(%p)\n", This, ret);
1164 return node_has_childnodes(&This->node, ret);
1168 static HRESULT WINAPI domdoc_get_ownerDocument(
1169 IXMLDOMDocument3 *iface,
1170 IXMLDOMDocument **doc)
1172 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1173 TRACE("(%p)->(%p)\n", This, doc);
1174 return node_get_owner_doc(&This->node, doc);
1178 static HRESULT WINAPI domdoc_cloneNode(
1179 IXMLDOMDocument3 *iface,
1180 VARIANT_BOOL deep,
1181 IXMLDOMNode** outNode)
1183 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1184 TRACE("(%p)->(%d %p)\n", This, deep, outNode);
1185 return node_clone( &This->node, deep, outNode );
1189 static HRESULT WINAPI domdoc_get_nodeTypeString(
1190 IXMLDOMDocument3 *iface,
1191 BSTR *p)
1193 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1194 static const WCHAR documentW[] = {'d','o','c','u','m','e','n','t',0};
1196 TRACE("(%p)->(%p)\n", This, p);
1198 return return_bstr(documentW, p);
1202 static HRESULT WINAPI domdoc_get_text(
1203 IXMLDOMDocument3 *iface,
1204 BSTR *p)
1206 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1207 TRACE("(%p)->(%p)\n", This, p);
1208 return node_get_text(&This->node, p);
1212 static HRESULT WINAPI domdoc_put_text(
1213 IXMLDOMDocument3 *iface,
1214 BSTR text )
1216 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1217 TRACE("(%p)->(%s)\n", This, debugstr_w(text));
1218 return E_FAIL;
1222 static HRESULT WINAPI domdoc_get_specified(
1223 IXMLDOMDocument3 *iface,
1224 VARIANT_BOOL* isSpecified )
1226 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1227 FIXME("(%p)->(%p) stub!\n", This, isSpecified);
1228 *isSpecified = VARIANT_TRUE;
1229 return S_OK;
1233 static HRESULT WINAPI domdoc_get_definition(
1234 IXMLDOMDocument3 *iface,
1235 IXMLDOMNode** definitionNode )
1237 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1238 FIXME("(%p)->(%p)\n", This, definitionNode);
1239 return E_NOTIMPL;
1243 static HRESULT WINAPI domdoc_get_nodeTypedValue(
1244 IXMLDOMDocument3 *iface,
1245 VARIANT* v )
1247 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1248 TRACE("(%p)->(%p)\n", This, v);
1249 return return_null_var(v);
1252 static HRESULT WINAPI domdoc_put_nodeTypedValue(
1253 IXMLDOMDocument3 *iface,
1254 VARIANT typedValue )
1256 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1257 FIXME("(%p)->(%s)\n", This, debugstr_variant(&typedValue));
1258 return E_NOTIMPL;
1262 static HRESULT WINAPI domdoc_get_dataType(
1263 IXMLDOMDocument3 *iface,
1264 VARIANT* typename )
1266 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1267 TRACE("(%p)->(%p)\n", This, typename);
1268 return return_null_var( typename );
1272 static HRESULT WINAPI domdoc_put_dataType(
1273 IXMLDOMDocument3 *iface,
1274 BSTR dataTypeName )
1276 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1278 FIXME("(%p)->(%s)\n", This, debugstr_w(dataTypeName));
1280 if(!dataTypeName)
1281 return E_INVALIDARG;
1283 return E_FAIL;
1286 static int XMLCALL domdoc_get_xml_writecallback(void *ctx, const char *data, int len)
1288 return xmlBufferAdd((xmlBufferPtr)ctx, (xmlChar*)data, len) == 0 ? len : 0;
1291 static HRESULT WINAPI domdoc_get_xml(
1292 IXMLDOMDocument3 *iface,
1293 BSTR* p)
1295 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1296 xmlSaveCtxtPtr ctxt;
1297 xmlBufferPtr buf;
1298 int options;
1299 long ret;
1301 TRACE("(%p)->(%p)\n", This, p);
1303 if(!p)
1304 return E_INVALIDARG;
1306 *p = NULL;
1308 buf = xmlBufferCreate();
1309 if(!buf)
1310 return E_OUTOFMEMORY;
1312 options = XML_SAVE_FORMAT | XML_SAVE_NO_DECL;
1313 ctxt = xmlSaveToIO(domdoc_get_xml_writecallback, NULL, buf, "UTF-8", options);
1315 if(!ctxt)
1317 xmlBufferFree(buf);
1318 return E_OUTOFMEMORY;
1321 ret = xmlSaveDoc(ctxt, get_doc(This));
1322 /* flushes on close */
1323 xmlSaveClose(ctxt);
1325 TRACE("%ld, len=%d\n", ret, xmlBufferLength(buf));
1326 if(ret != -1 && xmlBufferLength(buf) > 0)
1328 BSTR content;
1330 content = bstr_from_xmlChar(xmlBufferContent(buf));
1331 content = EnsureCorrectEOL(content);
1333 *p = content;
1335 else
1337 *p = SysAllocStringLen(NULL, 0);
1340 xmlBufferFree(buf);
1342 return *p ? S_OK : E_OUTOFMEMORY;
1346 static HRESULT WINAPI domdoc_transformNode(
1347 IXMLDOMDocument3 *iface,
1348 IXMLDOMNode *node,
1349 BSTR *p)
1351 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1352 TRACE("(%p)->(%p %p)\n", This, node, p);
1353 return node_transform_node(&This->node, node, p);
1357 static HRESULT WINAPI domdoc_selectNodes(
1358 IXMLDOMDocument3 *iface,
1359 BSTR p,
1360 IXMLDOMNodeList **outList)
1362 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1363 TRACE("(%p)->(%s %p)\n", This, debugstr_w(p), outList);
1364 return node_select_nodes(&This->node, p, outList);
1368 static HRESULT WINAPI domdoc_selectSingleNode(
1369 IXMLDOMDocument3 *iface,
1370 BSTR p,
1371 IXMLDOMNode **outNode)
1373 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1374 TRACE("(%p)->(%s %p)\n", This, debugstr_w(p), outNode);
1375 return node_select_singlenode(&This->node, p, outNode);
1379 static HRESULT WINAPI domdoc_get_parsed(
1380 IXMLDOMDocument3 *iface,
1381 VARIANT_BOOL* isParsed )
1383 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1384 FIXME("(%p)->(%p) stub!\n", This, isParsed);
1385 *isParsed = VARIANT_TRUE;
1386 return S_OK;
1389 static HRESULT WINAPI domdoc_get_namespaceURI(
1390 IXMLDOMDocument3 *iface,
1391 BSTR* namespaceURI )
1393 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1394 TRACE("(%p)->(%p)\n", This, namespaceURI);
1395 return return_null_bstr( namespaceURI );
1398 static HRESULT WINAPI domdoc_get_prefix(
1399 IXMLDOMDocument3 *iface,
1400 BSTR* prefix )
1402 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1403 TRACE("(%p)->(%p)\n", This, prefix);
1404 return return_null_bstr( prefix );
1408 static HRESULT WINAPI domdoc_get_baseName(
1409 IXMLDOMDocument3 *iface,
1410 BSTR* name )
1412 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1413 TRACE("(%p)->(%p)\n", This, name);
1414 return return_null_bstr( name );
1418 static HRESULT WINAPI domdoc_transformNodeToObject(
1419 IXMLDOMDocument3 *iface,
1420 IXMLDOMNode* stylesheet,
1421 VARIANT outputObject)
1423 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1424 FIXME("(%p)->(%p %s)\n", This, stylesheet, debugstr_variant(&outputObject));
1425 return E_NOTIMPL;
1429 static HRESULT WINAPI domdoc_get_doctype(
1430 IXMLDOMDocument3 *iface,
1431 IXMLDOMDocumentType** doctype )
1433 domdoc *This = impl_from_IXMLDOMDocument3(iface);
1434 IXMLDOMNode *node;
1435 xmlDtdPtr dtd;
1436 HRESULT hr;
1438 TRACE("(%p)->(%p)\n", This, doctype);
1440 if (!doctype) return E_INVALIDARG;
1442 *doctype = NULL;
1444 dtd = xmlGetIntSubset(get_doc(This));
1445 if (!dtd) return S_FALSE;
1447 node = create_node((xmlNodePtr)dtd);
1448 if (!node) return S_FALSE;
1450 hr = IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMDocumentType, (void**)doctype);
1451 IXMLDOMNode_Release(node);
1453 return hr;
1457 static HRESULT WINAPI domdoc_get_implementation(
1458 IXMLDOMDocument3 *iface,
1459 IXMLDOMImplementation** impl )
1461 domdoc *This = impl_from_IXMLDOMDocument3(iface);
1463 TRACE("(%p)->(%p)\n", This, impl);
1465 if(!impl)
1466 return E_INVALIDARG;
1468 *impl = (IXMLDOMImplementation*)create_doc_Implementation();
1470 return S_OK;
1473 static HRESULT WINAPI domdoc_get_documentElement(
1474 IXMLDOMDocument3 *iface,
1475 IXMLDOMElement** DOMElement )
1477 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1478 IXMLDOMNode *element_node;
1479 xmlNodePtr root;
1480 HRESULT hr;
1482 TRACE("(%p)->(%p)\n", This, DOMElement);
1484 if(!DOMElement)
1485 return E_INVALIDARG;
1487 *DOMElement = NULL;
1489 root = xmlDocGetRootElement( get_doc(This) );
1490 if ( !root )
1491 return S_FALSE;
1493 element_node = create_node( root );
1494 if(!element_node) return S_FALSE;
1496 hr = IXMLDOMNode_QueryInterface(element_node, &IID_IXMLDOMElement, (void**)DOMElement);
1497 IXMLDOMNode_Release(element_node);
1499 return hr;
1503 static HRESULT WINAPI domdoc_put_documentElement(
1504 IXMLDOMDocument3 *iface,
1505 IXMLDOMElement* DOMElement )
1507 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1508 IXMLDOMNode *elementNode;
1509 xmlNodePtr oldRoot;
1510 xmlnode *xmlNode;
1511 HRESULT hr;
1513 TRACE("(%p)->(%p)\n", This, DOMElement);
1515 hr = IXMLDOMElement_QueryInterface( DOMElement, &IID_IXMLDOMNode, (void**)&elementNode );
1516 if(FAILED(hr))
1517 return hr;
1519 xmlNode = get_node_obj( elementNode );
1520 if(!xmlNode) return E_FAIL;
1522 if(!xmlNode->node->parent)
1523 if(xmldoc_remove_orphan(xmlNode->node->doc, xmlNode->node) != S_OK)
1524 WARN("%p is not an orphan of %p\n", xmlNode->node->doc, xmlNode->node);
1526 oldRoot = xmlDocSetRootElement( get_doc(This), xmlNode->node);
1527 IXMLDOMNode_Release( elementNode );
1529 if(oldRoot)
1530 xmldoc_add_orphan(oldRoot->doc, oldRoot);
1532 return S_OK;
1536 static HRESULT WINAPI domdoc_createElement(
1537 IXMLDOMDocument3 *iface,
1538 BSTR tagname,
1539 IXMLDOMElement** element )
1541 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1542 IXMLDOMNode *node;
1543 VARIANT type;
1544 HRESULT hr;
1546 TRACE("(%p)->(%s %p)\n", This, debugstr_w(tagname), element);
1548 if (!element || !tagname) return E_INVALIDARG;
1550 V_VT(&type) = VT_I1;
1551 V_I1(&type) = NODE_ELEMENT;
1553 hr = IXMLDOMDocument3_createNode(iface, type, tagname, NULL, &node);
1554 if (hr == S_OK)
1556 IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMElement, (void**)element);
1557 IXMLDOMNode_Release(node);
1560 return hr;
1564 static HRESULT WINAPI domdoc_createDocumentFragment(
1565 IXMLDOMDocument3 *iface,
1566 IXMLDOMDocumentFragment** frag )
1568 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1569 IXMLDOMNode *node;
1570 VARIANT type;
1571 HRESULT hr;
1573 TRACE("(%p)->(%p)\n", This, frag);
1575 if (!frag) return E_INVALIDARG;
1577 *frag = NULL;
1579 V_VT(&type) = VT_I1;
1580 V_I1(&type) = NODE_DOCUMENT_FRAGMENT;
1582 hr = IXMLDOMDocument3_createNode(iface, type, NULL, NULL, &node);
1583 if (hr == S_OK)
1585 IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMDocumentFragment, (void**)frag);
1586 IXMLDOMNode_Release(node);
1589 return hr;
1593 static HRESULT WINAPI domdoc_createTextNode(
1594 IXMLDOMDocument3 *iface,
1595 BSTR data,
1596 IXMLDOMText** text )
1598 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1599 IXMLDOMNode *node;
1600 VARIANT type;
1601 HRESULT hr;
1603 TRACE("(%p)->(%s %p)\n", This, debugstr_w(data), text);
1605 if (!text) return E_INVALIDARG;
1607 *text = NULL;
1609 V_VT(&type) = VT_I1;
1610 V_I1(&type) = NODE_TEXT;
1612 hr = IXMLDOMDocument3_createNode(iface, type, NULL, NULL, &node);
1613 if (hr == S_OK)
1615 IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMText, (void**)text);
1616 IXMLDOMNode_Release(node);
1617 hr = IXMLDOMText_put_data(*text, data);
1620 return hr;
1624 static HRESULT WINAPI domdoc_createComment(
1625 IXMLDOMDocument3 *iface,
1626 BSTR data,
1627 IXMLDOMComment** comment )
1629 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1630 VARIANT type;
1631 HRESULT hr;
1632 IXMLDOMNode *node;
1634 TRACE("(%p)->(%s %p)\n", This, debugstr_w(data), comment);
1636 if (!comment) return E_INVALIDARG;
1638 *comment = NULL;
1640 V_VT(&type) = VT_I1;
1641 V_I1(&type) = NODE_COMMENT;
1643 hr = IXMLDOMDocument3_createNode(iface, type, NULL, NULL, &node);
1644 if (hr == S_OK)
1646 IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMComment, (void**)comment);
1647 IXMLDOMNode_Release(node);
1648 hr = IXMLDOMComment_put_data(*comment, data);
1651 return hr;
1655 static HRESULT WINAPI domdoc_createCDATASection(
1656 IXMLDOMDocument3 *iface,
1657 BSTR data,
1658 IXMLDOMCDATASection** cdata )
1660 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1661 IXMLDOMNode *node;
1662 VARIANT type;
1663 HRESULT hr;
1665 TRACE("(%p)->(%s %p)\n", This, debugstr_w(data), cdata);
1667 if (!cdata) return E_INVALIDARG;
1669 *cdata = NULL;
1671 V_VT(&type) = VT_I1;
1672 V_I1(&type) = NODE_CDATA_SECTION;
1674 hr = IXMLDOMDocument3_createNode(iface, type, NULL, NULL, &node);
1675 if (hr == S_OK)
1677 IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMCDATASection, (void**)cdata);
1678 IXMLDOMNode_Release(node);
1679 hr = IXMLDOMCDATASection_put_data(*cdata, data);
1682 return hr;
1686 static HRESULT WINAPI domdoc_createProcessingInstruction(
1687 IXMLDOMDocument3 *iface,
1688 BSTR target,
1689 BSTR data,
1690 IXMLDOMProcessingInstruction** pi )
1692 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1693 IXMLDOMNode *node;
1694 VARIANT type;
1695 HRESULT hr;
1697 TRACE("(%p)->(%s %s %p)\n", This, debugstr_w(target), debugstr_w(data), pi);
1699 if (!pi) return E_INVALIDARG;
1701 *pi = NULL;
1703 V_VT(&type) = VT_I1;
1704 V_I1(&type) = NODE_PROCESSING_INSTRUCTION;
1706 hr = IXMLDOMDocument3_createNode(iface, type, target, NULL, &node);
1707 if (hr == S_OK)
1709 xmlnode *node_obj;
1711 /* this is to bypass check in ::put_data() that blocks "<?xml" PIs */
1712 node_obj = get_node_obj(node);
1713 hr = node_set_content(node_obj, data);
1715 IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMProcessingInstruction, (void**)pi);
1716 IXMLDOMNode_Release(node);
1719 return hr;
1723 static HRESULT WINAPI domdoc_createAttribute(
1724 IXMLDOMDocument3 *iface,
1725 BSTR name,
1726 IXMLDOMAttribute** attribute )
1728 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1729 IXMLDOMNode *node;
1730 VARIANT type;
1731 HRESULT hr;
1733 TRACE("(%p)->(%s %p)\n", This, debugstr_w(name), attribute);
1735 if (!attribute || !name) return E_INVALIDARG;
1737 V_VT(&type) = VT_I1;
1738 V_I1(&type) = NODE_ATTRIBUTE;
1740 hr = IXMLDOMDocument3_createNode(iface, type, name, NULL, &node);
1741 if (hr == S_OK)
1743 IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMAttribute, (void**)attribute);
1744 IXMLDOMNode_Release(node);
1747 return hr;
1751 static HRESULT WINAPI domdoc_createEntityReference(
1752 IXMLDOMDocument3 *iface,
1753 BSTR name,
1754 IXMLDOMEntityReference** entityref )
1756 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1757 IXMLDOMNode *node;
1758 VARIANT type;
1759 HRESULT hr;
1761 TRACE("(%p)->(%s %p)\n", This, debugstr_w(name), entityref);
1763 if (!entityref) return E_INVALIDARG;
1765 *entityref = NULL;
1767 V_VT(&type) = VT_I1;
1768 V_I1(&type) = NODE_ENTITY_REFERENCE;
1770 hr = IXMLDOMDocument3_createNode(iface, type, name, NULL, &node);
1771 if (hr == S_OK)
1773 IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMEntityReference, (void**)entityref);
1774 IXMLDOMNode_Release(node);
1777 return hr;
1780 xmlChar* tagName_to_XPath(const BSTR tagName)
1782 xmlChar *query, *tmp;
1783 static const xmlChar mod_pre[] = "*[local-name()='";
1784 static const xmlChar mod_post[] = "']";
1785 static const xmlChar prefix[] = "descendant::";
1786 const WCHAR *tokBegin, *tokEnd;
1787 int len;
1789 query = xmlStrdup(prefix);
1791 tokBegin = tagName;
1792 while (tokBegin && *tokBegin)
1794 switch (*tokBegin)
1796 case '/':
1797 query = xmlStrcat(query, BAD_CAST "/");
1798 ++tokBegin;
1799 break;
1800 case '*':
1801 query = xmlStrcat(query, BAD_CAST "*");
1802 ++tokBegin;
1803 break;
1804 default:
1805 query = xmlStrcat(query, mod_pre);
1806 tokEnd = tokBegin;
1807 while (*tokEnd && *tokEnd != '/')
1808 ++tokEnd;
1809 len = WideCharToMultiByte(CP_UTF8, 0, tokBegin, tokEnd-tokBegin, NULL, 0, NULL, NULL);
1810 tmp = xmlMalloc(len);
1811 WideCharToMultiByte(CP_UTF8, 0, tokBegin, tokEnd-tokBegin, (char*)tmp, len, NULL, NULL);
1812 query = xmlStrncat(query, tmp, len);
1813 xmlFree(tmp);
1814 tokBegin = tokEnd;
1815 query = xmlStrcat(query, mod_post);
1819 return query;
1822 static HRESULT WINAPI domdoc_getElementsByTagName(
1823 IXMLDOMDocument3 *iface,
1824 BSTR tagName,
1825 IXMLDOMNodeList** resultList )
1827 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1828 xmlChar *query;
1829 HRESULT hr;
1830 BOOL XPath;
1832 TRACE("(%p)->(%s, %p)\n", This, debugstr_w(tagName), resultList);
1834 if (!tagName || !resultList) return E_INVALIDARG;
1836 XPath = This->properties->XPath;
1837 This->properties->XPath = TRUE;
1838 query = tagName_to_XPath(tagName);
1839 hr = create_selection((xmlNodePtr)get_doc(This), query, resultList);
1840 xmlFree(query);
1841 This->properties->XPath = XPath;
1843 return hr;
1846 static HRESULT get_node_type(VARIANT Type, DOMNodeType * type)
1848 VARIANT tmp;
1849 HRESULT hr;
1851 VariantInit(&tmp);
1852 hr = VariantChangeType(&tmp, &Type, 0, VT_I4);
1853 if(FAILED(hr))
1854 return E_INVALIDARG;
1856 *type = V_I4(&tmp);
1858 return S_OK;
1861 static HRESULT WINAPI domdoc_createNode(
1862 IXMLDOMDocument3 *iface,
1863 VARIANT Type,
1864 BSTR name,
1865 BSTR namespaceURI,
1866 IXMLDOMNode** node )
1868 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1869 DOMNodeType node_type;
1870 xmlNodePtr xmlnode;
1871 xmlChar *xml_name, *href;
1872 HRESULT hr;
1874 TRACE("(%p)->(%s %s %s %p)\n", This, debugstr_variant(&Type), debugstr_w(name), debugstr_w(namespaceURI), node);
1876 if(!node) return E_INVALIDARG;
1878 hr = get_node_type(Type, &node_type);
1879 if(FAILED(hr)) return hr;
1881 if(namespaceURI && namespaceURI[0] && node_type != NODE_ELEMENT)
1882 FIXME("nodes with namespaces currently not supported.\n");
1884 TRACE("node_type %d\n", node_type);
1886 /* exit earlier for types that need name */
1887 switch(node_type)
1889 case NODE_ELEMENT:
1890 case NODE_ATTRIBUTE:
1891 case NODE_ENTITY_REFERENCE:
1892 case NODE_PROCESSING_INSTRUCTION:
1893 if (!name || *name == 0) return E_FAIL;
1894 break;
1895 default:
1896 break;
1899 xml_name = xmlchar_from_wchar(name);
1900 /* prevent empty href to be allocated */
1901 href = namespaceURI ? xmlchar_from_wchar(namespaceURI) : NULL;
1903 switch(node_type)
1905 case NODE_ELEMENT:
1907 xmlChar *local, *prefix;
1909 local = xmlSplitQName2(xml_name, &prefix);
1911 xmlnode = xmlNewDocNode(get_doc(This), NULL, local ? local : xml_name, NULL);
1913 /* allow to create default namespace xmlns= */
1914 if (local || (href && *href))
1916 xmlNsPtr ns = xmlNewNs(xmlnode, href, prefix);
1917 xmlSetNs(xmlnode, ns);
1920 xmlFree(local);
1921 xmlFree(prefix);
1923 break;
1925 case NODE_ATTRIBUTE:
1926 xmlnode = (xmlNodePtr)xmlNewDocProp(get_doc(This), xml_name, NULL);
1927 break;
1928 case NODE_TEXT:
1929 xmlnode = (xmlNodePtr)xmlNewDocText(get_doc(This), NULL);
1930 break;
1931 case NODE_CDATA_SECTION:
1932 xmlnode = xmlNewCDataBlock(get_doc(This), NULL, 0);
1933 break;
1934 case NODE_ENTITY_REFERENCE:
1935 xmlnode = xmlNewReference(get_doc(This), xml_name);
1936 break;
1937 case NODE_PROCESSING_INSTRUCTION:
1938 #ifdef HAVE_XMLNEWDOCPI
1939 xmlnode = xmlNewDocPI(get_doc(This), xml_name, NULL);
1940 #else
1941 FIXME("xmlNewDocPI() not supported, use libxml2 2.6.15 or greater\n");
1942 xmlnode = NULL;
1943 #endif
1944 break;
1945 case NODE_COMMENT:
1946 xmlnode = xmlNewDocComment(get_doc(This), NULL);
1947 break;
1948 case NODE_DOCUMENT_FRAGMENT:
1949 xmlnode = xmlNewDocFragment(get_doc(This));
1950 break;
1951 /* unsupported types */
1952 case NODE_DOCUMENT:
1953 case NODE_DOCUMENT_TYPE:
1954 case NODE_ENTITY:
1955 case NODE_NOTATION:
1956 heap_free(xml_name);
1957 return E_INVALIDARG;
1958 default:
1959 FIXME("unhandled node type %d\n", node_type);
1960 xmlnode = NULL;
1961 break;
1964 *node = create_node(xmlnode);
1965 heap_free(xml_name);
1966 heap_free(href);
1968 if(*node)
1970 TRACE("created node (%d, %p, %p)\n", node_type, *node, xmlnode);
1971 xmldoc_add_orphan(xmlnode->doc, xmlnode);
1972 return S_OK;
1975 return E_FAIL;
1978 static HRESULT WINAPI domdoc_nodeFromID(
1979 IXMLDOMDocument3 *iface,
1980 BSTR idString,
1981 IXMLDOMNode** node )
1983 domdoc *This = impl_from_IXMLDOMDocument3(iface);
1984 FIXME("(%p)->(%s %p)\n", This, debugstr_w(idString), node);
1985 return E_NOTIMPL;
1988 static HRESULT domdoc_onDataAvailable(void *obj, char *ptr, DWORD len)
1990 domdoc *This = obj;
1991 xmlDocPtr xmldoc;
1993 xmldoc = doparse(This, ptr, len, XML_CHAR_ENCODING_NONE);
1994 if(xmldoc) {
1995 xmldoc->_private = create_priv();
1996 return attach_xmldoc(This, xmldoc);
1999 return S_OK;
2002 static HRESULT domdoc_load_moniker(domdoc *This, IMoniker *mon)
2004 bsc_t *bsc;
2005 HRESULT hr;
2007 hr = bind_url(mon, domdoc_onDataAvailable, This, &bsc);
2008 if(FAILED(hr))
2009 return hr;
2011 if(This->bsc) {
2012 hr = detach_bsc(This->bsc);
2013 if(FAILED(hr))
2014 return hr;
2017 This->bsc = bsc;
2018 return S_OK;
2021 static HRESULT WINAPI domdoc_load(
2022 IXMLDOMDocument3 *iface,
2023 VARIANT source,
2024 VARIANT_BOOL* isSuccessful )
2026 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2027 LPWSTR filename = NULL;
2028 HRESULT hr = S_FALSE;
2029 IXMLDOMDocument3 *pNewDoc = NULL;
2030 IStream *pStream = NULL;
2031 xmlDocPtr xmldoc;
2033 TRACE("(%p)->(%s)\n", This, debugstr_variant(&source));
2035 if (!isSuccessful)
2036 return E_POINTER;
2037 *isSuccessful = VARIANT_FALSE;
2039 assert( &This->node );
2041 switch( V_VT(&source) )
2043 case VT_BSTR:
2044 filename = V_BSTR(&source);
2045 break;
2046 case VT_BSTR|VT_BYREF:
2047 if (!V_BSTRREF(&source)) return E_INVALIDARG;
2048 filename = *V_BSTRREF(&source);
2049 break;
2050 case VT_ARRAY|VT_UI1:
2052 SAFEARRAY *psa = V_ARRAY(&source);
2053 char *str;
2054 LONG len;
2055 UINT dim = SafeArrayGetDim(psa);
2057 switch (dim)
2059 case 0:
2060 ERR("SAFEARRAY == NULL\n");
2061 hr = This->error = E_INVALIDARG;
2062 break;
2063 case 1:
2064 /* Only takes UTF-8 strings.
2065 * NOT NULL-terminated. */
2066 SafeArrayAccessData(psa, (void**)&str);
2067 SafeArrayGetUBound(psa, 1, &len);
2069 if ((xmldoc = doparse(This, str, ++len, XML_CHAR_ENCODING_UTF8)))
2071 hr = This->error = S_OK;
2072 *isSuccessful = VARIANT_TRUE;
2073 TRACE("parsed document %p\n", xmldoc);
2075 else
2077 This->error = E_FAIL;
2078 TRACE("failed to parse document\n");
2081 SafeArrayUnaccessData(psa);
2083 if(xmldoc)
2085 xmldoc->_private = create_priv();
2086 return attach_xmldoc(This, xmldoc);
2088 break;
2089 default:
2090 FIXME("unhandled SAFEARRAY dim: %d\n", dim);
2091 hr = This->error = E_NOTIMPL;
2094 break;
2095 case VT_UNKNOWN:
2096 hr = IUnknown_QueryInterface(V_UNKNOWN(&source), &IID_IXMLDOMDocument3, (void**)&pNewDoc);
2097 if(hr == S_OK)
2099 if(pNewDoc)
2101 domdoc *newDoc = impl_from_IXMLDOMDocument3( pNewDoc );
2103 xmldoc = xmlCopyDoc(get_doc(newDoc), 1);
2104 xmldoc->_private = create_priv();
2105 hr = attach_xmldoc(This, xmldoc);
2107 if(SUCCEEDED(hr))
2108 *isSuccessful = VARIANT_TRUE;
2110 return hr;
2113 hr = IUnknown_QueryInterface(V_UNKNOWN(&source), &IID_IStream, (void**)&pStream);
2114 if(hr == S_OK)
2116 IPersistStream *pDocStream;
2117 hr = IUnknown_QueryInterface(iface, &IID_IPersistStream, (void**)&pDocStream);
2118 if(hr == S_OK)
2120 hr = IPersistStream_Load(pDocStream, pStream);
2121 IStream_Release(pStream);
2122 if(hr == S_OK)
2124 *isSuccessful = VARIANT_TRUE;
2126 TRACE("Using IStream to load Document\n");
2127 return S_OK;
2129 else
2131 ERR("xmldoc_IPersistStream_Load failed (%d)\n", hr);
2134 else
2136 ERR("QueryInterface IID_IPersistStream failed (%d)\n", hr);
2139 else
2141 /* ISequentialStream */
2142 FIXME("Unknown type not supported (%d) (%p)(%p)\n", hr, pNewDoc, V_UNKNOWN(&source)->lpVtbl);
2144 break;
2145 default:
2146 FIXME("VT type not supported (%d)\n", V_VT(&source));
2149 if ( filename )
2151 IMoniker *mon;
2153 hr = create_moniker_from_url( filename, &mon);
2154 if ( SUCCEEDED(hr) )
2156 hr = domdoc_load_moniker( This, mon );
2157 IMoniker_Release(mon);
2160 if ( FAILED(hr) )
2161 This->error = E_FAIL;
2162 else
2164 hr = This->error = S_OK;
2165 *isSuccessful = VARIANT_TRUE;
2169 if(!filename || FAILED(hr)) {
2170 xmldoc = xmlNewDoc(NULL);
2171 xmldoc->_private = create_priv();
2172 hr = attach_xmldoc(This, xmldoc);
2173 if(SUCCEEDED(hr))
2174 hr = S_FALSE;
2177 TRACE("ret (%d)\n", hr);
2179 return hr;
2183 static HRESULT WINAPI domdoc_get_readyState(
2184 IXMLDOMDocument3 *iface,
2185 LONG *value )
2187 domdoc *This = impl_from_IXMLDOMDocument3(iface);
2188 FIXME("stub! (%p)->(%p)\n", This, value);
2190 if (!value)
2191 return E_INVALIDARG;
2193 *value = READYSTATE_COMPLETE;
2194 return S_OK;
2198 static HRESULT WINAPI domdoc_get_parseError(
2199 IXMLDOMDocument3 *iface,
2200 IXMLDOMParseError** errorObj )
2202 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2203 static const WCHAR err[] = {'e','r','r','o','r',0};
2204 BSTR error_string = NULL;
2206 FIXME("(%p)->(%p): creating a dummy parseError\n", iface, errorObj);
2208 if(This->error)
2209 error_string = SysAllocString(err);
2211 *errorObj = create_parseError(This->error, NULL, error_string, NULL, 0, 0, 0);
2212 if(!*errorObj) return E_OUTOFMEMORY;
2213 return S_OK;
2217 static HRESULT WINAPI domdoc_get_url(
2218 IXMLDOMDocument3 *iface,
2219 BSTR* urlString )
2221 domdoc *This = impl_from_IXMLDOMDocument3(iface);
2222 FIXME("(%p)->(%p)\n", This, urlString);
2223 return E_NOTIMPL;
2227 static HRESULT WINAPI domdoc_get_async(
2228 IXMLDOMDocument3 *iface,
2229 VARIANT_BOOL* isAsync )
2231 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2233 TRACE("(%p)->(%p: %d)\n", This, isAsync, This->async);
2234 *isAsync = This->async;
2235 return S_OK;
2239 static HRESULT WINAPI domdoc_put_async(
2240 IXMLDOMDocument3 *iface,
2241 VARIANT_BOOL isAsync )
2243 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2245 TRACE("(%p)->(%d)\n", This, isAsync);
2246 This->async = isAsync;
2247 return S_OK;
2251 static HRESULT WINAPI domdoc_abort(
2252 IXMLDOMDocument3 *iface )
2254 domdoc *This = impl_from_IXMLDOMDocument3(iface);
2255 FIXME("%p\n", This);
2256 return E_NOTIMPL;
2259 /* don't rely on data to be in BSTR format, treat it as WCHAR string */
2260 static HRESULT WINAPI domdoc_loadXML(
2261 IXMLDOMDocument3 *iface,
2262 BSTR data,
2263 VARIANT_BOOL* isSuccessful )
2265 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2266 xmlDocPtr xmldoc = NULL;
2267 HRESULT hr = S_FALSE, hr2;
2269 TRACE("(%p)->(%s %p)\n", This, debugstr_w(data), isSuccessful );
2271 assert ( &This->node );
2273 if ( isSuccessful )
2275 *isSuccessful = VARIANT_FALSE;
2277 if (data)
2279 WCHAR *ptr = data;
2281 /* skip leading spaces if needed */
2282 if (This->properties->version == MSXML_DEFAULT || This->properties->version == MSXML26)
2283 while (*ptr && isspaceW(*ptr)) ptr++;
2285 xmldoc = doparse(This, (char*)ptr, strlenW(ptr)*sizeof(WCHAR), XML_CHAR_ENCODING_UTF16LE);
2286 if ( !xmldoc )
2288 This->error = E_FAIL;
2289 TRACE("failed to parse document\n");
2291 else
2293 hr = This->error = S_OK;
2294 *isSuccessful = VARIANT_TRUE;
2295 TRACE("parsed document %p\n", xmldoc);
2300 if(!xmldoc)
2301 xmldoc = xmlNewDoc(NULL);
2302 xmldoc->_private = create_priv();
2303 hr2 = attach_xmldoc(This, xmldoc);
2304 if( FAILED(hr2) )
2305 hr = hr2;
2307 return hr;
2310 static int XMLCALL domdoc_save_writecallback(void *ctx, const char *buffer, int len)
2312 DWORD written = -1;
2314 if(!WriteFile(ctx, buffer, len, &written, NULL))
2316 WARN("write error\n");
2317 return -1;
2319 else
2320 return written;
2323 static int XMLCALL domdoc_save_closecallback(void *ctx)
2325 return CloseHandle(ctx) ? 0 : -1;
2328 static int XMLCALL domdoc_stream_save_writecallback(void *ctx, const char *buffer, int len)
2330 ULONG written = 0;
2331 HRESULT hr;
2333 hr = IStream_Write((IStream*)ctx, buffer, len, &written);
2334 TRACE("0x%08x %p %d %u\n", hr, buffer, len, written);
2335 if (hr != S_OK)
2337 WARN("stream write error: 0x%08x\n", hr);
2338 return -1;
2340 else
2341 return len;
2344 static int XMLCALL domdoc_stream_save_closecallback(void *ctx)
2346 IStream_Release((IStream*)ctx);
2347 return 0;
2350 static HRESULT WINAPI domdoc_save(
2351 IXMLDOMDocument3 *iface,
2352 VARIANT destination )
2354 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2355 xmlSaveCtxtPtr ctx = NULL;
2356 xmlNodePtr xmldecl;
2357 HRESULT ret = S_OK;
2359 TRACE("(%p)->(%s)\n", This, debugstr_variant(&destination));
2361 switch (V_VT(&destination))
2363 case VT_UNKNOWN:
2365 IUnknown *pUnk = V_UNKNOWN(&destination);
2366 IXMLDOMDocument3 *document;
2367 IStream *stream;
2369 ret = IUnknown_QueryInterface(pUnk, &IID_IXMLDOMDocument3, (void**)&document);
2370 if(ret == S_OK)
2372 VARIANT_BOOL success;
2373 BSTR xml;
2375 ret = IXMLDOMDocument3_get_xml(iface, &xml);
2376 if(ret == S_OK)
2378 ret = IXMLDOMDocument3_loadXML(document, xml, &success);
2379 SysFreeString(xml);
2382 IXMLDOMDocument3_Release(document);
2383 return ret;
2386 ret = IUnknown_QueryInterface(pUnk, &IID_IStream, (void**)&stream);
2387 if(ret == S_OK)
2389 int options = get_doc(This)->standalone == -1 ? XML_SAVE_NO_DECL : 0;
2390 ctx = xmlSaveToIO(domdoc_stream_save_writecallback,
2391 domdoc_stream_save_closecallback, stream, NULL, options);
2393 if(!ctx)
2395 IStream_Release(stream);
2396 return E_FAIL;
2400 break;
2402 case VT_BSTR:
2403 case VT_BSTR | VT_BYREF:
2405 int options = get_doc(This)->standalone == -1 ? XML_SAVE_NO_DECL : 0;
2407 /* save with file path */
2408 HANDLE handle = CreateFileW( (V_VT(&destination) & VT_BYREF)? *V_BSTRREF(&destination) : V_BSTR(&destination),
2409 GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL );
2410 if( handle == INVALID_HANDLE_VALUE )
2412 WARN("failed to create file\n");
2413 return E_FAIL;
2416 /* disable top XML declaration */
2417 ctx = xmlSaveToIO(domdoc_save_writecallback, domdoc_save_closecallback,
2418 handle, NULL, options);
2419 if (!ctx)
2421 CloseHandle(handle);
2422 return E_FAIL;
2425 break;
2427 default:
2428 FIXME("Unhandled VARIANT: %s\n", debugstr_variant(&destination));
2429 return S_FALSE;
2432 xmldecl = xmldoc_unlink_xmldecl(get_doc(This));
2433 if (xmlSaveDoc(ctx, get_doc(This)) == -1) ret = S_FALSE;
2434 xmldoc_link_xmldecl(get_doc(This), xmldecl);
2436 /* will release resources through close callback */
2437 xmlSaveClose(ctx);
2439 return ret;
2442 static HRESULT WINAPI domdoc_get_validateOnParse(
2443 IXMLDOMDocument3 *iface,
2444 VARIANT_BOOL* isValidating )
2446 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2447 TRACE("(%p)->(%p: %d)\n", This, isValidating, This->validating);
2448 *isValidating = This->validating;
2449 return S_OK;
2453 static HRESULT WINAPI domdoc_put_validateOnParse(
2454 IXMLDOMDocument3 *iface,
2455 VARIANT_BOOL isValidating )
2457 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2458 TRACE("(%p)->(%d)\n", This, isValidating);
2459 This->validating = isValidating;
2460 return S_OK;
2464 static HRESULT WINAPI domdoc_get_resolveExternals(
2465 IXMLDOMDocument3 *iface,
2466 VARIANT_BOOL* isResolving )
2468 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2469 TRACE("(%p)->(%p: %d)\n", This, isResolving, This->resolving);
2470 *isResolving = This->resolving;
2471 return S_OK;
2475 static HRESULT WINAPI domdoc_put_resolveExternals(
2476 IXMLDOMDocument3 *iface,
2477 VARIANT_BOOL isResolving )
2479 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2480 TRACE("(%p)->(%d)\n", This, isResolving);
2481 This->resolving = isResolving;
2482 return S_OK;
2486 static HRESULT WINAPI domdoc_get_preserveWhiteSpace(
2487 IXMLDOMDocument3 *iface,
2488 VARIANT_BOOL* isPreserving )
2490 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2491 TRACE("(%p)->(%p: %d)\n", This, isPreserving, This->properties->preserving);
2492 *isPreserving = This->properties->preserving;
2493 return S_OK;
2497 static HRESULT WINAPI domdoc_put_preserveWhiteSpace(
2498 IXMLDOMDocument3 *iface,
2499 VARIANT_BOOL isPreserving )
2501 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2502 TRACE("(%p)->(%d)\n", This, isPreserving);
2503 This->properties->preserving = isPreserving;
2504 return S_OK;
2508 static HRESULT WINAPI domdoc_put_onreadystatechange(
2509 IXMLDOMDocument3 *iface,
2510 VARIANT event )
2512 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2514 TRACE("(%p)->(%s)\n", This, debugstr_variant(&event));
2515 return set_doc_event(This, EVENTID_READYSTATECHANGE, &event);
2519 static HRESULT WINAPI domdoc_put_onDataAvailable(IXMLDOMDocument3 *iface, VARIANT sink)
2521 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2522 FIXME("(%p)->(%s): stub\n", This, debugstr_variant(&sink));
2523 return E_NOTIMPL;
2526 static HRESULT WINAPI domdoc_put_onTransformNode(IXMLDOMDocument3 *iface, VARIANT sink )
2528 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2529 FIXME("(%p)->(%s): stub\n", This, debugstr_variant(&sink));
2530 return E_NOTIMPL;
2533 static HRESULT WINAPI domdoc_get_namespaces(
2534 IXMLDOMDocument3* iface,
2535 IXMLDOMSchemaCollection** collection )
2537 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2538 HRESULT hr;
2540 FIXME("(%p)->(%p): semi-stub\n", This, collection);
2542 if (!collection) return E_POINTER;
2544 if (!This->namespaces)
2546 hr = SchemaCache_create(This->properties->version, NULL, (void**)&This->namespaces);
2547 if (hr != S_OK) return hr;
2549 hr = cache_from_doc_ns(This->namespaces, &This->node);
2550 if (hr != S_OK)
2551 release_namespaces(This);
2554 if (This->namespaces)
2555 return IXMLDOMSchemaCollection2_QueryInterface(This->namespaces,
2556 &IID_IXMLDOMSchemaCollection, (void**)collection);
2558 return hr;
2561 static HRESULT WINAPI domdoc_get_schemas(
2562 IXMLDOMDocument3* iface,
2563 VARIANT* schema )
2565 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2566 IXMLDOMSchemaCollection2* cur_schema = This->properties->schemaCache;
2567 HRESULT hr = S_FALSE;
2569 TRACE("(%p)->(%p)\n", This, schema);
2571 V_VT(schema) = VT_NULL;
2572 /* just to reset pointer part, cause that's what application is expected to use */
2573 V_DISPATCH(schema) = NULL;
2575 if(cur_schema)
2577 hr = IXMLDOMSchemaCollection2_QueryInterface(cur_schema, &IID_IDispatch, (void**)&V_DISPATCH(schema));
2578 if(SUCCEEDED(hr))
2579 V_VT(schema) = VT_DISPATCH;
2581 return hr;
2584 static HRESULT WINAPI domdoc_putref_schemas(
2585 IXMLDOMDocument3* iface,
2586 VARIANT schema)
2588 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2589 HRESULT hr = E_FAIL;
2590 IXMLDOMSchemaCollection2* new_schema = NULL;
2592 FIXME("(%p)->(%s): semi-stub\n", This, debugstr_variant(&schema));
2593 switch(V_VT(&schema))
2595 case VT_UNKNOWN:
2596 if (V_UNKNOWN(&schema))
2598 hr = IUnknown_QueryInterface(V_UNKNOWN(&schema), &IID_IXMLDOMSchemaCollection, (void**)&new_schema);
2599 break;
2601 /* fallthrough */
2602 case VT_DISPATCH:
2603 if (V_DISPATCH(&schema))
2605 hr = IDispatch_QueryInterface(V_DISPATCH(&schema), &IID_IXMLDOMSchemaCollection, (void**)&new_schema);
2606 break;
2608 /* fallthrough */
2609 case VT_NULL:
2610 case VT_EMPTY:
2611 hr = S_OK;
2612 break;
2614 default:
2615 WARN("Can't get schema from vt %x\n", V_VT(&schema));
2618 if(SUCCEEDED(hr))
2620 IXMLDOMSchemaCollection2* old_schema = InterlockedExchangePointer((void**)&This->properties->schemaCache, new_schema);
2621 if(old_schema) IXMLDOMSchemaCollection2_Release(old_schema);
2624 return hr;
2627 static inline BOOL is_wellformed(xmlDocPtr doc)
2629 #ifdef HAVE_XMLDOC_PROPERTIES
2630 return doc->properties & XML_DOC_WELLFORMED;
2631 #else
2632 /* Not a full check, but catches the worst violations */
2633 xmlNodePtr child;
2634 int root = 0;
2636 for (child = doc->children; child != NULL; child = child->next)
2638 switch (child->type)
2640 case XML_ELEMENT_NODE:
2641 if (++root > 1)
2642 return FALSE;
2643 break;
2644 case XML_TEXT_NODE:
2645 case XML_CDATA_SECTION_NODE:
2646 return FALSE;
2647 break;
2648 default:
2649 break;
2653 return root == 1;
2654 #endif
2657 static void LIBXML2_LOG_CALLBACK validate_error(void* ctx, char const* msg, ...)
2659 va_list ap;
2660 va_start(ap, msg);
2661 LIBXML2_CALLBACK_ERR(domdoc_validateNode, msg, ap);
2662 va_end(ap);
2665 static void LIBXML2_LOG_CALLBACK validate_warning(void* ctx, char const* msg, ...)
2667 va_list ap;
2668 va_start(ap, msg);
2669 LIBXML2_CALLBACK_WARN(domdoc_validateNode, msg, ap);
2670 va_end(ap);
2673 static HRESULT WINAPI domdoc_validateNode(
2674 IXMLDOMDocument3* iface,
2675 IXMLDOMNode* node,
2676 IXMLDOMParseError** err)
2678 domdoc* This = impl_from_IXMLDOMDocument3(iface);
2679 LONG state, err_code = 0;
2680 HRESULT hr = S_OK;
2681 int validated = 0;
2683 TRACE("(%p)->(%p, %p)\n", This, node, err);
2684 IXMLDOMDocument3_get_readyState(iface, &state);
2685 if (state != READYSTATE_COMPLETE)
2687 if (err)
2688 *err = create_parseError(err_code, NULL, NULL, NULL, 0, 0, 0);
2689 return E_PENDING;
2692 if (!node)
2694 if (err)
2695 *err = create_parseError(err_code, NULL, NULL, NULL, 0, 0, 0);
2696 return E_POINTER;
2699 if (!get_node_obj(node)->node || get_node_obj(node)->node->doc != get_doc(This))
2701 if (err)
2702 *err = create_parseError(err_code, NULL, NULL, NULL, 0, 0, 0);
2703 return E_FAIL;
2706 if (!is_wellformed(get_doc(This)))
2708 ERR("doc not well-formed\n");
2709 if (err)
2710 *err = create_parseError(E_XML_NOTWF, NULL, NULL, NULL, 0, 0, 0);
2711 return S_FALSE;
2714 /* DTD validation */
2715 if (get_doc(This)->intSubset || get_doc(This)->extSubset)
2717 xmlValidCtxtPtr vctx = xmlNewValidCtxt();
2718 vctx->error = validate_error;
2719 vctx->warning = validate_warning;
2720 ++validated;
2722 if (!((node == (IXMLDOMNode*)iface)?
2723 xmlValidateDocument(vctx, get_doc(This)) :
2724 xmlValidateElement(vctx, get_doc(This), get_node_obj(node)->node)))
2726 /* TODO: get a real error code here */
2727 TRACE("DTD validation failed\n");
2728 err_code = E_XML_INVALID;
2729 hr = S_FALSE;
2731 xmlFreeValidCtxt(vctx);
2734 /* Schema validation */
2735 if (hr == S_OK && This->properties->schemaCache != NULL)
2738 hr = SchemaCache_validate_tree(This->properties->schemaCache, get_node_obj(node)->node);
2739 if (SUCCEEDED(hr))
2741 ++validated;
2742 /* TODO: get a real error code here */
2743 if (hr == S_OK)
2745 TRACE("schema validation succeeded\n");
2747 else
2749 ERR("schema validation failed\n");
2750 err_code = E_XML_INVALID;
2753 else
2755 /* not really OK, just didn't find a schema for the ns */
2756 hr = S_OK;
2760 if (!validated)
2762 ERR("no DTD or schema found\n");
2763 err_code = E_XML_NODTD;
2764 hr = S_FALSE;
2767 if (err)
2768 *err = create_parseError(err_code, NULL, NULL, NULL, 0, 0, 0);
2770 return hr;
2773 static HRESULT WINAPI domdoc_validate(
2774 IXMLDOMDocument3* iface,
2775 IXMLDOMParseError** err)
2777 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2778 TRACE("(%p)->(%p)\n", This, err);
2779 return IXMLDOMDocument3_validateNode(iface, (IXMLDOMNode*)iface, err);
2782 static HRESULT WINAPI domdoc_setProperty(
2783 IXMLDOMDocument3* iface,
2784 BSTR p,
2785 VARIANT value)
2787 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2789 TRACE("(%p)->(%s %s)\n", This, debugstr_w(p), debugstr_variant(&value));
2791 if (lstrcmpiW(p, PropertySelectionLanguageW) == 0)
2793 VARIANT varStr;
2794 HRESULT hr;
2795 BSTR bstr;
2797 V_VT(&varStr) = VT_EMPTY;
2798 if (V_VT(&value) != VT_BSTR)
2800 if (FAILED(hr = VariantChangeType(&varStr, &value, 0, VT_BSTR)))
2801 return hr;
2802 bstr = V_BSTR(&varStr);
2804 else
2805 bstr = V_BSTR(&value);
2807 hr = S_OK;
2808 if (lstrcmpiW(bstr, PropValueXPathW) == 0)
2809 This->properties->XPath = TRUE;
2810 else if (lstrcmpiW(bstr, PropValueXSLPatternW) == 0)
2811 This->properties->XPath = FALSE;
2812 else
2813 hr = E_FAIL;
2815 VariantClear(&varStr);
2816 return hr;
2818 else if (lstrcmpiW(p, PropertySelectionNamespacesW) == 0)
2820 xmlChar *nsStr = (xmlChar*)This->properties->selectNsStr;
2821 struct list *pNsList;
2822 VARIANT varStr;
2823 HRESULT hr;
2824 BSTR bstr;
2826 V_VT(&varStr) = VT_EMPTY;
2827 if (V_VT(&value) != VT_BSTR)
2829 if (FAILED(hr = VariantChangeType(&varStr, &value, 0, VT_BSTR)))
2830 return hr;
2831 bstr = V_BSTR(&varStr);
2833 else
2834 bstr = V_BSTR(&value);
2836 hr = S_OK;
2838 pNsList = &(This->properties->selectNsList);
2839 clear_selectNsList(pNsList);
2840 heap_free(nsStr);
2841 nsStr = xmlchar_from_wchar(bstr);
2843 TRACE("property value: \"%s\"\n", debugstr_w(bstr));
2845 This->properties->selectNsStr = nsStr;
2846 This->properties->selectNsStr_len = xmlStrlen(nsStr);
2847 if (bstr && *bstr)
2849 xmlChar *pTokBegin, *pTokEnd, *pTokInner;
2850 select_ns_entry* ns_entry = NULL;
2851 xmlXPathContextPtr ctx;
2853 ctx = xmlXPathNewContext(This->node.node->doc);
2854 pTokBegin = nsStr;
2856 /* skip leading spaces */
2857 while (*pTokBegin == ' ' || *pTokBegin == '\n' ||
2858 *pTokBegin == '\t' || *pTokBegin == '\r')
2859 ++pTokBegin;
2861 for (; *pTokBegin; pTokBegin = pTokEnd)
2863 if (ns_entry)
2864 memset(ns_entry, 0, sizeof(select_ns_entry));
2865 else
2866 ns_entry = heap_alloc_zero(sizeof(select_ns_entry));
2868 while (*pTokBegin == ' ')
2869 ++pTokBegin;
2870 pTokEnd = pTokBegin;
2871 while (*pTokEnd != ' ' && *pTokEnd != 0)
2872 ++pTokEnd;
2874 if (xmlStrncmp(pTokBegin, (xmlChar const*)"xmlns", 5) != 0)
2876 hr = E_FAIL;
2877 WARN("Syntax error in xmlns string: %s\n\tat token: %s\n",
2878 debugstr_w(bstr), debugstr_an((const char*)pTokBegin, pTokEnd-pTokBegin));
2879 continue;
2882 pTokBegin += 5;
2883 if (*pTokBegin == '=')
2885 /*valid for XSLPattern?*/
2886 FIXME("Setting default xmlns not supported - skipping.\n");
2887 continue;
2889 else if (*pTokBegin == ':')
2891 ns_entry->prefix = ++pTokBegin;
2892 for (pTokInner = pTokBegin; pTokInner != pTokEnd && *pTokInner != '='; ++pTokInner)
2895 if (pTokInner == pTokEnd)
2897 hr = E_FAIL;
2898 WARN("Syntax error in xmlns string: %s\n\tat token: %s\n",
2899 debugstr_w(bstr), debugstr_an((const char*)pTokBegin, pTokEnd-pTokBegin));
2900 continue;
2903 ns_entry->prefix_end = *pTokInner;
2904 *pTokInner = 0;
2905 ++pTokInner;
2907 if (pTokEnd-pTokInner > 1 &&
2908 ((*pTokInner == '\'' && *(pTokEnd-1) == '\'') ||
2909 (*pTokInner == '"' && *(pTokEnd-1) == '"')))
2911 ns_entry->href = ++pTokInner;
2912 ns_entry->href_end = *(pTokEnd-1);
2913 *(pTokEnd-1) = 0;
2914 list_add_tail(pNsList, &ns_entry->entry);
2915 /*let libxml figure out if they're valid from here ;)*/
2916 if (xmlXPathRegisterNs(ctx, ns_entry->prefix, ns_entry->href) != 0)
2918 hr = E_FAIL;
2920 ns_entry = NULL;
2921 continue;
2923 else
2925 WARN("Syntax error in xmlns string: %s\n\tat token: %s\n",
2926 debugstr_w(bstr), debugstr_an((const char*)pTokInner, pTokEnd-pTokInner));
2927 list_add_tail(pNsList, &ns_entry->entry);
2929 ns_entry = NULL;
2930 hr = E_FAIL;
2931 continue;
2934 else
2936 hr = E_FAIL;
2937 continue;
2940 heap_free(ns_entry);
2941 xmlXPathFreeContext(ctx);
2944 VariantClear(&varStr);
2945 return hr;
2947 else if (lstrcmpiW(p, PropertyProhibitDTDW) == 0 ||
2948 lstrcmpiW(p, PropertyNewParserW) == 0 ||
2949 lstrcmpiW(p, PropertyResolveExternalsW) == 0)
2951 /* Ignore */
2952 FIXME("Ignoring property %s, value %d\n", debugstr_w(p), V_BOOL(&value));
2953 return S_OK;
2956 FIXME("Unknown property %s\n", debugstr_w(p));
2957 return E_FAIL;
2960 static HRESULT WINAPI domdoc_getProperty(
2961 IXMLDOMDocument3* iface,
2962 BSTR p,
2963 VARIANT* var)
2965 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2967 TRACE("(%p)->(%s)\n", This, debugstr_w(p));
2969 if (!var)
2970 return E_INVALIDARG;
2972 if (lstrcmpiW(p, PropertySelectionLanguageW) == 0)
2974 V_VT(var) = VT_BSTR;
2975 V_BSTR(var) = This->properties->XPath ?
2976 SysAllocString(PropValueXPathW) :
2977 SysAllocString(PropValueXSLPatternW);
2978 return V_BSTR(var) ? S_OK : E_OUTOFMEMORY;
2980 else if (lstrcmpiW(p, PropertySelectionNamespacesW) == 0)
2982 int lenA, lenW;
2983 BSTR rebuiltStr, cur;
2984 const xmlChar *nsStr;
2985 struct list *pNsList;
2986 select_ns_entry* pNsEntry;
2988 V_VT(var) = VT_BSTR;
2989 nsStr = This->properties->selectNsStr;
2990 pNsList = &This->properties->selectNsList;
2991 lenA = This->properties->selectNsStr_len;
2992 lenW = MultiByteToWideChar(CP_UTF8, 0, (LPCSTR)nsStr, lenA+1, NULL, 0);
2993 rebuiltStr = heap_alloc(lenW*sizeof(WCHAR));
2994 MultiByteToWideChar(CP_UTF8, 0, (LPCSTR)nsStr, lenA+1, rebuiltStr, lenW);
2995 cur = rebuiltStr;
2996 /* this is fine because all of the chars that end tokens are ASCII*/
2997 LIST_FOR_EACH_ENTRY(pNsEntry, pNsList, select_ns_entry, entry)
2999 while (*cur != 0) ++cur;
3000 if (pNsEntry->prefix_end)
3002 *cur = pNsEntry->prefix_end;
3003 while (*cur != 0) ++cur;
3006 if (pNsEntry->href_end)
3008 *cur = pNsEntry->href_end;
3011 V_BSTR(var) = SysAllocString(rebuiltStr);
3012 heap_free(rebuiltStr);
3013 return S_OK;
3016 FIXME("Unknown property %s\n", debugstr_w(p));
3017 return E_FAIL;
3020 static HRESULT WINAPI domdoc_importNode(
3021 IXMLDOMDocument3* iface,
3022 IXMLDOMNode* node,
3023 VARIANT_BOOL deep,
3024 IXMLDOMNode** clone)
3026 domdoc *This = impl_from_IXMLDOMDocument3( iface );
3027 FIXME("(%p)->(%p %d %p): stub\n", This, node, deep, clone);
3028 return E_NOTIMPL;
3031 static const struct IXMLDOMDocument3Vtbl XMLDOMDocument3Vtbl =
3033 domdoc_QueryInterface,
3034 domdoc_AddRef,
3035 domdoc_Release,
3036 domdoc_GetTypeInfoCount,
3037 domdoc_GetTypeInfo,
3038 domdoc_GetIDsOfNames,
3039 domdoc_Invoke,
3040 domdoc_get_nodeName,
3041 domdoc_get_nodeValue,
3042 domdoc_put_nodeValue,
3043 domdoc_get_nodeType,
3044 domdoc_get_parentNode,
3045 domdoc_get_childNodes,
3046 domdoc_get_firstChild,
3047 domdoc_get_lastChild,
3048 domdoc_get_previousSibling,
3049 domdoc_get_nextSibling,
3050 domdoc_get_attributes,
3051 domdoc_insertBefore,
3052 domdoc_replaceChild,
3053 domdoc_removeChild,
3054 domdoc_appendChild,
3055 domdoc_hasChildNodes,
3056 domdoc_get_ownerDocument,
3057 domdoc_cloneNode,
3058 domdoc_get_nodeTypeString,
3059 domdoc_get_text,
3060 domdoc_put_text,
3061 domdoc_get_specified,
3062 domdoc_get_definition,
3063 domdoc_get_nodeTypedValue,
3064 domdoc_put_nodeTypedValue,
3065 domdoc_get_dataType,
3066 domdoc_put_dataType,
3067 domdoc_get_xml,
3068 domdoc_transformNode,
3069 domdoc_selectNodes,
3070 domdoc_selectSingleNode,
3071 domdoc_get_parsed,
3072 domdoc_get_namespaceURI,
3073 domdoc_get_prefix,
3074 domdoc_get_baseName,
3075 domdoc_transformNodeToObject,
3076 domdoc_get_doctype,
3077 domdoc_get_implementation,
3078 domdoc_get_documentElement,
3079 domdoc_put_documentElement,
3080 domdoc_createElement,
3081 domdoc_createDocumentFragment,
3082 domdoc_createTextNode,
3083 domdoc_createComment,
3084 domdoc_createCDATASection,
3085 domdoc_createProcessingInstruction,
3086 domdoc_createAttribute,
3087 domdoc_createEntityReference,
3088 domdoc_getElementsByTagName,
3089 domdoc_createNode,
3090 domdoc_nodeFromID,
3091 domdoc_load,
3092 domdoc_get_readyState,
3093 domdoc_get_parseError,
3094 domdoc_get_url,
3095 domdoc_get_async,
3096 domdoc_put_async,
3097 domdoc_abort,
3098 domdoc_loadXML,
3099 domdoc_save,
3100 domdoc_get_validateOnParse,
3101 domdoc_put_validateOnParse,
3102 domdoc_get_resolveExternals,
3103 domdoc_put_resolveExternals,
3104 domdoc_get_preserveWhiteSpace,
3105 domdoc_put_preserveWhiteSpace,
3106 domdoc_put_onreadystatechange,
3107 domdoc_put_onDataAvailable,
3108 domdoc_put_onTransformNode,
3109 domdoc_get_namespaces,
3110 domdoc_get_schemas,
3111 domdoc_putref_schemas,
3112 domdoc_validate,
3113 domdoc_setProperty,
3114 domdoc_getProperty,
3115 domdoc_validateNode,
3116 domdoc_importNode
3119 /* IConnectionPointContainer */
3120 static HRESULT WINAPI ConnectionPointContainer_QueryInterface(IConnectionPointContainer *iface,
3121 REFIID riid, void **ppv)
3123 domdoc *This = impl_from_IConnectionPointContainer(iface);
3124 return IXMLDOMDocument3_QueryInterface(&This->IXMLDOMDocument3_iface, riid, ppv);
3127 static ULONG WINAPI ConnectionPointContainer_AddRef(IConnectionPointContainer *iface)
3129 domdoc *This = impl_from_IConnectionPointContainer(iface);
3130 return IXMLDOMDocument3_AddRef(&This->IXMLDOMDocument3_iface);
3133 static ULONG WINAPI ConnectionPointContainer_Release(IConnectionPointContainer *iface)
3135 domdoc *This = impl_from_IConnectionPointContainer(iface);
3136 return IXMLDOMDocument3_Release(&This->IXMLDOMDocument3_iface);
3139 static HRESULT WINAPI ConnectionPointContainer_EnumConnectionPoints(IConnectionPointContainer *iface,
3140 IEnumConnectionPoints **ppEnum)
3142 domdoc *This = impl_from_IConnectionPointContainer(iface);
3143 FIXME("(%p)->(%p): stub\n", This, ppEnum);
3144 return E_NOTIMPL;
3147 static HRESULT WINAPI ConnectionPointContainer_FindConnectionPoint(IConnectionPointContainer *iface,
3148 REFIID riid, IConnectionPoint **cp)
3150 domdoc *This = impl_from_IConnectionPointContainer(iface);
3151 ConnectionPoint *iter;
3153 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), cp);
3155 *cp = NULL;
3157 for(iter = This->cp_list; iter; iter = iter->next)
3159 if (IsEqualGUID(iter->iid, riid))
3160 *cp = &iter->IConnectionPoint_iface;
3163 if (*cp)
3165 IConnectionPoint_AddRef(*cp);
3166 return S_OK;
3169 FIXME("unsupported riid %s\n", debugstr_guid(riid));
3170 return CONNECT_E_NOCONNECTION;
3174 static const struct IConnectionPointContainerVtbl ConnectionPointContainerVtbl =
3176 ConnectionPointContainer_QueryInterface,
3177 ConnectionPointContainer_AddRef,
3178 ConnectionPointContainer_Release,
3179 ConnectionPointContainer_EnumConnectionPoints,
3180 ConnectionPointContainer_FindConnectionPoint
3183 /* IConnectionPoint */
3184 static HRESULT WINAPI ConnectionPoint_QueryInterface(IConnectionPoint *iface,
3185 REFIID riid, void **ppv)
3187 ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3189 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv );
3191 *ppv = NULL;
3193 if (IsEqualGUID(&IID_IUnknown, riid) ||
3194 IsEqualGUID(&IID_IConnectionPoint, riid))
3196 *ppv = iface;
3199 if (*ppv)
3201 IConnectionPoint_AddRef(iface);
3202 return S_OK;
3205 WARN("Unsupported interface %s\n", debugstr_guid(riid));
3206 return E_NOINTERFACE;
3209 static ULONG WINAPI ConnectionPoint_AddRef(IConnectionPoint *iface)
3211 ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3212 return IConnectionPointContainer_AddRef(This->container);
3215 static ULONG WINAPI ConnectionPoint_Release(IConnectionPoint *iface)
3217 ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3218 return IConnectionPointContainer_Release(This->container);
3221 static HRESULT WINAPI ConnectionPoint_GetConnectionInterface(IConnectionPoint *iface, IID *iid)
3223 ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3225 TRACE("(%p)->(%p)\n", This, iid);
3227 if (!iid) return E_POINTER;
3229 *iid = *This->iid;
3230 return S_OK;
3233 static HRESULT WINAPI ConnectionPoint_GetConnectionPointContainer(IConnectionPoint *iface,
3234 IConnectionPointContainer **container)
3236 ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3238 TRACE("(%p)->(%p)\n", This, container);
3240 if (!container) return E_POINTER;
3242 *container = This->container;
3243 IConnectionPointContainer_AddRef(*container);
3244 return S_OK;
3247 static HRESULT WINAPI ConnectionPoint_Advise(IConnectionPoint *iface, IUnknown *pUnkSink,
3248 DWORD *pdwCookie)
3250 ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3251 FIXME("(%p)->(%p %p): stub\n", This, pUnkSink, pdwCookie);
3252 return E_NOTIMPL;
3255 static HRESULT WINAPI ConnectionPoint_Unadvise(IConnectionPoint *iface, DWORD cookie)
3257 ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3259 TRACE("(%p)->(%d)\n", This, cookie);
3261 if (cookie == 0 || cookie > This->sinks_size || !This->sinks[cookie-1].unk)
3262 return CONNECT_E_NOCONNECTION;
3264 IUnknown_Release(This->sinks[cookie-1].unk);
3265 This->sinks[cookie-1].unk = NULL;
3267 return S_OK;
3270 static HRESULT WINAPI ConnectionPoint_EnumConnections(IConnectionPoint *iface,
3271 IEnumConnections **ppEnum)
3273 ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3274 FIXME("(%p)->(%p): stub\n", This, ppEnum);
3275 return E_NOTIMPL;
3278 static const IConnectionPointVtbl ConnectionPointVtbl =
3280 ConnectionPoint_QueryInterface,
3281 ConnectionPoint_AddRef,
3282 ConnectionPoint_Release,
3283 ConnectionPoint_GetConnectionInterface,
3284 ConnectionPoint_GetConnectionPointContainer,
3285 ConnectionPoint_Advise,
3286 ConnectionPoint_Unadvise,
3287 ConnectionPoint_EnumConnections
3290 static void ConnectionPoint_Init(ConnectionPoint *cp, struct domdoc *doc, REFIID riid)
3292 cp->IConnectionPoint_iface.lpVtbl = &ConnectionPointVtbl;
3293 cp->doc = doc;
3294 cp->iid = riid;
3295 cp->sinks = NULL;
3296 cp->sinks_size = 0;
3298 cp->next = doc->cp_list;
3299 doc->cp_list = cp;
3301 cp->container = &doc->IConnectionPointContainer_iface;
3304 /* domdoc implementation of IObjectWithSite */
3305 static HRESULT WINAPI
3306 domdoc_ObjectWithSite_QueryInterface( IObjectWithSite* iface, REFIID riid, void** ppvObject )
3308 domdoc *This = impl_from_IObjectWithSite(iface);
3309 return IXMLDOMDocument3_QueryInterface(&This->IXMLDOMDocument3_iface, riid, ppvObject);
3312 static ULONG WINAPI domdoc_ObjectWithSite_AddRef( IObjectWithSite* iface )
3314 domdoc *This = impl_from_IObjectWithSite(iface);
3315 return IXMLDOMDocument3_AddRef(&This->IXMLDOMDocument3_iface);
3318 static ULONG WINAPI domdoc_ObjectWithSite_Release( IObjectWithSite* iface )
3320 domdoc *This = impl_from_IObjectWithSite(iface);
3321 return IXMLDOMDocument3_Release(&This->IXMLDOMDocument3_iface);
3324 static HRESULT WINAPI domdoc_ObjectWithSite_GetSite( IObjectWithSite *iface, REFIID iid, void **ppvSite )
3326 domdoc *This = impl_from_IObjectWithSite(iface);
3328 TRACE("(%p)->(%s %p)\n", This, debugstr_guid( iid ), ppvSite );
3330 if ( !This->site )
3331 return E_FAIL;
3333 return IUnknown_QueryInterface( This->site, iid, ppvSite );
3336 static HRESULT WINAPI domdoc_ObjectWithSite_SetSite( IObjectWithSite *iface, IUnknown *punk )
3338 domdoc *This = impl_from_IObjectWithSite(iface);
3340 TRACE("(%p)->(%p)\n", iface, punk);
3342 if(!punk)
3344 if(This->site)
3346 IUnknown_Release( This->site );
3347 This->site = NULL;
3350 return S_OK;
3353 IUnknown_AddRef( punk );
3355 if(This->site)
3356 IUnknown_Release( This->site );
3358 This->site = punk;
3360 return S_OK;
3363 static const IObjectWithSiteVtbl domdocObjectSite =
3365 domdoc_ObjectWithSite_QueryInterface,
3366 domdoc_ObjectWithSite_AddRef,
3367 domdoc_ObjectWithSite_Release,
3368 domdoc_ObjectWithSite_SetSite,
3369 domdoc_ObjectWithSite_GetSite
3372 static HRESULT WINAPI domdoc_Safety_QueryInterface(IObjectSafety *iface, REFIID riid, void **ppv)
3374 domdoc *This = impl_from_IObjectSafety(iface);
3375 return IXMLDOMDocument3_QueryInterface(&This->IXMLDOMDocument3_iface, riid, ppv);
3378 static ULONG WINAPI domdoc_Safety_AddRef(IObjectSafety *iface)
3380 domdoc *This = impl_from_IObjectSafety(iface);
3381 return IXMLDOMDocument3_AddRef(&This->IXMLDOMDocument3_iface);
3384 static ULONG WINAPI domdoc_Safety_Release(IObjectSafety *iface)
3386 domdoc *This = impl_from_IObjectSafety(iface);
3387 return IXMLDOMDocument3_Release(&This->IXMLDOMDocument3_iface);
3390 #define SAFETY_SUPPORTED_OPTIONS (INTERFACESAFE_FOR_UNTRUSTED_CALLER|INTERFACESAFE_FOR_UNTRUSTED_DATA|INTERFACE_USES_SECURITY_MANAGER)
3392 static HRESULT WINAPI domdoc_Safety_GetInterfaceSafetyOptions(IObjectSafety *iface, REFIID riid,
3393 DWORD *supported, DWORD *enabled)
3395 domdoc *This = impl_from_IObjectSafety(iface);
3397 TRACE("(%p)->(%s %p %p)\n", This, debugstr_guid(riid), supported, enabled);
3399 if(!supported || !enabled) return E_POINTER;
3401 *supported = SAFETY_SUPPORTED_OPTIONS;
3402 *enabled = This->safeopt;
3404 return S_OK;
3407 static HRESULT WINAPI domdoc_Safety_SetInterfaceSafetyOptions(IObjectSafety *iface, REFIID riid,
3408 DWORD mask, DWORD enabled)
3410 domdoc *This = impl_from_IObjectSafety(iface);
3411 TRACE("(%p)->(%s %x %x)\n", This, debugstr_guid(riid), mask, enabled);
3413 if ((mask & ~SAFETY_SUPPORTED_OPTIONS) != 0)
3414 return E_FAIL;
3416 This->safeopt = (This->safeopt & ~mask) | (mask & enabled);
3418 return S_OK;
3421 #undef SAFETY_SUPPORTED_OPTIONS
3423 static const IObjectSafetyVtbl domdocObjectSafetyVtbl = {
3424 domdoc_Safety_QueryInterface,
3425 domdoc_Safety_AddRef,
3426 domdoc_Safety_Release,
3427 domdoc_Safety_GetInterfaceSafetyOptions,
3428 domdoc_Safety_SetInterfaceSafetyOptions
3431 static const tid_t domdoc_iface_tids[] = {
3432 IXMLDOMDocument3_tid,
3436 static dispex_static_data_t domdoc_dispex = {
3437 NULL,
3438 IXMLDOMDocument3_tid,
3439 NULL,
3440 domdoc_iface_tids
3443 HRESULT get_domdoc_from_xmldoc(xmlDocPtr xmldoc, IXMLDOMDocument3 **document)
3445 domdoc *doc;
3447 doc = heap_alloc( sizeof (*doc) );
3448 if( !doc )
3449 return E_OUTOFMEMORY;
3451 doc->IXMLDOMDocument3_iface.lpVtbl = &XMLDOMDocument3Vtbl;
3452 doc->IPersistStreamInit_iface.lpVtbl = &xmldoc_IPersistStreamInit_VTable;
3453 doc->IObjectWithSite_iface.lpVtbl = &domdocObjectSite;
3454 doc->IObjectSafety_iface.lpVtbl = &domdocObjectSafetyVtbl;
3455 doc->IConnectionPointContainer_iface.lpVtbl = &ConnectionPointContainerVtbl;
3456 doc->ref = 1;
3457 doc->async = VARIANT_TRUE;
3458 doc->validating = 0;
3459 doc->resolving = 0;
3460 doc->properties = properties_from_xmlDocPtr(xmldoc);
3461 doc->error = S_OK;
3462 doc->stream = NULL;
3463 doc->site = NULL;
3464 doc->safeopt = 0;
3465 doc->bsc = NULL;
3466 doc->cp_list = NULL;
3467 doc->namespaces = NULL;
3468 memset(doc->events, 0, sizeof(doc->events));
3470 /* events connection points */
3471 ConnectionPoint_Init(&doc->cp_dispatch, doc, &IID_IDispatch);
3472 ConnectionPoint_Init(&doc->cp_propnotif, doc, &IID_IPropertyNotifySink);
3473 ConnectionPoint_Init(&doc->cp_domdocevents, doc, &DIID_XMLDOMDocumentEvents);
3475 init_xmlnode(&doc->node, (xmlNodePtr)xmldoc, (IXMLDOMNode*)&doc->IXMLDOMDocument3_iface,
3476 &domdoc_dispex);
3478 *document = &doc->IXMLDOMDocument3_iface;
3480 TRACE("returning iface %p\n", *document);
3481 return S_OK;
3484 HRESULT DOMDocument_create(MSXML_VERSION version, IUnknown *pUnkOuter, void **ppObj)
3486 xmlDocPtr xmldoc;
3487 HRESULT hr;
3489 TRACE("(%d, %p, %p)\n", version, pUnkOuter, ppObj);
3491 xmldoc = xmlNewDoc(NULL);
3492 if(!xmldoc)
3493 return E_OUTOFMEMORY;
3495 xmldoc_init(xmldoc, version);
3497 hr = get_domdoc_from_xmldoc(xmldoc, (IXMLDOMDocument3**)ppObj);
3498 if(FAILED(hr))
3500 free_properties(properties_from_xmlDocPtr(xmldoc));
3501 heap_free(xmldoc->_private);
3502 xmlFreeDoc(xmldoc);
3503 return hr;
3506 return hr;
3509 IUnknown* create_domdoc( xmlNodePtr document )
3511 void* pObj = NULL;
3512 HRESULT hr;
3514 TRACE("(%p)\n", document);
3516 hr = get_domdoc_from_xmldoc((xmlDocPtr)document, (IXMLDOMDocument3**)&pObj);
3517 if (FAILED(hr))
3518 return NULL;
3520 return pObj;
3523 #else
3525 HRESULT DOMDocument_create(MSXML_VERSION version, IUnknown *pUnkOuter, void **ppObj)
3527 MESSAGE("This program tried to use a DOMDocument object, but\n"
3528 "libxml2 support was not present at compile time.\n");
3529 return E_NOTIMPL;
3532 #endif