msxml3: Enable inline wrappers and fix warnings.
[wine/multimedia.git] / dlls / msxml3 / domdoc.c
blob54c601eebcdc387fe8e95da9aa163fe68d4bc66b
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 if (!V_UNKNOWN(&source)) return E_INVALIDARG;
2097 hr = IUnknown_QueryInterface(V_UNKNOWN(&source), &IID_IXMLDOMDocument3, (void**)&pNewDoc);
2098 if(hr == S_OK)
2100 if(pNewDoc)
2102 domdoc *newDoc = impl_from_IXMLDOMDocument3( pNewDoc );
2104 xmldoc = xmlCopyDoc(get_doc(newDoc), 1);
2105 xmldoc->_private = create_priv();
2106 hr = attach_xmldoc(This, xmldoc);
2108 if(SUCCEEDED(hr))
2109 *isSuccessful = VARIANT_TRUE;
2111 return hr;
2114 hr = IUnknown_QueryInterface(V_UNKNOWN(&source), &IID_IStream, (void**)&pStream);
2115 if(hr == S_OK)
2117 IPersistStream *pDocStream;
2118 hr = IXMLDOMDocument3_QueryInterface(iface, &IID_IPersistStream, (void**)&pDocStream);
2119 if(hr == S_OK)
2121 hr = IPersistStream_Load(pDocStream, pStream);
2122 IStream_Release(pStream);
2123 if(hr == S_OK)
2125 *isSuccessful = VARIANT_TRUE;
2127 TRACE("Using IStream to load Document\n");
2128 return S_OK;
2130 else
2132 ERR("xmldoc_IPersistStream_Load failed (%d)\n", hr);
2135 else
2137 ERR("QueryInterface IID_IPersistStream failed (%d)\n", hr);
2140 else
2142 /* ISequentialStream */
2143 FIXME("Unknown type not supported (%d) (%p)(%p)\n", hr, pNewDoc, V_UNKNOWN(&source)->lpVtbl);
2145 break;
2146 default:
2147 FIXME("VT type not supported (%d)\n", V_VT(&source));
2150 if ( filename )
2152 IMoniker *mon;
2154 hr = create_moniker_from_url( filename, &mon);
2155 if ( SUCCEEDED(hr) )
2157 hr = domdoc_load_moniker( This, mon );
2158 IMoniker_Release(mon);
2161 if ( FAILED(hr) )
2162 This->error = E_FAIL;
2163 else
2165 hr = This->error = S_OK;
2166 *isSuccessful = VARIANT_TRUE;
2170 if(!filename || FAILED(hr)) {
2171 xmldoc = xmlNewDoc(NULL);
2172 xmldoc->_private = create_priv();
2173 hr = attach_xmldoc(This, xmldoc);
2174 if(SUCCEEDED(hr))
2175 hr = S_FALSE;
2178 TRACE("ret (%d)\n", hr);
2180 return hr;
2184 static HRESULT WINAPI domdoc_get_readyState(
2185 IXMLDOMDocument3 *iface,
2186 LONG *value )
2188 domdoc *This = impl_from_IXMLDOMDocument3(iface);
2189 FIXME("stub! (%p)->(%p)\n", This, value);
2191 if (!value)
2192 return E_INVALIDARG;
2194 *value = READYSTATE_COMPLETE;
2195 return S_OK;
2199 static HRESULT WINAPI domdoc_get_parseError(
2200 IXMLDOMDocument3 *iface,
2201 IXMLDOMParseError** errorObj )
2203 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2204 static const WCHAR err[] = {'e','r','r','o','r',0};
2205 BSTR error_string = NULL;
2207 FIXME("(%p)->(%p): creating a dummy parseError\n", iface, errorObj);
2209 if(This->error)
2210 error_string = SysAllocString(err);
2212 *errorObj = create_parseError(This->error, NULL, error_string, NULL, 0, 0, 0);
2213 if(!*errorObj) return E_OUTOFMEMORY;
2214 return S_OK;
2218 static HRESULT WINAPI domdoc_get_url(
2219 IXMLDOMDocument3 *iface,
2220 BSTR* urlString )
2222 domdoc *This = impl_from_IXMLDOMDocument3(iface);
2223 FIXME("(%p)->(%p)\n", This, urlString);
2224 return E_NOTIMPL;
2228 static HRESULT WINAPI domdoc_get_async(
2229 IXMLDOMDocument3 *iface,
2230 VARIANT_BOOL* isAsync )
2232 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2234 TRACE("(%p)->(%p: %d)\n", This, isAsync, This->async);
2235 *isAsync = This->async;
2236 return S_OK;
2240 static HRESULT WINAPI domdoc_put_async(
2241 IXMLDOMDocument3 *iface,
2242 VARIANT_BOOL isAsync )
2244 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2246 TRACE("(%p)->(%d)\n", This, isAsync);
2247 This->async = isAsync;
2248 return S_OK;
2252 static HRESULT WINAPI domdoc_abort(
2253 IXMLDOMDocument3 *iface )
2255 domdoc *This = impl_from_IXMLDOMDocument3(iface);
2256 FIXME("%p\n", This);
2257 return E_NOTIMPL;
2260 /* don't rely on data to be in BSTR format, treat it as WCHAR string */
2261 static HRESULT WINAPI domdoc_loadXML(
2262 IXMLDOMDocument3 *iface,
2263 BSTR data,
2264 VARIANT_BOOL* isSuccessful )
2266 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2267 xmlDocPtr xmldoc = NULL;
2268 HRESULT hr = S_FALSE, hr2;
2270 TRACE("(%p)->(%s %p)\n", This, debugstr_w(data), isSuccessful );
2272 assert ( &This->node );
2274 if ( isSuccessful )
2276 *isSuccessful = VARIANT_FALSE;
2278 if (data)
2280 WCHAR *ptr = data;
2282 /* skip leading spaces if needed */
2283 if (This->properties->version == MSXML_DEFAULT || This->properties->version == MSXML26)
2284 while (*ptr && isspaceW(*ptr)) ptr++;
2286 xmldoc = doparse(This, (char*)ptr, strlenW(ptr)*sizeof(WCHAR), XML_CHAR_ENCODING_UTF16LE);
2287 if ( !xmldoc )
2289 This->error = E_FAIL;
2290 TRACE("failed to parse document\n");
2292 else
2294 hr = This->error = S_OK;
2295 *isSuccessful = VARIANT_TRUE;
2296 TRACE("parsed document %p\n", xmldoc);
2301 if(!xmldoc)
2302 xmldoc = xmlNewDoc(NULL);
2303 xmldoc->_private = create_priv();
2304 hr2 = attach_xmldoc(This, xmldoc);
2305 if( FAILED(hr2) )
2306 hr = hr2;
2308 return hr;
2311 static int XMLCALL domdoc_save_writecallback(void *ctx, const char *buffer, int len)
2313 DWORD written = -1;
2315 if(!WriteFile(ctx, buffer, len, &written, NULL))
2317 WARN("write error\n");
2318 return -1;
2320 else
2321 return written;
2324 static int XMLCALL domdoc_save_closecallback(void *ctx)
2326 return CloseHandle(ctx) ? 0 : -1;
2329 static int XMLCALL domdoc_stream_save_writecallback(void *ctx, const char *buffer, int len)
2331 ULONG written = 0;
2332 HRESULT hr;
2334 hr = IStream_Write((IStream*)ctx, buffer, len, &written);
2335 TRACE("0x%08x %p %d %u\n", hr, buffer, len, written);
2336 if (hr != S_OK)
2338 WARN("stream write error: 0x%08x\n", hr);
2339 return -1;
2341 else
2342 return len;
2345 static int XMLCALL domdoc_stream_save_closecallback(void *ctx)
2347 IStream_Release((IStream*)ctx);
2348 return 0;
2351 static HRESULT WINAPI domdoc_save(
2352 IXMLDOMDocument3 *iface,
2353 VARIANT destination )
2355 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2356 xmlSaveCtxtPtr ctx = NULL;
2357 xmlNodePtr xmldecl;
2358 HRESULT ret = S_OK;
2360 TRACE("(%p)->(%s)\n", This, debugstr_variant(&destination));
2362 switch (V_VT(&destination))
2364 case VT_UNKNOWN:
2366 IUnknown *pUnk = V_UNKNOWN(&destination);
2367 IXMLDOMDocument3 *document;
2368 IStream *stream;
2370 ret = IUnknown_QueryInterface(pUnk, &IID_IXMLDOMDocument3, (void**)&document);
2371 if(ret == S_OK)
2373 VARIANT_BOOL success;
2374 BSTR xml;
2376 ret = IXMLDOMDocument3_get_xml(iface, &xml);
2377 if(ret == S_OK)
2379 ret = IXMLDOMDocument3_loadXML(document, xml, &success);
2380 SysFreeString(xml);
2383 IXMLDOMDocument3_Release(document);
2384 return ret;
2387 ret = IUnknown_QueryInterface(pUnk, &IID_IStream, (void**)&stream);
2388 if(ret == S_OK)
2390 int options = get_doc(This)->standalone == -1 ? XML_SAVE_NO_DECL : 0;
2391 ctx = xmlSaveToIO(domdoc_stream_save_writecallback,
2392 domdoc_stream_save_closecallback, stream, NULL, options);
2394 if(!ctx)
2396 IStream_Release(stream);
2397 return E_FAIL;
2401 break;
2403 case VT_BSTR:
2404 case VT_BSTR | VT_BYREF:
2406 int options = get_doc(This)->standalone == -1 ? XML_SAVE_NO_DECL : 0;
2408 /* save with file path */
2409 HANDLE handle = CreateFileW( (V_VT(&destination) & VT_BYREF)? *V_BSTRREF(&destination) : V_BSTR(&destination),
2410 GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL );
2411 if( handle == INVALID_HANDLE_VALUE )
2413 WARN("failed to create file\n");
2414 return E_FAIL;
2417 /* disable top XML declaration */
2418 ctx = xmlSaveToIO(domdoc_save_writecallback, domdoc_save_closecallback,
2419 handle, NULL, options);
2420 if (!ctx)
2422 CloseHandle(handle);
2423 return E_FAIL;
2426 break;
2428 default:
2429 FIXME("Unhandled VARIANT: %s\n", debugstr_variant(&destination));
2430 return S_FALSE;
2433 xmldecl = xmldoc_unlink_xmldecl(get_doc(This));
2434 if (xmlSaveDoc(ctx, get_doc(This)) == -1) ret = S_FALSE;
2435 xmldoc_link_xmldecl(get_doc(This), xmldecl);
2437 /* will release resources through close callback */
2438 xmlSaveClose(ctx);
2440 return ret;
2443 static HRESULT WINAPI domdoc_get_validateOnParse(
2444 IXMLDOMDocument3 *iface,
2445 VARIANT_BOOL* isValidating )
2447 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2448 TRACE("(%p)->(%p: %d)\n", This, isValidating, This->validating);
2449 *isValidating = This->validating;
2450 return S_OK;
2454 static HRESULT WINAPI domdoc_put_validateOnParse(
2455 IXMLDOMDocument3 *iface,
2456 VARIANT_BOOL isValidating )
2458 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2459 TRACE("(%p)->(%d)\n", This, isValidating);
2460 This->validating = isValidating;
2461 return S_OK;
2465 static HRESULT WINAPI domdoc_get_resolveExternals(
2466 IXMLDOMDocument3 *iface,
2467 VARIANT_BOOL* isResolving )
2469 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2470 TRACE("(%p)->(%p: %d)\n", This, isResolving, This->resolving);
2471 *isResolving = This->resolving;
2472 return S_OK;
2476 static HRESULT WINAPI domdoc_put_resolveExternals(
2477 IXMLDOMDocument3 *iface,
2478 VARIANT_BOOL isResolving )
2480 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2481 TRACE("(%p)->(%d)\n", This, isResolving);
2482 This->resolving = isResolving;
2483 return S_OK;
2487 static HRESULT WINAPI domdoc_get_preserveWhiteSpace(
2488 IXMLDOMDocument3 *iface,
2489 VARIANT_BOOL* isPreserving )
2491 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2492 TRACE("(%p)->(%p: %d)\n", This, isPreserving, This->properties->preserving);
2493 *isPreserving = This->properties->preserving;
2494 return S_OK;
2498 static HRESULT WINAPI domdoc_put_preserveWhiteSpace(
2499 IXMLDOMDocument3 *iface,
2500 VARIANT_BOOL isPreserving )
2502 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2503 TRACE("(%p)->(%d)\n", This, isPreserving);
2504 This->properties->preserving = isPreserving;
2505 return S_OK;
2509 static HRESULT WINAPI domdoc_put_onreadystatechange(
2510 IXMLDOMDocument3 *iface,
2511 VARIANT event )
2513 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2515 TRACE("(%p)->(%s)\n", This, debugstr_variant(&event));
2516 return set_doc_event(This, EVENTID_READYSTATECHANGE, &event);
2520 static HRESULT WINAPI domdoc_put_onDataAvailable(IXMLDOMDocument3 *iface, VARIANT sink)
2522 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2523 FIXME("(%p)->(%s): stub\n", This, debugstr_variant(&sink));
2524 return E_NOTIMPL;
2527 static HRESULT WINAPI domdoc_put_onTransformNode(IXMLDOMDocument3 *iface, VARIANT sink )
2529 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2530 FIXME("(%p)->(%s): stub\n", This, debugstr_variant(&sink));
2531 return E_NOTIMPL;
2534 static HRESULT WINAPI domdoc_get_namespaces(
2535 IXMLDOMDocument3* iface,
2536 IXMLDOMSchemaCollection** collection )
2538 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2539 HRESULT hr;
2541 FIXME("(%p)->(%p): semi-stub\n", This, collection);
2543 if (!collection) return E_POINTER;
2545 if (!This->namespaces)
2547 hr = SchemaCache_create(This->properties->version, NULL, (void**)&This->namespaces);
2548 if (hr != S_OK) return hr;
2550 hr = cache_from_doc_ns(This->namespaces, &This->node);
2551 if (hr != S_OK)
2552 release_namespaces(This);
2555 if (This->namespaces)
2556 return IXMLDOMSchemaCollection2_QueryInterface(This->namespaces,
2557 &IID_IXMLDOMSchemaCollection, (void**)collection);
2559 return hr;
2562 static HRESULT WINAPI domdoc_get_schemas(
2563 IXMLDOMDocument3* iface,
2564 VARIANT* schema )
2566 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2567 IXMLDOMSchemaCollection2* cur_schema = This->properties->schemaCache;
2568 HRESULT hr = S_FALSE;
2570 TRACE("(%p)->(%p)\n", This, schema);
2572 V_VT(schema) = VT_NULL;
2573 /* just to reset pointer part, cause that's what application is expected to use */
2574 V_DISPATCH(schema) = NULL;
2576 if(cur_schema)
2578 hr = IXMLDOMSchemaCollection2_QueryInterface(cur_schema, &IID_IDispatch, (void**)&V_DISPATCH(schema));
2579 if(SUCCEEDED(hr))
2580 V_VT(schema) = VT_DISPATCH;
2582 return hr;
2585 static HRESULT WINAPI domdoc_putref_schemas(
2586 IXMLDOMDocument3* iface,
2587 VARIANT schema)
2589 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2590 HRESULT hr = E_FAIL;
2591 IXMLDOMSchemaCollection2* new_schema = NULL;
2593 FIXME("(%p)->(%s): semi-stub\n", This, debugstr_variant(&schema));
2594 switch(V_VT(&schema))
2596 case VT_UNKNOWN:
2597 if (V_UNKNOWN(&schema))
2599 hr = IUnknown_QueryInterface(V_UNKNOWN(&schema), &IID_IXMLDOMSchemaCollection, (void**)&new_schema);
2600 break;
2602 /* fallthrough */
2603 case VT_DISPATCH:
2604 if (V_DISPATCH(&schema))
2606 hr = IDispatch_QueryInterface(V_DISPATCH(&schema), &IID_IXMLDOMSchemaCollection, (void**)&new_schema);
2607 break;
2609 /* fallthrough */
2610 case VT_NULL:
2611 case VT_EMPTY:
2612 hr = S_OK;
2613 break;
2615 default:
2616 WARN("Can't get schema from vt %x\n", V_VT(&schema));
2619 if(SUCCEEDED(hr))
2621 IXMLDOMSchemaCollection2* old_schema = InterlockedExchangePointer((void**)&This->properties->schemaCache, new_schema);
2622 if(old_schema) IXMLDOMSchemaCollection2_Release(old_schema);
2625 return hr;
2628 static inline BOOL is_wellformed(xmlDocPtr doc)
2630 #ifdef HAVE_XMLDOC_PROPERTIES
2631 return doc->properties & XML_DOC_WELLFORMED;
2632 #else
2633 /* Not a full check, but catches the worst violations */
2634 xmlNodePtr child;
2635 int root = 0;
2637 for (child = doc->children; child != NULL; child = child->next)
2639 switch (child->type)
2641 case XML_ELEMENT_NODE:
2642 if (++root > 1)
2643 return FALSE;
2644 break;
2645 case XML_TEXT_NODE:
2646 case XML_CDATA_SECTION_NODE:
2647 return FALSE;
2648 break;
2649 default:
2650 break;
2654 return root == 1;
2655 #endif
2658 static void LIBXML2_LOG_CALLBACK validate_error(void* ctx, char const* msg, ...)
2660 va_list ap;
2661 va_start(ap, msg);
2662 LIBXML2_CALLBACK_ERR(domdoc_validateNode, msg, ap);
2663 va_end(ap);
2666 static void LIBXML2_LOG_CALLBACK validate_warning(void* ctx, char const* msg, ...)
2668 va_list ap;
2669 va_start(ap, msg);
2670 LIBXML2_CALLBACK_WARN(domdoc_validateNode, msg, ap);
2671 va_end(ap);
2674 static HRESULT WINAPI domdoc_validateNode(
2675 IXMLDOMDocument3* iface,
2676 IXMLDOMNode* node,
2677 IXMLDOMParseError** err)
2679 domdoc* This = impl_from_IXMLDOMDocument3(iface);
2680 LONG state, err_code = 0;
2681 HRESULT hr = S_OK;
2682 int validated = 0;
2684 TRACE("(%p)->(%p, %p)\n", This, node, err);
2685 IXMLDOMDocument3_get_readyState(iface, &state);
2686 if (state != READYSTATE_COMPLETE)
2688 if (err)
2689 *err = create_parseError(err_code, NULL, NULL, NULL, 0, 0, 0);
2690 return E_PENDING;
2693 if (!node)
2695 if (err)
2696 *err = create_parseError(err_code, NULL, NULL, NULL, 0, 0, 0);
2697 return E_POINTER;
2700 if (!get_node_obj(node)->node || get_node_obj(node)->node->doc != get_doc(This))
2702 if (err)
2703 *err = create_parseError(err_code, NULL, NULL, NULL, 0, 0, 0);
2704 return E_FAIL;
2707 if (!is_wellformed(get_doc(This)))
2709 ERR("doc not well-formed\n");
2710 if (err)
2711 *err = create_parseError(E_XML_NOTWF, NULL, NULL, NULL, 0, 0, 0);
2712 return S_FALSE;
2715 /* DTD validation */
2716 if (get_doc(This)->intSubset || get_doc(This)->extSubset)
2718 xmlValidCtxtPtr vctx = xmlNewValidCtxt();
2719 vctx->error = validate_error;
2720 vctx->warning = validate_warning;
2721 ++validated;
2723 if (!((node == (IXMLDOMNode*)iface)?
2724 xmlValidateDocument(vctx, get_doc(This)) :
2725 xmlValidateElement(vctx, get_doc(This), get_node_obj(node)->node)))
2727 /* TODO: get a real error code here */
2728 TRACE("DTD validation failed\n");
2729 err_code = E_XML_INVALID;
2730 hr = S_FALSE;
2732 xmlFreeValidCtxt(vctx);
2735 /* Schema validation */
2736 if (hr == S_OK && This->properties->schemaCache != NULL)
2739 hr = SchemaCache_validate_tree(This->properties->schemaCache, get_node_obj(node)->node);
2740 if (SUCCEEDED(hr))
2742 ++validated;
2743 /* TODO: get a real error code here */
2744 if (hr == S_OK)
2746 TRACE("schema validation succeeded\n");
2748 else
2750 ERR("schema validation failed\n");
2751 err_code = E_XML_INVALID;
2754 else
2756 /* not really OK, just didn't find a schema for the ns */
2757 hr = S_OK;
2761 if (!validated)
2763 ERR("no DTD or schema found\n");
2764 err_code = E_XML_NODTD;
2765 hr = S_FALSE;
2768 if (err)
2769 *err = create_parseError(err_code, NULL, NULL, NULL, 0, 0, 0);
2771 return hr;
2774 static HRESULT WINAPI domdoc_validate(
2775 IXMLDOMDocument3* iface,
2776 IXMLDOMParseError** err)
2778 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2779 TRACE("(%p)->(%p)\n", This, err);
2780 return IXMLDOMDocument3_validateNode(iface, (IXMLDOMNode*)iface, err);
2783 static HRESULT WINAPI domdoc_setProperty(
2784 IXMLDOMDocument3* iface,
2785 BSTR p,
2786 VARIANT value)
2788 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2790 TRACE("(%p)->(%s %s)\n", This, debugstr_w(p), debugstr_variant(&value));
2792 if (lstrcmpiW(p, PropertySelectionLanguageW) == 0)
2794 VARIANT varStr;
2795 HRESULT hr;
2796 BSTR bstr;
2798 V_VT(&varStr) = VT_EMPTY;
2799 if (V_VT(&value) != VT_BSTR)
2801 if (FAILED(hr = VariantChangeType(&varStr, &value, 0, VT_BSTR)))
2802 return hr;
2803 bstr = V_BSTR(&varStr);
2805 else
2806 bstr = V_BSTR(&value);
2808 hr = S_OK;
2809 if (lstrcmpiW(bstr, PropValueXPathW) == 0)
2810 This->properties->XPath = TRUE;
2811 else if (lstrcmpiW(bstr, PropValueXSLPatternW) == 0)
2812 This->properties->XPath = FALSE;
2813 else
2814 hr = E_FAIL;
2816 VariantClear(&varStr);
2817 return hr;
2819 else if (lstrcmpiW(p, PropertySelectionNamespacesW) == 0)
2821 xmlChar *nsStr = (xmlChar*)This->properties->selectNsStr;
2822 struct list *pNsList;
2823 VARIANT varStr;
2824 HRESULT hr;
2825 BSTR bstr;
2827 V_VT(&varStr) = VT_EMPTY;
2828 if (V_VT(&value) != VT_BSTR)
2830 if (FAILED(hr = VariantChangeType(&varStr, &value, 0, VT_BSTR)))
2831 return hr;
2832 bstr = V_BSTR(&varStr);
2834 else
2835 bstr = V_BSTR(&value);
2837 hr = S_OK;
2839 pNsList = &(This->properties->selectNsList);
2840 clear_selectNsList(pNsList);
2841 heap_free(nsStr);
2842 nsStr = xmlchar_from_wchar(bstr);
2844 TRACE("property value: \"%s\"\n", debugstr_w(bstr));
2846 This->properties->selectNsStr = nsStr;
2847 This->properties->selectNsStr_len = xmlStrlen(nsStr);
2848 if (bstr && *bstr)
2850 xmlChar *pTokBegin, *pTokEnd, *pTokInner;
2851 select_ns_entry* ns_entry = NULL;
2852 xmlXPathContextPtr ctx;
2854 ctx = xmlXPathNewContext(This->node.node->doc);
2855 pTokBegin = nsStr;
2857 /* skip leading spaces */
2858 while (*pTokBegin == ' ' || *pTokBegin == '\n' ||
2859 *pTokBegin == '\t' || *pTokBegin == '\r')
2860 ++pTokBegin;
2862 for (; *pTokBegin; pTokBegin = pTokEnd)
2864 if (ns_entry)
2865 memset(ns_entry, 0, sizeof(select_ns_entry));
2866 else
2867 ns_entry = heap_alloc_zero(sizeof(select_ns_entry));
2869 while (*pTokBegin == ' ')
2870 ++pTokBegin;
2871 pTokEnd = pTokBegin;
2872 while (*pTokEnd != ' ' && *pTokEnd != 0)
2873 ++pTokEnd;
2875 /* so it failed to advance which means we've got some trailing spaces */
2876 if (pTokEnd == pTokBegin) break;
2878 if (xmlStrncmp(pTokBegin, (xmlChar const*)"xmlns", 5) != 0)
2880 hr = E_FAIL;
2881 WARN("Syntax error in xmlns string: %s\n\tat token: %s\n",
2882 debugstr_w(bstr), debugstr_an((const char*)pTokBegin, pTokEnd-pTokBegin));
2883 continue;
2886 pTokBegin += 5;
2887 if (*pTokBegin == '=')
2889 /*valid for XSLPattern?*/
2890 FIXME("Setting default xmlns not supported - skipping.\n");
2891 continue;
2893 else if (*pTokBegin == ':')
2895 ns_entry->prefix = ++pTokBegin;
2896 for (pTokInner = pTokBegin; pTokInner != pTokEnd && *pTokInner != '='; ++pTokInner)
2899 if (pTokInner == pTokEnd)
2901 hr = E_FAIL;
2902 WARN("Syntax error in xmlns string: %s\n\tat token: %s\n",
2903 debugstr_w(bstr), debugstr_an((const char*)pTokBegin, pTokEnd-pTokBegin));
2904 continue;
2907 ns_entry->prefix_end = *pTokInner;
2908 *pTokInner = 0;
2909 ++pTokInner;
2911 if (pTokEnd-pTokInner > 1 &&
2912 ((*pTokInner == '\'' && *(pTokEnd-1) == '\'') ||
2913 (*pTokInner == '"' && *(pTokEnd-1) == '"')))
2915 ns_entry->href = ++pTokInner;
2916 ns_entry->href_end = *(pTokEnd-1);
2917 *(pTokEnd-1) = 0;
2918 list_add_tail(pNsList, &ns_entry->entry);
2919 /*let libxml figure out if they're valid from here ;)*/
2920 if (xmlXPathRegisterNs(ctx, ns_entry->prefix, ns_entry->href) != 0)
2922 hr = E_FAIL;
2924 ns_entry = NULL;
2925 continue;
2927 else
2929 WARN("Syntax error in xmlns string: %s\n\tat token: %s\n",
2930 debugstr_w(bstr), debugstr_an((const char*)pTokInner, pTokEnd-pTokInner));
2931 list_add_tail(pNsList, &ns_entry->entry);
2933 ns_entry = NULL;
2934 hr = E_FAIL;
2935 continue;
2938 else
2940 hr = E_FAIL;
2941 continue;
2944 heap_free(ns_entry);
2945 xmlXPathFreeContext(ctx);
2948 VariantClear(&varStr);
2949 return hr;
2951 else if (lstrcmpiW(p, PropertyProhibitDTDW) == 0 ||
2952 lstrcmpiW(p, PropertyNewParserW) == 0 ||
2953 lstrcmpiW(p, PropertyResolveExternalsW) == 0)
2955 /* Ignore */
2956 FIXME("Ignoring property %s, value %d\n", debugstr_w(p), V_BOOL(&value));
2957 return S_OK;
2960 FIXME("Unknown property %s\n", debugstr_w(p));
2961 return E_FAIL;
2964 static HRESULT WINAPI domdoc_getProperty(
2965 IXMLDOMDocument3* iface,
2966 BSTR p,
2967 VARIANT* var)
2969 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2971 TRACE("(%p)->(%s)\n", This, debugstr_w(p));
2973 if (!var)
2974 return E_INVALIDARG;
2976 if (lstrcmpiW(p, PropertySelectionLanguageW) == 0)
2978 V_VT(var) = VT_BSTR;
2979 V_BSTR(var) = This->properties->XPath ?
2980 SysAllocString(PropValueXPathW) :
2981 SysAllocString(PropValueXSLPatternW);
2982 return V_BSTR(var) ? S_OK : E_OUTOFMEMORY;
2984 else if (lstrcmpiW(p, PropertySelectionNamespacesW) == 0)
2986 int lenA, lenW;
2987 BSTR rebuiltStr, cur;
2988 const xmlChar *nsStr;
2989 struct list *pNsList;
2990 select_ns_entry* pNsEntry;
2992 V_VT(var) = VT_BSTR;
2993 nsStr = This->properties->selectNsStr;
2994 pNsList = &This->properties->selectNsList;
2995 lenA = This->properties->selectNsStr_len;
2996 lenW = MultiByteToWideChar(CP_UTF8, 0, (LPCSTR)nsStr, lenA+1, NULL, 0);
2997 rebuiltStr = heap_alloc(lenW*sizeof(WCHAR));
2998 MultiByteToWideChar(CP_UTF8, 0, (LPCSTR)nsStr, lenA+1, rebuiltStr, lenW);
2999 cur = rebuiltStr;
3000 /* this is fine because all of the chars that end tokens are ASCII*/
3001 LIST_FOR_EACH_ENTRY(pNsEntry, pNsList, select_ns_entry, entry)
3003 while (*cur != 0) ++cur;
3004 if (pNsEntry->prefix_end)
3006 *cur = pNsEntry->prefix_end;
3007 while (*cur != 0) ++cur;
3010 if (pNsEntry->href_end)
3012 *cur = pNsEntry->href_end;
3015 V_BSTR(var) = SysAllocString(rebuiltStr);
3016 heap_free(rebuiltStr);
3017 return S_OK;
3020 FIXME("Unknown property %s\n", debugstr_w(p));
3021 return E_FAIL;
3024 static HRESULT WINAPI domdoc_importNode(
3025 IXMLDOMDocument3* iface,
3026 IXMLDOMNode* node,
3027 VARIANT_BOOL deep,
3028 IXMLDOMNode** clone)
3030 domdoc *This = impl_from_IXMLDOMDocument3( iface );
3031 FIXME("(%p)->(%p %d %p): stub\n", This, node, deep, clone);
3032 return E_NOTIMPL;
3035 static const struct IXMLDOMDocument3Vtbl XMLDOMDocument3Vtbl =
3037 domdoc_QueryInterface,
3038 domdoc_AddRef,
3039 domdoc_Release,
3040 domdoc_GetTypeInfoCount,
3041 domdoc_GetTypeInfo,
3042 domdoc_GetIDsOfNames,
3043 domdoc_Invoke,
3044 domdoc_get_nodeName,
3045 domdoc_get_nodeValue,
3046 domdoc_put_nodeValue,
3047 domdoc_get_nodeType,
3048 domdoc_get_parentNode,
3049 domdoc_get_childNodes,
3050 domdoc_get_firstChild,
3051 domdoc_get_lastChild,
3052 domdoc_get_previousSibling,
3053 domdoc_get_nextSibling,
3054 domdoc_get_attributes,
3055 domdoc_insertBefore,
3056 domdoc_replaceChild,
3057 domdoc_removeChild,
3058 domdoc_appendChild,
3059 domdoc_hasChildNodes,
3060 domdoc_get_ownerDocument,
3061 domdoc_cloneNode,
3062 domdoc_get_nodeTypeString,
3063 domdoc_get_text,
3064 domdoc_put_text,
3065 domdoc_get_specified,
3066 domdoc_get_definition,
3067 domdoc_get_nodeTypedValue,
3068 domdoc_put_nodeTypedValue,
3069 domdoc_get_dataType,
3070 domdoc_put_dataType,
3071 domdoc_get_xml,
3072 domdoc_transformNode,
3073 domdoc_selectNodes,
3074 domdoc_selectSingleNode,
3075 domdoc_get_parsed,
3076 domdoc_get_namespaceURI,
3077 domdoc_get_prefix,
3078 domdoc_get_baseName,
3079 domdoc_transformNodeToObject,
3080 domdoc_get_doctype,
3081 domdoc_get_implementation,
3082 domdoc_get_documentElement,
3083 domdoc_put_documentElement,
3084 domdoc_createElement,
3085 domdoc_createDocumentFragment,
3086 domdoc_createTextNode,
3087 domdoc_createComment,
3088 domdoc_createCDATASection,
3089 domdoc_createProcessingInstruction,
3090 domdoc_createAttribute,
3091 domdoc_createEntityReference,
3092 domdoc_getElementsByTagName,
3093 domdoc_createNode,
3094 domdoc_nodeFromID,
3095 domdoc_load,
3096 domdoc_get_readyState,
3097 domdoc_get_parseError,
3098 domdoc_get_url,
3099 domdoc_get_async,
3100 domdoc_put_async,
3101 domdoc_abort,
3102 domdoc_loadXML,
3103 domdoc_save,
3104 domdoc_get_validateOnParse,
3105 domdoc_put_validateOnParse,
3106 domdoc_get_resolveExternals,
3107 domdoc_put_resolveExternals,
3108 domdoc_get_preserveWhiteSpace,
3109 domdoc_put_preserveWhiteSpace,
3110 domdoc_put_onreadystatechange,
3111 domdoc_put_onDataAvailable,
3112 domdoc_put_onTransformNode,
3113 domdoc_get_namespaces,
3114 domdoc_get_schemas,
3115 domdoc_putref_schemas,
3116 domdoc_validate,
3117 domdoc_setProperty,
3118 domdoc_getProperty,
3119 domdoc_validateNode,
3120 domdoc_importNode
3123 /* IConnectionPointContainer */
3124 static HRESULT WINAPI ConnectionPointContainer_QueryInterface(IConnectionPointContainer *iface,
3125 REFIID riid, void **ppv)
3127 domdoc *This = impl_from_IConnectionPointContainer(iface);
3128 return IXMLDOMDocument3_QueryInterface(&This->IXMLDOMDocument3_iface, riid, ppv);
3131 static ULONG WINAPI ConnectionPointContainer_AddRef(IConnectionPointContainer *iface)
3133 domdoc *This = impl_from_IConnectionPointContainer(iface);
3134 return IXMLDOMDocument3_AddRef(&This->IXMLDOMDocument3_iface);
3137 static ULONG WINAPI ConnectionPointContainer_Release(IConnectionPointContainer *iface)
3139 domdoc *This = impl_from_IConnectionPointContainer(iface);
3140 return IXMLDOMDocument3_Release(&This->IXMLDOMDocument3_iface);
3143 static HRESULT WINAPI ConnectionPointContainer_EnumConnectionPoints(IConnectionPointContainer *iface,
3144 IEnumConnectionPoints **ppEnum)
3146 domdoc *This = impl_from_IConnectionPointContainer(iface);
3147 FIXME("(%p)->(%p): stub\n", This, ppEnum);
3148 return E_NOTIMPL;
3151 static HRESULT WINAPI ConnectionPointContainer_FindConnectionPoint(IConnectionPointContainer *iface,
3152 REFIID riid, IConnectionPoint **cp)
3154 domdoc *This = impl_from_IConnectionPointContainer(iface);
3155 ConnectionPoint *iter;
3157 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), cp);
3159 *cp = NULL;
3161 for(iter = This->cp_list; iter; iter = iter->next)
3163 if (IsEqualGUID(iter->iid, riid))
3164 *cp = &iter->IConnectionPoint_iface;
3167 if (*cp)
3169 IConnectionPoint_AddRef(*cp);
3170 return S_OK;
3173 FIXME("unsupported riid %s\n", debugstr_guid(riid));
3174 return CONNECT_E_NOCONNECTION;
3178 static const struct IConnectionPointContainerVtbl ConnectionPointContainerVtbl =
3180 ConnectionPointContainer_QueryInterface,
3181 ConnectionPointContainer_AddRef,
3182 ConnectionPointContainer_Release,
3183 ConnectionPointContainer_EnumConnectionPoints,
3184 ConnectionPointContainer_FindConnectionPoint
3187 /* IConnectionPoint */
3188 static HRESULT WINAPI ConnectionPoint_QueryInterface(IConnectionPoint *iface,
3189 REFIID riid, void **ppv)
3191 ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3193 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv );
3195 *ppv = NULL;
3197 if (IsEqualGUID(&IID_IUnknown, riid) ||
3198 IsEqualGUID(&IID_IConnectionPoint, riid))
3200 *ppv = iface;
3203 if (*ppv)
3205 IConnectionPoint_AddRef(iface);
3206 return S_OK;
3209 WARN("Unsupported interface %s\n", debugstr_guid(riid));
3210 return E_NOINTERFACE;
3213 static ULONG WINAPI ConnectionPoint_AddRef(IConnectionPoint *iface)
3215 ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3216 return IConnectionPointContainer_AddRef(This->container);
3219 static ULONG WINAPI ConnectionPoint_Release(IConnectionPoint *iface)
3221 ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3222 return IConnectionPointContainer_Release(This->container);
3225 static HRESULT WINAPI ConnectionPoint_GetConnectionInterface(IConnectionPoint *iface, IID *iid)
3227 ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3229 TRACE("(%p)->(%p)\n", This, iid);
3231 if (!iid) return E_POINTER;
3233 *iid = *This->iid;
3234 return S_OK;
3237 static HRESULT WINAPI ConnectionPoint_GetConnectionPointContainer(IConnectionPoint *iface,
3238 IConnectionPointContainer **container)
3240 ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3242 TRACE("(%p)->(%p)\n", This, container);
3244 if (!container) return E_POINTER;
3246 *container = This->container;
3247 IConnectionPointContainer_AddRef(*container);
3248 return S_OK;
3251 static HRESULT WINAPI ConnectionPoint_Advise(IConnectionPoint *iface, IUnknown *pUnkSink,
3252 DWORD *pdwCookie)
3254 ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3255 FIXME("(%p)->(%p %p): stub\n", This, pUnkSink, pdwCookie);
3256 return E_NOTIMPL;
3259 static HRESULT WINAPI ConnectionPoint_Unadvise(IConnectionPoint *iface, DWORD cookie)
3261 ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3263 TRACE("(%p)->(%d)\n", This, cookie);
3265 if (cookie == 0 || cookie > This->sinks_size || !This->sinks[cookie-1].unk)
3266 return CONNECT_E_NOCONNECTION;
3268 IUnknown_Release(This->sinks[cookie-1].unk);
3269 This->sinks[cookie-1].unk = NULL;
3271 return S_OK;
3274 static HRESULT WINAPI ConnectionPoint_EnumConnections(IConnectionPoint *iface,
3275 IEnumConnections **ppEnum)
3277 ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3278 FIXME("(%p)->(%p): stub\n", This, ppEnum);
3279 return E_NOTIMPL;
3282 static const IConnectionPointVtbl ConnectionPointVtbl =
3284 ConnectionPoint_QueryInterface,
3285 ConnectionPoint_AddRef,
3286 ConnectionPoint_Release,
3287 ConnectionPoint_GetConnectionInterface,
3288 ConnectionPoint_GetConnectionPointContainer,
3289 ConnectionPoint_Advise,
3290 ConnectionPoint_Unadvise,
3291 ConnectionPoint_EnumConnections
3294 static void ConnectionPoint_Init(ConnectionPoint *cp, struct domdoc *doc, REFIID riid)
3296 cp->IConnectionPoint_iface.lpVtbl = &ConnectionPointVtbl;
3297 cp->doc = doc;
3298 cp->iid = riid;
3299 cp->sinks = NULL;
3300 cp->sinks_size = 0;
3302 cp->next = doc->cp_list;
3303 doc->cp_list = cp;
3305 cp->container = &doc->IConnectionPointContainer_iface;
3308 /* domdoc implementation of IObjectWithSite */
3309 static HRESULT WINAPI
3310 domdoc_ObjectWithSite_QueryInterface( IObjectWithSite* iface, REFIID riid, void** ppvObject )
3312 domdoc *This = impl_from_IObjectWithSite(iface);
3313 return IXMLDOMDocument3_QueryInterface(&This->IXMLDOMDocument3_iface, riid, ppvObject);
3316 static ULONG WINAPI domdoc_ObjectWithSite_AddRef( IObjectWithSite* iface )
3318 domdoc *This = impl_from_IObjectWithSite(iface);
3319 return IXMLDOMDocument3_AddRef(&This->IXMLDOMDocument3_iface);
3322 static ULONG WINAPI domdoc_ObjectWithSite_Release( IObjectWithSite* iface )
3324 domdoc *This = impl_from_IObjectWithSite(iface);
3325 return IXMLDOMDocument3_Release(&This->IXMLDOMDocument3_iface);
3328 static HRESULT WINAPI domdoc_ObjectWithSite_GetSite( IObjectWithSite *iface, REFIID iid, void **ppvSite )
3330 domdoc *This = impl_from_IObjectWithSite(iface);
3332 TRACE("(%p)->(%s %p)\n", This, debugstr_guid( iid ), ppvSite );
3334 if ( !This->site )
3335 return E_FAIL;
3337 return IUnknown_QueryInterface( This->site, iid, ppvSite );
3340 static HRESULT WINAPI domdoc_ObjectWithSite_SetSite( IObjectWithSite *iface, IUnknown *punk )
3342 domdoc *This = impl_from_IObjectWithSite(iface);
3344 TRACE("(%p)->(%p)\n", iface, punk);
3346 if(!punk)
3348 if(This->site)
3350 IUnknown_Release( This->site );
3351 This->site = NULL;
3354 return S_OK;
3357 IUnknown_AddRef( punk );
3359 if(This->site)
3360 IUnknown_Release( This->site );
3362 This->site = punk;
3364 return S_OK;
3367 static const IObjectWithSiteVtbl domdocObjectSite =
3369 domdoc_ObjectWithSite_QueryInterface,
3370 domdoc_ObjectWithSite_AddRef,
3371 domdoc_ObjectWithSite_Release,
3372 domdoc_ObjectWithSite_SetSite,
3373 domdoc_ObjectWithSite_GetSite
3376 static HRESULT WINAPI domdoc_Safety_QueryInterface(IObjectSafety *iface, REFIID riid, void **ppv)
3378 domdoc *This = impl_from_IObjectSafety(iface);
3379 return IXMLDOMDocument3_QueryInterface(&This->IXMLDOMDocument3_iface, riid, ppv);
3382 static ULONG WINAPI domdoc_Safety_AddRef(IObjectSafety *iface)
3384 domdoc *This = impl_from_IObjectSafety(iface);
3385 return IXMLDOMDocument3_AddRef(&This->IXMLDOMDocument3_iface);
3388 static ULONG WINAPI domdoc_Safety_Release(IObjectSafety *iface)
3390 domdoc *This = impl_from_IObjectSafety(iface);
3391 return IXMLDOMDocument3_Release(&This->IXMLDOMDocument3_iface);
3394 #define SAFETY_SUPPORTED_OPTIONS (INTERFACESAFE_FOR_UNTRUSTED_CALLER|INTERFACESAFE_FOR_UNTRUSTED_DATA|INTERFACE_USES_SECURITY_MANAGER)
3396 static HRESULT WINAPI domdoc_Safety_GetInterfaceSafetyOptions(IObjectSafety *iface, REFIID riid,
3397 DWORD *supported, DWORD *enabled)
3399 domdoc *This = impl_from_IObjectSafety(iface);
3401 TRACE("(%p)->(%s %p %p)\n", This, debugstr_guid(riid), supported, enabled);
3403 if(!supported || !enabled) return E_POINTER;
3405 *supported = SAFETY_SUPPORTED_OPTIONS;
3406 *enabled = This->safeopt;
3408 return S_OK;
3411 static HRESULT WINAPI domdoc_Safety_SetInterfaceSafetyOptions(IObjectSafety *iface, REFIID riid,
3412 DWORD mask, DWORD enabled)
3414 domdoc *This = impl_from_IObjectSafety(iface);
3415 TRACE("(%p)->(%s %x %x)\n", This, debugstr_guid(riid), mask, enabled);
3417 if ((mask & ~SAFETY_SUPPORTED_OPTIONS) != 0)
3418 return E_FAIL;
3420 This->safeopt = (This->safeopt & ~mask) | (mask & enabled);
3422 return S_OK;
3425 #undef SAFETY_SUPPORTED_OPTIONS
3427 static const IObjectSafetyVtbl domdocObjectSafetyVtbl = {
3428 domdoc_Safety_QueryInterface,
3429 domdoc_Safety_AddRef,
3430 domdoc_Safety_Release,
3431 domdoc_Safety_GetInterfaceSafetyOptions,
3432 domdoc_Safety_SetInterfaceSafetyOptions
3435 static const tid_t domdoc_iface_tids[] = {
3436 IXMLDOMDocument3_tid,
3440 static dispex_static_data_t domdoc_dispex = {
3441 NULL,
3442 IXMLDOMDocument3_tid,
3443 NULL,
3444 domdoc_iface_tids
3447 HRESULT get_domdoc_from_xmldoc(xmlDocPtr xmldoc, IXMLDOMDocument3 **document)
3449 domdoc *doc;
3451 doc = heap_alloc( sizeof (*doc) );
3452 if( !doc )
3453 return E_OUTOFMEMORY;
3455 doc->IXMLDOMDocument3_iface.lpVtbl = &XMLDOMDocument3Vtbl;
3456 doc->IPersistStreamInit_iface.lpVtbl = &xmldoc_IPersistStreamInit_VTable;
3457 doc->IObjectWithSite_iface.lpVtbl = &domdocObjectSite;
3458 doc->IObjectSafety_iface.lpVtbl = &domdocObjectSafetyVtbl;
3459 doc->IConnectionPointContainer_iface.lpVtbl = &ConnectionPointContainerVtbl;
3460 doc->ref = 1;
3461 doc->async = VARIANT_TRUE;
3462 doc->validating = 0;
3463 doc->resolving = 0;
3464 doc->properties = properties_from_xmlDocPtr(xmldoc);
3465 doc->error = S_OK;
3466 doc->stream = NULL;
3467 doc->site = NULL;
3468 doc->safeopt = 0;
3469 doc->bsc = NULL;
3470 doc->cp_list = NULL;
3471 doc->namespaces = NULL;
3472 memset(doc->events, 0, sizeof(doc->events));
3474 /* events connection points */
3475 ConnectionPoint_Init(&doc->cp_dispatch, doc, &IID_IDispatch);
3476 ConnectionPoint_Init(&doc->cp_propnotif, doc, &IID_IPropertyNotifySink);
3477 ConnectionPoint_Init(&doc->cp_domdocevents, doc, &DIID_XMLDOMDocumentEvents);
3479 init_xmlnode(&doc->node, (xmlNodePtr)xmldoc, (IXMLDOMNode*)&doc->IXMLDOMDocument3_iface,
3480 &domdoc_dispex);
3482 *document = &doc->IXMLDOMDocument3_iface;
3484 TRACE("returning iface %p\n", *document);
3485 return S_OK;
3488 HRESULT DOMDocument_create(MSXML_VERSION version, IUnknown *pUnkOuter, void **ppObj)
3490 xmlDocPtr xmldoc;
3491 HRESULT hr;
3493 TRACE("(%d, %p, %p)\n", version, pUnkOuter, ppObj);
3495 xmldoc = xmlNewDoc(NULL);
3496 if(!xmldoc)
3497 return E_OUTOFMEMORY;
3499 xmldoc_init(xmldoc, version);
3501 hr = get_domdoc_from_xmldoc(xmldoc, (IXMLDOMDocument3**)ppObj);
3502 if(FAILED(hr))
3504 free_properties(properties_from_xmlDocPtr(xmldoc));
3505 heap_free(xmldoc->_private);
3506 xmlFreeDoc(xmldoc);
3507 return hr;
3510 return hr;
3513 IUnknown* create_domdoc( xmlNodePtr document )
3515 void* pObj = NULL;
3516 HRESULT hr;
3518 TRACE("(%p)\n", document);
3520 hr = get_domdoc_from_xmldoc((xmlDocPtr)document, (IXMLDOMDocument3**)&pObj);
3521 if (FAILED(hr))
3522 return NULL;
3524 return pObj;
3527 #else
3529 HRESULT DOMDocument_create(MSXML_VERSION version, IUnknown *pUnkOuter, void **ppObj)
3531 MESSAGE("This program tried to use a DOMDocument object, but\n"
3532 "libxml2 support was not present at compile time.\n");
3533 return E_NOTIMPL;
3536 #endif