d3d10core: Implement d3d10_device_OMGetRenderTargets().
[wine.git] / dlls / msxml3 / domdoc.c
blob2244172eabfebcbca9c7b4b256942a8cf12da99b
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"
53 #include "msxml_private.h"
55 WINE_DEFAULT_DEBUG_CHANNEL(msxml);
57 #ifdef HAVE_LIBXML2
59 /* not defined in older versions */
60 #define XML_SAVE_FORMAT 1
61 #define XML_SAVE_NO_DECL 2
62 #define XML_SAVE_NO_EMPTY 4
63 #define XML_SAVE_NO_XHTML 8
64 #define XML_SAVE_XHTML 16
65 #define XML_SAVE_AS_XML 32
66 #define XML_SAVE_AS_HTML 64
68 static const WCHAR PropertySelectionLanguageW[] = {'S','e','l','e','c','t','i','o','n','L','a','n','g','u','a','g','e',0};
69 static const WCHAR PropertySelectionNamespacesW[] = {'S','e','l','e','c','t','i','o','n','N','a','m','e','s','p','a','c','e','s',0};
70 static const WCHAR PropertyProhibitDTDW[] = {'P','r','o','h','i','b','i','t','D','T','D',0};
71 static const WCHAR PropertyNewParserW[] = {'N','e','w','P','a','r','s','e','r',0};
72 static const WCHAR PropValueXPathW[] = {'X','P','a','t','h',0};
73 static const WCHAR PropValueXSLPatternW[] = {'X','S','L','P','a','t','t','e','r','n',0};
74 static const WCHAR PropertyResolveExternalsW[] = {'R','e','s','o','l','v','e','E','x','t','e','r','n','a','l','s',0};
76 /* Anything that passes the test_get_ownerDocument()
77 * tests can go here (data shared between all instances).
78 * We need to preserve this when reloading a document,
79 * and also need access to it from the libxml backend. */
80 typedef struct {
81 MSXML_VERSION version;
82 VARIANT_BOOL preserving;
83 IXMLDOMSchemaCollection2* schemaCache;
84 struct list selectNsList;
85 xmlChar const* selectNsStr;
86 LONG selectNsStr_len;
87 BOOL XPath;
88 WCHAR *url;
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 HRESULT error;
134 /* IObjectWithSite */
135 IUnknown *site;
137 /* IObjectSafety */
138 DWORD safeopt;
140 /* connection list */
141 ConnectionPoint *cp_list;
142 ConnectionPoint cp_domdocevents;
143 ConnectionPoint cp_propnotif;
144 ConnectionPoint cp_dispatch;
146 /* events */
147 IDispatch *events[EVENTID_LAST];
149 IXMLDOMSchemaCollection2 *namespaces;
152 static HRESULT set_doc_event(domdoc *doc, eventid_t eid, const VARIANT *v)
154 IDispatch *disp;
156 switch (V_VT(v))
158 case VT_UNKNOWN:
159 if (V_UNKNOWN(v))
160 IUnknown_QueryInterface(V_UNKNOWN(v), &IID_IDispatch, (void**)&disp);
161 else
162 disp = NULL;
163 break;
164 case VT_DISPATCH:
165 disp = V_DISPATCH(v);
166 if (disp) IDispatch_AddRef(disp);
167 break;
168 default:
169 return DISP_E_TYPEMISMATCH;
172 if (doc->events[eid]) IDispatch_Release(doc->events[eid]);
173 doc->events[eid] = disp;
175 return S_OK;
178 static inline ConnectionPoint *impl_from_IConnectionPoint(IConnectionPoint *iface)
180 return CONTAINING_RECORD(iface, ConnectionPoint, IConnectionPoint_iface);
184 In native windows, the whole lifetime management of XMLDOMNodes is
185 managed automatically using reference counts. Wine emulates that by
186 maintaining a reference count to the document that is increased for
187 each IXMLDOMNode pointer passed out for this document. If all these
188 pointers are gone, the document is unreachable and gets freed, that
189 is, all nodes in the tree of the document get freed.
191 You are able to create nodes that are associated to a document (in
192 fact, in msxml's XMLDOM model, all nodes are associated to a document),
193 but not in the tree of that document, for example using the createFoo
194 functions from IXMLDOMDocument. These nodes do not get cleaned up
195 by libxml, so we have to do it ourselves.
197 To catch these nodes, a list of "orphan nodes" is introduced.
198 It contains pointers to all roots of node trees that are
199 associated with the document without being part of the document
200 tree. All nodes with parent==NULL (except for the document root nodes)
201 should be in the orphan node list of their document. All orphan nodes
202 get freed together with the document itself.
205 typedef struct _xmldoc_priv {
206 LONG refs;
207 struct list orphans;
208 domdoc_properties* properties;
209 } xmldoc_priv;
211 typedef struct _orphan_entry {
212 struct list entry;
213 xmlNode * node;
214 } orphan_entry;
216 typedef struct _select_ns_entry {
217 struct list entry;
218 xmlChar const* prefix;
219 xmlChar prefix_end;
220 xmlChar const* href;
221 xmlChar href_end;
222 } select_ns_entry;
224 static inline xmldoc_priv * priv_from_xmlDocPtr(const xmlDocPtr doc)
226 return doc->_private;
229 static inline domdoc_properties * properties_from_xmlDocPtr(xmlDocPtr doc)
231 return priv_from_xmlDocPtr(doc)->properties;
234 BOOL is_xpathmode(const xmlDocPtr doc)
236 return properties_from_xmlDocPtr(doc)->XPath;
239 void set_xpathmode(xmlDocPtr doc, BOOL xpath)
241 properties_from_xmlDocPtr(doc)->XPath = xpath;
244 int registerNamespaces(xmlXPathContextPtr ctxt)
246 int n = 0;
247 const select_ns_entry* ns = NULL;
248 const struct list* pNsList = &properties_from_xmlDocPtr(ctxt->doc)->selectNsList;
250 TRACE("(%p)\n", ctxt);
252 LIST_FOR_EACH_ENTRY( ns, pNsList, select_ns_entry, entry )
254 xmlXPathRegisterNs(ctxt, ns->prefix, ns->href);
255 ++n;
258 return n;
261 static inline void clear_selectNsList(struct list* pNsList)
263 select_ns_entry *ns, *ns2;
264 LIST_FOR_EACH_ENTRY_SAFE( ns, ns2, pNsList, select_ns_entry, entry )
266 heap_free( ns );
268 list_init(pNsList);
271 static xmldoc_priv * create_priv(void)
273 xmldoc_priv *priv;
274 priv = heap_alloc( sizeof (*priv) );
276 if (priv)
278 priv->refs = 0;
279 list_init( &priv->orphans );
280 priv->properties = NULL;
283 return priv;
286 static domdoc_properties *create_properties(MSXML_VERSION version)
288 domdoc_properties *properties = heap_alloc(sizeof(domdoc_properties));
290 list_init(&properties->selectNsList);
291 properties->preserving = VARIANT_FALSE;
292 properties->schemaCache = NULL;
293 properties->selectNsStr = heap_alloc_zero(sizeof(xmlChar));
294 properties->selectNsStr_len = 0;
296 /* properties that are dependent on object versions */
297 properties->version = version;
298 properties->XPath = (version == MSXML4 || version == MSXML6);
300 /* document url */
301 properties->url = NULL;
303 return properties;
306 static domdoc_properties* copy_properties(domdoc_properties const* properties)
308 domdoc_properties* pcopy = heap_alloc(sizeof(domdoc_properties));
309 select_ns_entry const* ns = NULL;
310 select_ns_entry* new_ns = NULL;
311 int len = (properties->selectNsStr_len+1)*sizeof(xmlChar);
312 ptrdiff_t offset;
314 if (pcopy)
316 pcopy->version = properties->version;
317 pcopy->preserving = properties->preserving;
318 pcopy->schemaCache = properties->schemaCache;
319 if (pcopy->schemaCache)
320 IXMLDOMSchemaCollection2_AddRef(pcopy->schemaCache);
321 pcopy->XPath = properties->XPath;
322 pcopy->selectNsStr_len = properties->selectNsStr_len;
323 list_init( &pcopy->selectNsList );
324 pcopy->selectNsStr = heap_alloc(len);
325 memcpy((xmlChar*)pcopy->selectNsStr, properties->selectNsStr, len);
326 offset = pcopy->selectNsStr - properties->selectNsStr;
328 LIST_FOR_EACH_ENTRY( ns, (&properties->selectNsList), select_ns_entry, entry )
330 new_ns = heap_alloc(sizeof(select_ns_entry));
331 memcpy(new_ns, ns, sizeof(select_ns_entry));
332 new_ns->href += offset;
333 new_ns->prefix += offset;
334 list_add_tail(&pcopy->selectNsList, &new_ns->entry);
337 if (properties->url)
339 int len = strlenW(properties->url);
341 pcopy->url = CoTaskMemAlloc((len+1)*sizeof(WCHAR));
342 memcpy(pcopy->url, properties->url, len*sizeof(WCHAR));
343 pcopy->url[len] = 0;
345 else
346 pcopy->url = NULL;
349 return pcopy;
352 static void free_properties(domdoc_properties* properties)
354 if (properties)
356 if (properties->schemaCache)
357 IXMLDOMSchemaCollection2_Release(properties->schemaCache);
358 clear_selectNsList(&properties->selectNsList);
359 heap_free((xmlChar*)properties->selectNsStr);
360 CoTaskMemFree(properties->url);
361 heap_free(properties);
365 static void release_namespaces(domdoc *This)
367 if (This->namespaces)
369 IXMLDOMSchemaCollection2_Release(This->namespaces);
370 This->namespaces = NULL;
374 /* links a "<?xml" node as a first child */
375 void xmldoc_link_xmldecl(xmlDocPtr doc, xmlNodePtr node)
377 assert(doc != NULL);
378 if (doc->standalone != -1) xmlAddPrevSibling( doc->children, node );
381 /* unlinks a first "<?xml" child if it was created */
382 xmlNodePtr xmldoc_unlink_xmldecl(xmlDocPtr doc)
384 static const xmlChar xmlA[] = "xml";
385 xmlNodePtr node, first_child;
387 assert(doc != NULL);
389 /* xml declaration node could be created automatically after parsing or added
390 to a tree later */
391 first_child = doc->children;
392 if (first_child && first_child->type == XML_PI_NODE && xmlStrEqual(first_child->name, xmlA))
394 node = first_child;
395 xmlUnlinkNode( node );
397 else
398 node = NULL;
400 return node;
403 BOOL is_preserving_whitespace(xmlNodePtr node)
405 domdoc_properties* properties = NULL;
406 /* during parsing the xmlDoc._private stuff is not there */
407 if (priv_from_xmlDocPtr(node->doc))
408 properties = properties_from_xmlDocPtr(node->doc);
409 return ((properties && properties->preserving == VARIANT_TRUE) ||
410 xmlNodeGetSpacePreserve(node) == 1);
413 static inline BOOL strn_isspace(xmlChar const* str, int len)
415 for (; str && len > 0 && *str; ++str, --len)
416 if (!isspace(*str))
417 break;
419 return len == 0;
422 static void sax_characters(void *ctx, const xmlChar *ch, int len)
424 xmlParserCtxtPtr ctxt;
425 const domdoc *This;
427 ctxt = (xmlParserCtxtPtr) ctx;
428 This = (const domdoc*) ctxt->_private;
430 if (ctxt->node)
432 xmlChar cur = *(ctxt->input->cur);
434 /* Characters are reported with multiple calls, for example each charref is reported with a separate
435 call and then parser appends it to a single text node or creates a new node if not created.
436 It's not possible to tell if it's ignorable data or not just looking at data itself cause it could be
437 space chars that separate charrefs or similar case. We only need to skip leading and trailing spaces,
438 or whole node if it has nothing but space chars, so to detect leading space node->last is checked that
439 contains text node pointer if already created, trailing spaces are detected directly looking at parser input
440 for next '<' opening bracket - similar logic is used by libxml2 itself. Basically 'cur' == '<' means the last
441 chunk of char data, in case it's not the last chunk we check for previously added node type and if it's not
442 a text node it's safe to ignore.
444 Note that during domdoc_loadXML() the xmlDocPtr->_private data is not available. */
446 if (!This->properties->preserving &&
447 !is_preserving_whitespace(ctxt->node) &&
448 strn_isspace(ch, len) &&
449 (!ctxt->node->last ||
450 ((ctxt->node->last && (cur == '<' || ctxt->node->last->type != XML_TEXT_NODE))
452 return;
455 xmlSAX2Characters(ctxt, ch, len);
458 static void LIBXML2_LOG_CALLBACK sax_error(void* ctx, char const* msg, ...)
460 va_list ap;
461 va_start(ap, msg);
462 LIBXML2_CALLBACK_ERR(doparse, msg, ap);
463 va_end(ap);
466 static void LIBXML2_LOG_CALLBACK sax_warning(void* ctx, char const* msg, ...)
468 va_list ap;
469 va_start(ap, msg);
470 LIBXML2_CALLBACK_WARN(doparse, msg, ap);
471 va_end(ap);
474 static void sax_serror(void* ctx, xmlErrorPtr err)
476 LIBXML2_CALLBACK_SERROR(doparse, err);
479 static xmlDocPtr doparse(domdoc* This, char const* ptr, int len, xmlCharEncoding encoding)
481 xmlDocPtr doc = NULL;
482 xmlParserCtxtPtr pctx;
483 static xmlSAXHandler sax_handler = {
484 xmlSAX2InternalSubset, /* internalSubset */
485 xmlSAX2IsStandalone, /* isStandalone */
486 xmlSAX2HasInternalSubset, /* hasInternalSubset */
487 xmlSAX2HasExternalSubset, /* hasExternalSubset */
488 xmlSAX2ResolveEntity, /* resolveEntity */
489 xmlSAX2GetEntity, /* getEntity */
490 xmlSAX2EntityDecl, /* entityDecl */
491 xmlSAX2NotationDecl, /* notationDecl */
492 xmlSAX2AttributeDecl, /* attributeDecl */
493 xmlSAX2ElementDecl, /* elementDecl */
494 xmlSAX2UnparsedEntityDecl, /* unparsedEntityDecl */
495 xmlSAX2SetDocumentLocator, /* setDocumentLocator */
496 xmlSAX2StartDocument, /* startDocument */
497 xmlSAX2EndDocument, /* endDocument */
498 xmlSAX2StartElement, /* startElement */
499 xmlSAX2EndElement, /* endElement */
500 xmlSAX2Reference, /* reference */
501 sax_characters, /* characters */
502 sax_characters, /* ignorableWhitespace */
503 xmlSAX2ProcessingInstruction, /* processingInstruction */
504 xmlSAX2Comment, /* comment */
505 sax_warning, /* warning */
506 sax_error, /* error */
507 sax_error, /* fatalError */
508 xmlSAX2GetParameterEntity, /* getParameterEntity */
509 xmlSAX2CDataBlock, /* cdataBlock */
510 xmlSAX2ExternalSubset, /* externalSubset */
511 0, /* initialized */
512 NULL, /* _private */
513 xmlSAX2StartElementNs, /* startElementNs */
514 xmlSAX2EndElementNs, /* endElementNs */
515 sax_serror /* serror */
518 pctx = xmlCreateMemoryParserCtxt(ptr, len);
519 if (!pctx)
521 ERR("Failed to create parser context\n");
522 return NULL;
525 if (pctx->sax) xmlFree(pctx->sax);
526 pctx->sax = &sax_handler;
527 pctx->_private = This;
528 pctx->recovery = 0;
530 if (encoding != XML_CHAR_ENCODING_NONE)
531 xmlSwitchEncoding(pctx, encoding);
533 xmlParseDocument(pctx);
535 if (pctx->wellFormed)
537 doc = pctx->myDoc;
539 else
541 xmlFreeDoc(pctx->myDoc);
542 pctx->myDoc = NULL;
544 pctx->sax = NULL;
545 xmlFreeParserCtxt(pctx);
547 /* TODO: put this in one of the SAX callbacks */
548 /* create first child as a <?xml...?> */
549 if (doc && doc->standalone != -1)
551 xmlNodePtr node;
552 char buff[30];
553 xmlChar *xmlbuff = (xmlChar*)buff;
555 node = xmlNewDocPI( doc, (xmlChar*)"xml", NULL );
557 /* version attribute can't be omitted */
558 sprintf(buff, "version=\"%s\"", doc->version ? (char*)doc->version : "1.0");
559 xmlNodeAddContent( node, xmlbuff );
561 if (doc->encoding)
563 sprintf(buff, " encoding=\"%s\"", doc->encoding);
564 xmlNodeAddContent( node, xmlbuff );
567 if (doc->standalone != -2)
569 sprintf(buff, " standalone=\"%s\"", doc->standalone == 0 ? "no" : "yes");
570 xmlNodeAddContent( node, xmlbuff );
573 xmldoc_link_xmldecl( doc, node );
576 return doc;
579 void xmldoc_init(xmlDocPtr doc, MSXML_VERSION version)
581 doc->_private = create_priv();
582 priv_from_xmlDocPtr(doc)->properties = create_properties(version);
585 LONG xmldoc_add_refs(xmlDocPtr doc, LONG refs)
587 LONG ref = InterlockedExchangeAdd(&priv_from_xmlDocPtr(doc)->refs, refs) + refs;
588 TRACE("(%p)->(%d)\n", doc, ref);
589 return ref;
592 LONG xmldoc_add_ref(xmlDocPtr doc)
594 return xmldoc_add_refs(doc, 1);
597 LONG xmldoc_release_refs(xmlDocPtr doc, LONG refs)
599 xmldoc_priv *priv = priv_from_xmlDocPtr(doc);
600 LONG ref = InterlockedExchangeAdd(&priv->refs, -refs) - refs;
601 TRACE("(%p)->(%d)\n", doc, ref);
603 if (ref < 0)
604 WARN("negative refcount, expect troubles\n");
606 if (ref == 0)
608 orphan_entry *orphan, *orphan2;
609 TRACE("freeing docptr %p\n", doc);
611 LIST_FOR_EACH_ENTRY_SAFE( orphan, orphan2, &priv->orphans, orphan_entry, entry )
613 xmlFreeNode( orphan->node );
614 heap_free( orphan );
616 free_properties(priv->properties);
617 heap_free(doc->_private);
619 xmlFreeDoc(doc);
622 return ref;
625 LONG xmldoc_release(xmlDocPtr doc)
627 return xmldoc_release_refs(doc, 1);
630 HRESULT xmldoc_add_orphan(xmlDocPtr doc, xmlNodePtr node)
632 xmldoc_priv *priv = priv_from_xmlDocPtr(doc);
633 orphan_entry *entry;
635 entry = heap_alloc( sizeof (*entry) );
636 if(!entry)
637 return E_OUTOFMEMORY;
639 entry->node = node;
640 list_add_head( &priv->orphans, &entry->entry );
641 return S_OK;
644 HRESULT xmldoc_remove_orphan(xmlDocPtr doc, xmlNodePtr node)
646 xmldoc_priv *priv = priv_from_xmlDocPtr(doc);
647 orphan_entry *entry, *entry2;
649 LIST_FOR_EACH_ENTRY_SAFE( entry, entry2, &priv->orphans, orphan_entry, entry )
651 if( entry->node == node )
653 list_remove( &entry->entry );
654 heap_free( entry );
655 return S_OK;
659 return S_FALSE;
662 static inline xmlDocPtr get_doc( domdoc *This )
664 return This->node.node->doc;
667 static HRESULT attach_xmldoc(domdoc *This, xmlDocPtr xml )
669 release_namespaces(This);
671 if(This->node.node)
673 priv_from_xmlDocPtr(get_doc(This))->properties = NULL;
674 if (xmldoc_release(get_doc(This)) != 0)
675 priv_from_xmlDocPtr(get_doc(This))->properties =
676 copy_properties(This->properties);
679 This->node.node = (xmlNodePtr) xml;
681 if(This->node.node)
683 xmldoc_add_ref(get_doc(This));
684 priv_from_xmlDocPtr(get_doc(This))->properties = This->properties;
687 return S_OK;
690 static inline domdoc *impl_from_IXMLDOMDocument3( IXMLDOMDocument3 *iface )
692 return CONTAINING_RECORD(iface, domdoc, IXMLDOMDocument3_iface);
695 static inline domdoc *impl_from_IPersistStreamInit(IPersistStreamInit *iface)
697 return CONTAINING_RECORD(iface, domdoc, IPersistStreamInit_iface);
700 static inline domdoc *impl_from_IObjectWithSite(IObjectWithSite *iface)
702 return CONTAINING_RECORD(iface, domdoc, IObjectWithSite_iface);
705 static inline domdoc *impl_from_IObjectSafety(IObjectSafety *iface)
707 return CONTAINING_RECORD(iface, domdoc, IObjectSafety_iface);
710 static inline domdoc *impl_from_IConnectionPointContainer(IConnectionPointContainer *iface)
712 return CONTAINING_RECORD(iface, domdoc, IConnectionPointContainer_iface);
715 /************************************************************************
716 * domdoc implementation of IPersistStream.
718 static HRESULT WINAPI PersistStreamInit_QueryInterface(
719 IPersistStreamInit *iface, REFIID riid, void **ppvObj)
721 domdoc* This = impl_from_IPersistStreamInit(iface);
722 return IXMLDOMDocument3_QueryInterface(&This->IXMLDOMDocument3_iface, riid, ppvObj);
725 static ULONG WINAPI PersistStreamInit_AddRef(
726 IPersistStreamInit *iface)
728 domdoc* This = impl_from_IPersistStreamInit(iface);
729 return IXMLDOMDocument3_AddRef(&This->IXMLDOMDocument3_iface);
732 static ULONG WINAPI PersistStreamInit_Release(
733 IPersistStreamInit *iface)
735 domdoc* This = impl_from_IPersistStreamInit(iface);
736 return IXMLDOMDocument3_Release(&This->IXMLDOMDocument3_iface);
739 static HRESULT WINAPI PersistStreamInit_GetClassID(
740 IPersistStreamInit *iface, CLSID *classid)
742 domdoc* This = impl_from_IPersistStreamInit(iface);
743 TRACE("(%p)->(%p)\n", This, classid);
745 if(!classid)
746 return E_POINTER;
748 *classid = *DOMDocument_version(This->properties->version);
750 return S_OK;
753 static HRESULT WINAPI PersistStreamInit_IsDirty(
754 IPersistStreamInit *iface)
756 domdoc *This = impl_from_IPersistStreamInit(iface);
757 FIXME("(%p): stub!\n", This);
758 return S_FALSE;
761 static HRESULT domdoc_load_from_stream(domdoc *doc, ISequentialStream *stream)
763 DWORD read, written, len;
764 xmlDocPtr xmldoc = NULL;
765 IStream *hstream;
766 HGLOBAL hglobal;
767 BYTE buf[4096];
768 HRESULT hr;
769 char *ptr;
771 hstream = NULL;
772 hr = CreateStreamOnHGlobal(NULL, TRUE, &hstream);
773 if (FAILED(hr))
774 return hr;
778 ISequentialStream_Read(stream, buf, sizeof(buf), &read);
779 hr = IStream_Write(hstream, buf, read, &written);
780 } while(SUCCEEDED(hr) && written != 0 && read != 0);
782 if (FAILED(hr))
784 ERR("failed to copy stream 0x%08x\n", hr);
785 IStream_Release(hstream);
786 return hr;
789 hr = GetHGlobalFromStream(hstream, &hglobal);
790 if (FAILED(hr))
791 return hr;
793 len = GlobalSize(hglobal);
794 ptr = GlobalLock(hglobal);
795 if (len)
796 xmldoc = doparse(doc, ptr, len, XML_CHAR_ENCODING_NONE);
797 GlobalUnlock(hglobal);
799 if (!xmldoc)
801 ERR("Failed to parse xml\n");
802 return E_FAIL;
805 xmldoc->_private = create_priv();
807 return attach_xmldoc(doc, xmldoc);
810 static HRESULT WINAPI PersistStreamInit_Load(IPersistStreamInit *iface, IStream *stream)
812 domdoc *This = impl_from_IPersistStreamInit(iface);
814 TRACE("(%p)->(%p)\n", This, stream);
816 if (!stream)
817 return E_INVALIDARG;
819 return domdoc_load_from_stream(This, (ISequentialStream*)stream);
822 static HRESULT WINAPI PersistStreamInit_Save(
823 IPersistStreamInit *iface, IStream *stream, BOOL clr_dirty)
825 domdoc *This = impl_from_IPersistStreamInit(iface);
826 BSTR xmlString;
827 HRESULT hr;
829 TRACE("(%p)->(%p %d)\n", This, stream, clr_dirty);
831 hr = IXMLDOMDocument3_get_xml(&This->IXMLDOMDocument3_iface, &xmlString);
832 if(hr == S_OK)
834 DWORD len = SysStringLen(xmlString) * sizeof(WCHAR);
836 hr = IStream_Write( stream, xmlString, len, NULL );
837 SysFreeString(xmlString);
840 TRACE("ret 0x%08x\n", hr);
842 return hr;
845 static HRESULT WINAPI PersistStreamInit_GetSizeMax(
846 IPersistStreamInit *iface, ULARGE_INTEGER *pcbSize)
848 domdoc *This = impl_from_IPersistStreamInit(iface);
849 TRACE("(%p)->(%p)\n", This, pcbSize);
850 return E_NOTIMPL;
853 static HRESULT WINAPI PersistStreamInit_InitNew(
854 IPersistStreamInit *iface)
856 domdoc *This = impl_from_IPersistStreamInit(iface);
857 TRACE("(%p)\n", This);
858 return S_OK;
861 static const IPersistStreamInitVtbl xmldoc_IPersistStreamInit_VTable =
863 PersistStreamInit_QueryInterface,
864 PersistStreamInit_AddRef,
865 PersistStreamInit_Release,
866 PersistStreamInit_GetClassID,
867 PersistStreamInit_IsDirty,
868 PersistStreamInit_Load,
869 PersistStreamInit_Save,
870 PersistStreamInit_GetSizeMax,
871 PersistStreamInit_InitNew
874 /* IXMLDOMDocument3 interface */
876 static const tid_t domdoc_se_tids[] = {
877 IXMLDOMNode_tid,
878 IXMLDOMDocument_tid,
879 IXMLDOMDocument2_tid,
880 IXMLDOMDocument3_tid,
881 NULL_tid
884 static HRESULT WINAPI domdoc_QueryInterface( IXMLDOMDocument3 *iface, REFIID riid, void** ppvObject )
886 domdoc *This = impl_from_IXMLDOMDocument3( iface );
888 TRACE("(%p)->(%s %p)\n", This, debugstr_guid( riid ), ppvObject );
890 *ppvObject = NULL;
892 if ( IsEqualGUID( riid, &IID_IUnknown ) ||
893 IsEqualGUID( riid, &IID_IDispatch ) ||
894 IsEqualGUID( riid, &IID_IXMLDOMNode ) ||
895 IsEqualGUID( riid, &IID_IXMLDOMDocument ) ||
896 IsEqualGUID( riid, &IID_IXMLDOMDocument2 )||
897 IsEqualGUID( riid, &IID_IXMLDOMDocument3 ))
899 *ppvObject = iface;
901 else if (IsEqualGUID(&IID_IPersistStream, riid) ||
902 IsEqualGUID(&IID_IPersistStreamInit, riid))
904 *ppvObject = &This->IPersistStreamInit_iface;
906 else if (IsEqualGUID(&IID_IObjectWithSite, riid))
908 *ppvObject = &This->IObjectWithSite_iface;
910 else if (IsEqualGUID(&IID_IObjectSafety, riid))
912 *ppvObject = &This->IObjectSafety_iface;
914 else if( IsEqualGUID( riid, &IID_ISupportErrorInfo ))
916 return node_create_supporterrorinfo(domdoc_se_tids, ppvObject);
918 else if(node_query_interface(&This->node, riid, ppvObject))
920 return *ppvObject ? S_OK : E_NOINTERFACE;
922 else if (IsEqualGUID( riid, &IID_IConnectionPointContainer ))
924 *ppvObject = &This->IConnectionPointContainer_iface;
926 else
928 TRACE("interface %s not implemented\n", debugstr_guid(riid));
929 return E_NOINTERFACE;
932 IUnknown_AddRef((IUnknown*)*ppvObject);
934 return S_OK;
937 static ULONG WINAPI domdoc_AddRef( IXMLDOMDocument3 *iface )
939 domdoc *This = impl_from_IXMLDOMDocument3( iface );
940 ULONG ref = InterlockedIncrement( &This->ref );
941 TRACE("(%p)->(%d)\n", This, ref );
942 return ref;
945 static ULONG WINAPI domdoc_Release( IXMLDOMDocument3 *iface )
947 domdoc *This = impl_from_IXMLDOMDocument3( iface );
948 LONG ref = InterlockedDecrement( &This->ref );
950 TRACE("(%p)->(%d)\n", This, ref );
952 if ( ref == 0 )
954 int eid;
956 if (This->site)
957 IUnknown_Release( This->site );
958 destroy_xmlnode(&This->node);
960 for (eid = 0; eid < EVENTID_LAST; eid++)
961 if (This->events[eid]) IDispatch_Release(This->events[eid]);
963 release_namespaces(This);
964 heap_free(This);
967 return ref;
970 static HRESULT WINAPI domdoc_GetTypeInfoCount( IXMLDOMDocument3 *iface, UINT* pctinfo )
972 domdoc *This = impl_from_IXMLDOMDocument3( iface );
973 return IDispatchEx_GetTypeInfoCount(&This->node.dispex.IDispatchEx_iface, pctinfo);
976 static HRESULT WINAPI domdoc_GetTypeInfo(
977 IXMLDOMDocument3 *iface,
978 UINT iTInfo, LCID lcid, ITypeInfo** ppTInfo )
980 domdoc *This = impl_from_IXMLDOMDocument3( iface );
981 return IDispatchEx_GetTypeInfo(&This->node.dispex.IDispatchEx_iface, iTInfo, lcid, ppTInfo);
984 static HRESULT WINAPI domdoc_GetIDsOfNames(
985 IXMLDOMDocument3 *iface,
986 REFIID riid,
987 LPOLESTR* rgszNames,
988 UINT cNames,
989 LCID lcid,
990 DISPID* rgDispId)
992 domdoc *This = impl_from_IXMLDOMDocument3( iface );
993 return IDispatchEx_GetIDsOfNames(&This->node.dispex.IDispatchEx_iface,
994 riid, rgszNames, cNames, lcid, rgDispId);
997 static HRESULT WINAPI domdoc_Invoke(
998 IXMLDOMDocument3 *iface,
999 DISPID dispIdMember,
1000 REFIID riid,
1001 LCID lcid,
1002 WORD wFlags,
1003 DISPPARAMS* pDispParams,
1004 VARIANT* pVarResult,
1005 EXCEPINFO* pExcepInfo,
1006 UINT* puArgErr)
1008 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1009 return IDispatchEx_Invoke(&This->node.dispex.IDispatchEx_iface,
1010 dispIdMember, riid, lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
1013 static HRESULT WINAPI domdoc_get_nodeName(
1014 IXMLDOMDocument3 *iface,
1015 BSTR* name )
1017 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1019 static const WCHAR documentW[] = {'#','d','o','c','u','m','e','n','t',0};
1021 TRACE("(%p)->(%p)\n", This, name);
1023 return return_bstr(documentW, name);
1027 static HRESULT WINAPI domdoc_get_nodeValue(
1028 IXMLDOMDocument3 *iface,
1029 VARIANT* value )
1031 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1033 TRACE("(%p)->(%p)\n", This, value);
1035 if(!value)
1036 return E_INVALIDARG;
1038 V_VT(value) = VT_NULL;
1039 V_BSTR(value) = NULL; /* tests show that we should do this */
1040 return S_FALSE;
1044 static HRESULT WINAPI domdoc_put_nodeValue(
1045 IXMLDOMDocument3 *iface,
1046 VARIANT value)
1048 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1049 TRACE("(%p)->(%s)\n", This, debugstr_variant(&value));
1050 return E_FAIL;
1054 static HRESULT WINAPI domdoc_get_nodeType(
1055 IXMLDOMDocument3 *iface,
1056 DOMNodeType* type )
1058 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1060 TRACE("(%p)->(%p)\n", This, type);
1062 *type = NODE_DOCUMENT;
1063 return S_OK;
1067 static HRESULT WINAPI domdoc_get_parentNode(
1068 IXMLDOMDocument3 *iface,
1069 IXMLDOMNode** parent )
1071 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1073 TRACE("(%p)->(%p)\n", This, parent);
1075 return node_get_parent(&This->node, parent);
1079 static HRESULT WINAPI domdoc_get_childNodes(
1080 IXMLDOMDocument3 *iface,
1081 IXMLDOMNodeList** childList )
1083 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1085 TRACE("(%p)->(%p)\n", This, childList);
1087 return node_get_child_nodes(&This->node, childList);
1091 static HRESULT WINAPI domdoc_get_firstChild(
1092 IXMLDOMDocument3 *iface,
1093 IXMLDOMNode** firstChild )
1095 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1097 TRACE("(%p)->(%p)\n", This, firstChild);
1099 return node_get_first_child(&This->node, firstChild);
1103 static HRESULT WINAPI domdoc_get_lastChild(
1104 IXMLDOMDocument3 *iface,
1105 IXMLDOMNode** lastChild )
1107 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1109 TRACE("(%p)->(%p)\n", This, lastChild);
1111 return node_get_last_child(&This->node, lastChild);
1115 static HRESULT WINAPI domdoc_get_previousSibling(
1116 IXMLDOMDocument3 *iface,
1117 IXMLDOMNode** previousSibling )
1119 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1121 TRACE("(%p)->(%p)\n", This, previousSibling);
1123 return return_null_node(previousSibling);
1127 static HRESULT WINAPI domdoc_get_nextSibling(
1128 IXMLDOMDocument3 *iface,
1129 IXMLDOMNode** nextSibling )
1131 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1133 TRACE("(%p)->(%p)\n", This, nextSibling);
1135 return return_null_node(nextSibling);
1139 static HRESULT WINAPI domdoc_get_attributes(
1140 IXMLDOMDocument3 *iface,
1141 IXMLDOMNamedNodeMap** attributeMap )
1143 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1145 TRACE("(%p)->(%p)\n", This, attributeMap);
1147 return return_null_ptr((void**)attributeMap);
1151 static HRESULT WINAPI domdoc_insertBefore(
1152 IXMLDOMDocument3 *iface,
1153 IXMLDOMNode* newChild,
1154 VARIANT refChild,
1155 IXMLDOMNode** outNewChild )
1157 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1158 DOMNodeType type;
1159 HRESULT hr;
1161 TRACE("(%p)->(%p %s %p)\n", This, newChild, debugstr_variant(&refChild), outNewChild);
1163 hr = IXMLDOMNode_get_nodeType(newChild, &type);
1164 if (hr != S_OK) return hr;
1166 TRACE("new node type %d\n", type);
1167 switch (type)
1169 case NODE_ATTRIBUTE:
1170 case NODE_DOCUMENT:
1171 case NODE_CDATA_SECTION:
1172 if (outNewChild) *outNewChild = NULL;
1173 return E_FAIL;
1174 default:
1175 return node_insert_before(&This->node, newChild, &refChild, outNewChild);
1179 static HRESULT WINAPI domdoc_replaceChild(
1180 IXMLDOMDocument3 *iface,
1181 IXMLDOMNode* newChild,
1182 IXMLDOMNode* oldChild,
1183 IXMLDOMNode** outOldChild)
1185 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1187 TRACE("(%p)->(%p %p %p)\n", This, newChild, oldChild, outOldChild);
1189 return node_replace_child(&This->node, newChild, oldChild, outOldChild);
1193 static HRESULT WINAPI domdoc_removeChild(
1194 IXMLDOMDocument3 *iface,
1195 IXMLDOMNode *child,
1196 IXMLDOMNode **oldChild)
1198 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1199 TRACE("(%p)->(%p %p)\n", This, child, oldChild);
1200 return node_remove_child(&This->node, child, oldChild);
1204 static HRESULT WINAPI domdoc_appendChild(
1205 IXMLDOMDocument3 *iface,
1206 IXMLDOMNode *child,
1207 IXMLDOMNode **outChild)
1209 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1210 TRACE("(%p)->(%p %p)\n", This, child, outChild);
1211 return node_append_child(&This->node, child, outChild);
1215 static HRESULT WINAPI domdoc_hasChildNodes(
1216 IXMLDOMDocument3 *iface,
1217 VARIANT_BOOL *ret)
1219 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1220 TRACE("(%p)->(%p)\n", This, ret);
1221 return node_has_childnodes(&This->node, ret);
1225 static HRESULT WINAPI domdoc_get_ownerDocument(
1226 IXMLDOMDocument3 *iface,
1227 IXMLDOMDocument **doc)
1229 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1230 TRACE("(%p)->(%p)\n", This, doc);
1231 return node_get_owner_doc(&This->node, doc);
1235 static HRESULT WINAPI domdoc_cloneNode(
1236 IXMLDOMDocument3 *iface,
1237 VARIANT_BOOL deep,
1238 IXMLDOMNode** outNode)
1240 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1241 TRACE("(%p)->(%d %p)\n", This, deep, outNode);
1242 return node_clone( &This->node, deep, outNode );
1246 static HRESULT WINAPI domdoc_get_nodeTypeString(
1247 IXMLDOMDocument3 *iface,
1248 BSTR *p)
1250 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1251 static const WCHAR documentW[] = {'d','o','c','u','m','e','n','t',0};
1253 TRACE("(%p)->(%p)\n", This, p);
1255 return return_bstr(documentW, p);
1259 static HRESULT WINAPI domdoc_get_text(
1260 IXMLDOMDocument3 *iface,
1261 BSTR *p)
1263 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1264 TRACE("(%p)->(%p)\n", This, p);
1265 return node_get_text(&This->node, p);
1269 static HRESULT WINAPI domdoc_put_text(
1270 IXMLDOMDocument3 *iface,
1271 BSTR text )
1273 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1274 TRACE("(%p)->(%s)\n", This, debugstr_w(text));
1275 return E_FAIL;
1279 static HRESULT WINAPI domdoc_get_specified(
1280 IXMLDOMDocument3 *iface,
1281 VARIANT_BOOL* isSpecified )
1283 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1284 FIXME("(%p)->(%p) stub!\n", This, isSpecified);
1285 *isSpecified = VARIANT_TRUE;
1286 return S_OK;
1290 static HRESULT WINAPI domdoc_get_definition(
1291 IXMLDOMDocument3 *iface,
1292 IXMLDOMNode** definitionNode )
1294 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1295 FIXME("(%p)->(%p)\n", This, definitionNode);
1296 return E_NOTIMPL;
1300 static HRESULT WINAPI domdoc_get_nodeTypedValue(
1301 IXMLDOMDocument3 *iface,
1302 VARIANT* v )
1304 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1305 TRACE("(%p)->(%p)\n", This, v);
1306 return return_null_var(v);
1309 static HRESULT WINAPI domdoc_put_nodeTypedValue(
1310 IXMLDOMDocument3 *iface,
1311 VARIANT typedValue )
1313 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1314 FIXME("(%p)->(%s)\n", This, debugstr_variant(&typedValue));
1315 return E_NOTIMPL;
1319 static HRESULT WINAPI domdoc_get_dataType(
1320 IXMLDOMDocument3 *iface,
1321 VARIANT* typename )
1323 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1324 TRACE("(%p)->(%p)\n", This, typename);
1325 return return_null_var( typename );
1329 static HRESULT WINAPI domdoc_put_dataType(
1330 IXMLDOMDocument3 *iface,
1331 BSTR dataTypeName )
1333 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1335 FIXME("(%p)->(%s)\n", This, debugstr_w(dataTypeName));
1337 if(!dataTypeName)
1338 return E_INVALIDARG;
1340 return E_FAIL;
1343 static int XMLCALL domdoc_get_xml_writecallback(void *ctx, const char *data, int len)
1345 return xmlBufferAdd((xmlBufferPtr)ctx, (xmlChar*)data, len) == 0 ? len : 0;
1348 static HRESULT WINAPI domdoc_get_xml(
1349 IXMLDOMDocument3 *iface,
1350 BSTR* p)
1352 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1353 xmlSaveCtxtPtr ctxt;
1354 xmlBufferPtr buf;
1355 int options;
1356 long ret;
1358 TRACE("(%p)->(%p)\n", This, p);
1360 if(!p)
1361 return E_INVALIDARG;
1363 *p = NULL;
1365 buf = xmlBufferCreate();
1366 if(!buf)
1367 return E_OUTOFMEMORY;
1369 options = XML_SAVE_FORMAT | XML_SAVE_NO_DECL;
1370 ctxt = xmlSaveToIO(domdoc_get_xml_writecallback, NULL, buf, "UTF-8", options);
1372 if(!ctxt)
1374 xmlBufferFree(buf);
1375 return E_OUTOFMEMORY;
1378 ret = xmlSaveDoc(ctxt, get_doc(This));
1379 /* flushes on close */
1380 xmlSaveClose(ctxt);
1382 TRACE("%ld, len=%d\n", ret, xmlBufferLength(buf));
1383 if(ret != -1 && xmlBufferLength(buf) > 0)
1385 BSTR content;
1387 content = bstr_from_xmlChar(xmlBufferContent(buf));
1388 content = EnsureCorrectEOL(content);
1390 *p = content;
1392 else
1394 *p = SysAllocStringLen(NULL, 0);
1397 xmlBufferFree(buf);
1399 return *p ? S_OK : E_OUTOFMEMORY;
1403 static HRESULT WINAPI domdoc_transformNode(
1404 IXMLDOMDocument3 *iface,
1405 IXMLDOMNode *node,
1406 BSTR *p)
1408 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1409 TRACE("(%p)->(%p %p)\n", This, node, p);
1410 return node_transform_node(&This->node, node, p);
1414 static HRESULT WINAPI domdoc_selectNodes(
1415 IXMLDOMDocument3 *iface,
1416 BSTR p,
1417 IXMLDOMNodeList **outList)
1419 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1420 TRACE("(%p)->(%s %p)\n", This, debugstr_w(p), outList);
1421 return node_select_nodes(&This->node, p, outList);
1425 static HRESULT WINAPI domdoc_selectSingleNode(
1426 IXMLDOMDocument3 *iface,
1427 BSTR p,
1428 IXMLDOMNode **outNode)
1430 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1431 TRACE("(%p)->(%s %p)\n", This, debugstr_w(p), outNode);
1432 return node_select_singlenode(&This->node, p, outNode);
1436 static HRESULT WINAPI domdoc_get_parsed(
1437 IXMLDOMDocument3 *iface,
1438 VARIANT_BOOL* isParsed )
1440 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1441 FIXME("(%p)->(%p) stub!\n", This, isParsed);
1442 *isParsed = VARIANT_TRUE;
1443 return S_OK;
1446 static HRESULT WINAPI domdoc_get_namespaceURI(
1447 IXMLDOMDocument3 *iface,
1448 BSTR* namespaceURI )
1450 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1451 TRACE("(%p)->(%p)\n", This, namespaceURI);
1452 return return_null_bstr( namespaceURI );
1455 static HRESULT WINAPI domdoc_get_prefix(
1456 IXMLDOMDocument3 *iface,
1457 BSTR* prefix )
1459 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1460 TRACE("(%p)->(%p)\n", This, prefix);
1461 return return_null_bstr( prefix );
1465 static HRESULT WINAPI domdoc_get_baseName(
1466 IXMLDOMDocument3 *iface,
1467 BSTR* name )
1469 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1470 TRACE("(%p)->(%p)\n", This, name);
1471 return return_null_bstr( name );
1475 static HRESULT WINAPI domdoc_transformNodeToObject(
1476 IXMLDOMDocument3 *iface,
1477 IXMLDOMNode* stylesheet,
1478 VARIANT outputObject)
1480 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1481 FIXME("(%p)->(%p %s)\n", This, stylesheet, debugstr_variant(&outputObject));
1482 return E_NOTIMPL;
1486 static HRESULT WINAPI domdoc_get_doctype(
1487 IXMLDOMDocument3 *iface,
1488 IXMLDOMDocumentType** doctype )
1490 domdoc *This = impl_from_IXMLDOMDocument3(iface);
1491 IXMLDOMNode *node;
1492 xmlDtdPtr dtd;
1493 HRESULT hr;
1495 TRACE("(%p)->(%p)\n", This, doctype);
1497 if (!doctype) return E_INVALIDARG;
1499 *doctype = NULL;
1501 dtd = xmlGetIntSubset(get_doc(This));
1502 if (!dtd) return S_FALSE;
1504 node = create_node((xmlNodePtr)dtd);
1505 if (!node) return S_FALSE;
1507 hr = IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMDocumentType, (void**)doctype);
1508 IXMLDOMNode_Release(node);
1510 return hr;
1514 static HRESULT WINAPI domdoc_get_implementation(
1515 IXMLDOMDocument3 *iface,
1516 IXMLDOMImplementation** impl )
1518 domdoc *This = impl_from_IXMLDOMDocument3(iface);
1520 TRACE("(%p)->(%p)\n", This, impl);
1522 if(!impl)
1523 return E_INVALIDARG;
1525 *impl = (IXMLDOMImplementation*)create_doc_Implementation();
1527 return S_OK;
1530 static HRESULT WINAPI domdoc_get_documentElement(
1531 IXMLDOMDocument3 *iface,
1532 IXMLDOMElement** DOMElement )
1534 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1535 IXMLDOMNode *element_node;
1536 xmlNodePtr root;
1537 HRESULT hr;
1539 TRACE("(%p)->(%p)\n", This, DOMElement);
1541 if(!DOMElement)
1542 return E_INVALIDARG;
1544 *DOMElement = NULL;
1546 root = xmlDocGetRootElement( get_doc(This) );
1547 if ( !root )
1548 return S_FALSE;
1550 element_node = create_node( root );
1551 if(!element_node) return S_FALSE;
1553 hr = IXMLDOMNode_QueryInterface(element_node, &IID_IXMLDOMElement, (void**)DOMElement);
1554 IXMLDOMNode_Release(element_node);
1556 return hr;
1560 static HRESULT WINAPI domdoc_put_documentElement(
1561 IXMLDOMDocument3 *iface,
1562 IXMLDOMElement* DOMElement )
1564 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1565 IXMLDOMNode *elementNode;
1566 xmlNodePtr oldRoot;
1567 xmlDocPtr old_doc;
1568 xmlnode *xmlNode;
1569 int refcount = 0;
1570 HRESULT hr;
1572 TRACE("(%p)->(%p)\n", This, DOMElement);
1574 hr = IXMLDOMElement_QueryInterface( DOMElement, &IID_IXMLDOMNode, (void**)&elementNode );
1575 if(FAILED(hr))
1576 return hr;
1578 xmlNode = get_node_obj( elementNode );
1579 if(!xmlNode) return E_FAIL;
1581 if(!xmlNode->node->parent)
1582 if(xmldoc_remove_orphan(xmlNode->node->doc, xmlNode->node) != S_OK)
1583 WARN("%p is not an orphan of %p\n", xmlNode->node->doc, xmlNode->node);
1585 old_doc = xmlNode->node->doc;
1586 if (old_doc != get_doc(This))
1587 refcount = xmlnode_get_inst_cnt(xmlNode);
1589 /* old root is still orphaned by its document, update refcount from new root */
1590 if (refcount) xmldoc_add_refs(get_doc(This), refcount);
1591 oldRoot = xmlDocSetRootElement( get_doc(This), xmlNode->node);
1592 if (refcount) xmldoc_release_refs(old_doc, refcount);
1593 IXMLDOMNode_Release( elementNode );
1595 if(oldRoot)
1596 xmldoc_add_orphan(oldRoot->doc, oldRoot);
1598 return S_OK;
1602 static HRESULT WINAPI domdoc_createElement(
1603 IXMLDOMDocument3 *iface,
1604 BSTR tagname,
1605 IXMLDOMElement** element )
1607 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1608 IXMLDOMNode *node;
1609 VARIANT type;
1610 HRESULT hr;
1612 TRACE("(%p)->(%s %p)\n", This, debugstr_w(tagname), element);
1614 if (!element || !tagname) return E_INVALIDARG;
1616 V_VT(&type) = VT_I1;
1617 V_I1(&type) = NODE_ELEMENT;
1619 hr = IXMLDOMDocument3_createNode(iface, type, tagname, NULL, &node);
1620 if (hr == S_OK)
1622 IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMElement, (void**)element);
1623 IXMLDOMNode_Release(node);
1626 return hr;
1630 static HRESULT WINAPI domdoc_createDocumentFragment(
1631 IXMLDOMDocument3 *iface,
1632 IXMLDOMDocumentFragment** frag )
1634 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1635 IXMLDOMNode *node;
1636 VARIANT type;
1637 HRESULT hr;
1639 TRACE("(%p)->(%p)\n", This, frag);
1641 if (!frag) return E_INVALIDARG;
1643 *frag = NULL;
1645 V_VT(&type) = VT_I1;
1646 V_I1(&type) = NODE_DOCUMENT_FRAGMENT;
1648 hr = IXMLDOMDocument3_createNode(iface, type, NULL, NULL, &node);
1649 if (hr == S_OK)
1651 IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMDocumentFragment, (void**)frag);
1652 IXMLDOMNode_Release(node);
1655 return hr;
1659 static HRESULT WINAPI domdoc_createTextNode(
1660 IXMLDOMDocument3 *iface,
1661 BSTR data,
1662 IXMLDOMText** text )
1664 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1665 IXMLDOMNode *node;
1666 VARIANT type;
1667 HRESULT hr;
1669 TRACE("(%p)->(%s %p)\n", This, debugstr_w(data), text);
1671 if (!text) return E_INVALIDARG;
1673 *text = NULL;
1675 V_VT(&type) = VT_I1;
1676 V_I1(&type) = NODE_TEXT;
1678 hr = IXMLDOMDocument3_createNode(iface, type, NULL, NULL, &node);
1679 if (hr == S_OK)
1681 IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMText, (void**)text);
1682 IXMLDOMNode_Release(node);
1683 hr = IXMLDOMText_put_data(*text, data);
1686 return hr;
1690 static HRESULT WINAPI domdoc_createComment(
1691 IXMLDOMDocument3 *iface,
1692 BSTR data,
1693 IXMLDOMComment** comment )
1695 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1696 VARIANT type;
1697 HRESULT hr;
1698 IXMLDOMNode *node;
1700 TRACE("(%p)->(%s %p)\n", This, debugstr_w(data), comment);
1702 if (!comment) return E_INVALIDARG;
1704 *comment = NULL;
1706 V_VT(&type) = VT_I1;
1707 V_I1(&type) = NODE_COMMENT;
1709 hr = IXMLDOMDocument3_createNode(iface, type, NULL, NULL, &node);
1710 if (hr == S_OK)
1712 IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMComment, (void**)comment);
1713 IXMLDOMNode_Release(node);
1714 hr = IXMLDOMComment_put_data(*comment, data);
1717 return hr;
1721 static HRESULT WINAPI domdoc_createCDATASection(
1722 IXMLDOMDocument3 *iface,
1723 BSTR data,
1724 IXMLDOMCDATASection** cdata )
1726 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1727 IXMLDOMNode *node;
1728 VARIANT type;
1729 HRESULT hr;
1731 TRACE("(%p)->(%s %p)\n", This, debugstr_w(data), cdata);
1733 if (!cdata) return E_INVALIDARG;
1735 *cdata = NULL;
1737 V_VT(&type) = VT_I1;
1738 V_I1(&type) = NODE_CDATA_SECTION;
1740 hr = IXMLDOMDocument3_createNode(iface, type, NULL, NULL, &node);
1741 if (hr == S_OK)
1743 IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMCDATASection, (void**)cdata);
1744 IXMLDOMNode_Release(node);
1745 hr = IXMLDOMCDATASection_put_data(*cdata, data);
1748 return hr;
1752 static HRESULT WINAPI domdoc_createProcessingInstruction(
1753 IXMLDOMDocument3 *iface,
1754 BSTR target,
1755 BSTR data,
1756 IXMLDOMProcessingInstruction** pi )
1758 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1759 IXMLDOMNode *node;
1760 VARIANT type;
1761 HRESULT hr;
1763 TRACE("(%p)->(%s %s %p)\n", This, debugstr_w(target), debugstr_w(data), pi);
1765 if (!pi) return E_INVALIDARG;
1767 *pi = NULL;
1769 V_VT(&type) = VT_I1;
1770 V_I1(&type) = NODE_PROCESSING_INSTRUCTION;
1772 hr = IXMLDOMDocument3_createNode(iface, type, target, NULL, &node);
1773 if (hr == S_OK)
1775 xmlnode *node_obj;
1777 /* this is to bypass check in ::put_data() that blocks "<?xml" PIs */
1778 node_obj = get_node_obj(node);
1779 hr = node_set_content(node_obj, data);
1781 IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMProcessingInstruction, (void**)pi);
1782 IXMLDOMNode_Release(node);
1785 return hr;
1789 static HRESULT WINAPI domdoc_createAttribute(
1790 IXMLDOMDocument3 *iface,
1791 BSTR name,
1792 IXMLDOMAttribute** attribute )
1794 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1795 IXMLDOMNode *node;
1796 VARIANT type;
1797 HRESULT hr;
1799 TRACE("(%p)->(%s %p)\n", This, debugstr_w(name), attribute);
1801 if (!attribute || !name) return E_INVALIDARG;
1803 V_VT(&type) = VT_I1;
1804 V_I1(&type) = NODE_ATTRIBUTE;
1806 hr = IXMLDOMDocument3_createNode(iface, type, name, NULL, &node);
1807 if (hr == S_OK)
1809 IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMAttribute, (void**)attribute);
1810 IXMLDOMNode_Release(node);
1813 return hr;
1817 static HRESULT WINAPI domdoc_createEntityReference(
1818 IXMLDOMDocument3 *iface,
1819 BSTR name,
1820 IXMLDOMEntityReference** entityref )
1822 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1823 IXMLDOMNode *node;
1824 VARIANT type;
1825 HRESULT hr;
1827 TRACE("(%p)->(%s %p)\n", This, debugstr_w(name), entityref);
1829 if (!entityref) return E_INVALIDARG;
1831 *entityref = NULL;
1833 V_VT(&type) = VT_I1;
1834 V_I1(&type) = NODE_ENTITY_REFERENCE;
1836 hr = IXMLDOMDocument3_createNode(iface, type, name, NULL, &node);
1837 if (hr == S_OK)
1839 IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMEntityReference, (void**)entityref);
1840 IXMLDOMNode_Release(node);
1843 return hr;
1846 xmlChar* tagName_to_XPath(const BSTR tagName)
1848 xmlChar *query, *tmp;
1849 static const xmlChar everything[] = "/descendant::node()";
1850 static const xmlChar mod_pre[] = "*[local-name()='";
1851 static const xmlChar mod_post[] = "']";
1852 static const xmlChar prefix[] = "descendant::";
1853 const WCHAR *tokBegin, *tokEnd;
1854 int len;
1856 /* Special case - empty tagname - means select all nodes,
1857 except document itself. */
1858 if (!*tagName)
1859 return xmlStrdup(everything);
1861 query = xmlStrdup(prefix);
1863 tokBegin = tagName;
1864 while (tokBegin && *tokBegin)
1866 switch (*tokBegin)
1868 case '/':
1869 query = xmlStrcat(query, BAD_CAST "/");
1870 ++tokBegin;
1871 break;
1872 case '*':
1873 query = xmlStrcat(query, BAD_CAST "*");
1874 ++tokBegin;
1875 break;
1876 default:
1877 query = xmlStrcat(query, mod_pre);
1878 tokEnd = tokBegin;
1879 while (*tokEnd && *tokEnd != '/')
1880 ++tokEnd;
1881 len = WideCharToMultiByte(CP_UTF8, 0, tokBegin, tokEnd-tokBegin, NULL, 0, NULL, NULL);
1882 tmp = xmlMalloc(len);
1883 WideCharToMultiByte(CP_UTF8, 0, tokBegin, tokEnd-tokBegin, (char*)tmp, len, NULL, NULL);
1884 query = xmlStrncat(query, tmp, len);
1885 xmlFree(tmp);
1886 tokBegin = tokEnd;
1887 query = xmlStrcat(query, mod_post);
1891 return query;
1894 static HRESULT WINAPI domdoc_getElementsByTagName(
1895 IXMLDOMDocument3 *iface,
1896 BSTR tagName,
1897 IXMLDOMNodeList** resultList )
1899 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1900 xmlChar *query;
1901 HRESULT hr;
1902 BOOL XPath;
1904 TRACE("(%p)->(%s, %p)\n", This, debugstr_w(tagName), resultList);
1906 if (!tagName || !resultList) return E_INVALIDARG;
1908 XPath = This->properties->XPath;
1909 This->properties->XPath = TRUE;
1910 query = tagName_to_XPath(tagName);
1911 hr = create_selection((xmlNodePtr)get_doc(This), query, resultList);
1912 xmlFree(query);
1913 This->properties->XPath = XPath;
1915 return hr;
1918 static HRESULT get_node_type(VARIANT Type, DOMNodeType * type)
1920 VARIANT tmp;
1921 HRESULT hr;
1923 VariantInit(&tmp);
1924 hr = VariantChangeType(&tmp, &Type, 0, VT_I4);
1925 if(FAILED(hr))
1926 return E_INVALIDARG;
1928 *type = V_I4(&tmp);
1930 return S_OK;
1933 static HRESULT WINAPI domdoc_createNode(
1934 IXMLDOMDocument3 *iface,
1935 VARIANT Type,
1936 BSTR name,
1937 BSTR namespaceURI,
1938 IXMLDOMNode** node )
1940 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1941 DOMNodeType node_type;
1942 xmlNodePtr xmlnode;
1943 xmlChar *xml_name, *href;
1944 HRESULT hr;
1946 TRACE("(%p)->(%s %s %s %p)\n", This, debugstr_variant(&Type), debugstr_w(name), debugstr_w(namespaceURI), node);
1948 if(!node) return E_INVALIDARG;
1950 hr = get_node_type(Type, &node_type);
1951 if(FAILED(hr)) return hr;
1953 TRACE("node_type %d\n", node_type);
1955 /* exit earlier for types that need name */
1956 switch(node_type)
1958 case NODE_ELEMENT:
1959 case NODE_ATTRIBUTE:
1960 case NODE_ENTITY_REFERENCE:
1961 case NODE_PROCESSING_INSTRUCTION:
1962 if (!name || *name == 0) return E_FAIL;
1963 break;
1964 default:
1965 break;
1968 xml_name = xmlchar_from_wchar(name);
1969 /* prevent empty href to be allocated */
1970 href = namespaceURI ? xmlchar_from_wchar(namespaceURI) : NULL;
1972 switch(node_type)
1974 case NODE_ELEMENT:
1976 xmlChar *local, *prefix;
1978 local = xmlSplitQName2(xml_name, &prefix);
1980 xmlnode = xmlNewDocNode(get_doc(This), NULL, local ? local : xml_name, NULL);
1982 /* allow to create default namespace xmlns= */
1983 if (local || (href && *href))
1985 xmlNsPtr ns = xmlNewNs(xmlnode, href, prefix);
1986 xmlSetNs(xmlnode, ns);
1989 xmlFree(local);
1990 xmlFree(prefix);
1992 break;
1994 case NODE_ATTRIBUTE:
1996 xmlChar *local, *prefix;
1998 local = xmlSplitQName2(xml_name, &prefix);
2000 xmlnode = (xmlNodePtr)xmlNewDocProp(get_doc(This), local ? local : xml_name, NULL);
2002 if (local || (href && *href))
2004 /* we need a floating namespace here, it can't be created linked to attribute from
2005 a start */
2006 xmlNsPtr ns = xmlNewNs(NULL, href, prefix);
2007 xmlSetNs(xmlnode, ns);
2010 xmlFree(local);
2011 xmlFree(prefix);
2013 break;
2015 case NODE_TEXT:
2016 xmlnode = (xmlNodePtr)xmlNewDocText(get_doc(This), NULL);
2017 break;
2018 case NODE_CDATA_SECTION:
2019 xmlnode = xmlNewCDataBlock(get_doc(This), NULL, 0);
2020 break;
2021 case NODE_ENTITY_REFERENCE:
2022 xmlnode = xmlNewReference(get_doc(This), xml_name);
2023 break;
2024 case NODE_PROCESSING_INSTRUCTION:
2025 #ifdef HAVE_XMLNEWDOCPI
2026 xmlnode = xmlNewDocPI(get_doc(This), xml_name, NULL);
2027 #else
2028 FIXME("xmlNewDocPI() not supported, use libxml2 2.6.15 or greater\n");
2029 xmlnode = NULL;
2030 #endif
2031 break;
2032 case NODE_COMMENT:
2033 xmlnode = xmlNewDocComment(get_doc(This), NULL);
2034 break;
2035 case NODE_DOCUMENT_FRAGMENT:
2036 xmlnode = xmlNewDocFragment(get_doc(This));
2037 break;
2038 /* unsupported types */
2039 case NODE_DOCUMENT:
2040 case NODE_DOCUMENT_TYPE:
2041 case NODE_ENTITY:
2042 case NODE_NOTATION:
2043 heap_free(xml_name);
2044 return E_INVALIDARG;
2045 default:
2046 FIXME("unhandled node type %d\n", node_type);
2047 xmlnode = NULL;
2048 break;
2051 *node = create_node(xmlnode);
2052 heap_free(xml_name);
2053 heap_free(href);
2055 if(*node)
2057 TRACE("created node (%d, %p, %p)\n", node_type, *node, xmlnode);
2058 xmldoc_add_orphan(xmlnode->doc, xmlnode);
2059 return S_OK;
2062 return E_FAIL;
2065 static HRESULT WINAPI domdoc_nodeFromID(
2066 IXMLDOMDocument3 *iface,
2067 BSTR idString,
2068 IXMLDOMNode** node )
2070 domdoc *This = impl_from_IXMLDOMDocument3(iface);
2071 FIXME("(%p)->(%s %p)\n", This, debugstr_w(idString), node);
2072 return E_NOTIMPL;
2075 static HRESULT domdoc_onDataAvailable(void *obj, char *ptr, DWORD len)
2077 domdoc *This = obj;
2078 xmlDocPtr xmldoc;
2080 xmldoc = doparse(This, ptr, len, XML_CHAR_ENCODING_NONE);
2081 if(xmldoc) {
2082 xmldoc->_private = create_priv();
2083 return attach_xmldoc(This, xmldoc);
2086 return E_FAIL;
2089 static HRESULT domdoc_load_moniker(domdoc *This, IMoniker *mon)
2091 bsc_t *bsc;
2092 HRESULT hr;
2094 hr = bind_url(mon, domdoc_onDataAvailable, This, &bsc);
2095 if(FAILED(hr))
2096 return hr;
2098 return detach_bsc(bsc);
2101 static HRESULT WINAPI domdoc_load(
2102 IXMLDOMDocument3 *iface,
2103 VARIANT source,
2104 VARIANT_BOOL* isSuccessful )
2106 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2107 LPWSTR filename = NULL;
2108 HRESULT hr = S_FALSE;
2109 xmlDocPtr xmldoc;
2111 TRACE("(%p)->(%s)\n", This, debugstr_variant(&source));
2113 if (!isSuccessful)
2114 return E_POINTER;
2115 *isSuccessful = VARIANT_FALSE;
2117 assert( &This->node );
2119 switch( V_VT(&source) )
2121 case VT_BSTR:
2122 filename = V_BSTR(&source);
2123 break;
2124 case VT_BSTR|VT_BYREF:
2125 if (!V_BSTRREF(&source)) return E_INVALIDARG;
2126 filename = *V_BSTRREF(&source);
2127 break;
2128 case VT_ARRAY|VT_UI1:
2130 SAFEARRAY *psa = V_ARRAY(&source);
2131 char *str;
2132 LONG len;
2133 UINT dim = SafeArrayGetDim(psa);
2135 switch (dim)
2137 case 0:
2138 ERR("SAFEARRAY == NULL\n");
2139 hr = This->error = E_INVALIDARG;
2140 break;
2141 case 1:
2142 /* Only takes UTF-8 strings.
2143 * NOT NULL-terminated. */
2144 SafeArrayAccessData(psa, (void**)&str);
2145 SafeArrayGetUBound(psa, 1, &len);
2147 if ((xmldoc = doparse(This, str, ++len, XML_CHAR_ENCODING_UTF8)))
2149 hr = This->error = S_OK;
2150 *isSuccessful = VARIANT_TRUE;
2151 TRACE("parsed document %p\n", xmldoc);
2153 else
2155 This->error = E_FAIL;
2156 TRACE("failed to parse document\n");
2159 SafeArrayUnaccessData(psa);
2161 if(xmldoc)
2163 xmldoc->_private = create_priv();
2164 return attach_xmldoc(This, xmldoc);
2166 break;
2167 default:
2168 FIXME("unhandled SAFEARRAY dim: %d\n", dim);
2169 hr = This->error = E_NOTIMPL;
2172 break;
2173 case VT_UNKNOWN:
2175 ISequentialStream *stream = NULL;
2176 IXMLDOMDocument3 *newdoc = NULL;
2178 if (!V_UNKNOWN(&source)) return E_INVALIDARG;
2180 hr = IUnknown_QueryInterface(V_UNKNOWN(&source), &IID_IXMLDOMDocument3, (void**)&newdoc);
2181 if(hr == S_OK)
2183 if(newdoc)
2185 domdoc *newDoc = impl_from_IXMLDOMDocument3( newdoc );
2187 xmldoc = xmlCopyDoc(get_doc(newDoc), 1);
2188 xmldoc->_private = create_priv();
2189 hr = attach_xmldoc(This, xmldoc);
2191 if(SUCCEEDED(hr))
2192 *isSuccessful = VARIANT_TRUE;
2194 return hr;
2198 hr = IUnknown_QueryInterface(V_UNKNOWN(&source), &IID_IStream, (void**)&stream);
2199 if (FAILED(hr))
2200 hr = IUnknown_QueryInterface(V_UNKNOWN(&source), &IID_ISequentialStream, (void**)&stream);
2202 if (hr == S_OK)
2204 hr = domdoc_load_from_stream(This, stream);
2205 if (hr == S_OK)
2206 *isSuccessful = VARIANT_TRUE;
2207 ISequentialStream_Release(stream);
2208 return hr;
2211 FIXME("unsupported IUnknown type (0x%08x) (%p)\n", hr, V_UNKNOWN(&source)->lpVtbl);
2212 break;
2214 default:
2215 FIXME("VT type not supported (%d)\n", V_VT(&source));
2218 if ( filename )
2220 IMoniker *mon;
2222 CoTaskMemFree(This->properties->url);
2223 This->properties->url = NULL;
2225 hr = create_moniker_from_url( filename, &mon);
2226 if ( SUCCEEDED(hr) )
2228 hr = domdoc_load_moniker( This, mon );
2229 if (hr == S_OK)
2230 IMoniker_GetDisplayName(mon, NULL, NULL, &This->properties->url);
2231 IMoniker_Release(mon);
2234 if ( FAILED(hr) )
2235 This->error = E_FAIL;
2236 else
2238 hr = This->error = S_OK;
2239 *isSuccessful = VARIANT_TRUE;
2243 if(!filename || FAILED(hr)) {
2244 xmldoc = xmlNewDoc(NULL);
2245 xmldoc->_private = create_priv();
2246 hr = attach_xmldoc(This, xmldoc);
2247 if(SUCCEEDED(hr))
2248 hr = S_FALSE;
2251 TRACE("ret (%d)\n", hr);
2253 return hr;
2257 static HRESULT WINAPI domdoc_get_readyState(
2258 IXMLDOMDocument3 *iface,
2259 LONG *value )
2261 domdoc *This = impl_from_IXMLDOMDocument3(iface);
2262 FIXME("stub! (%p)->(%p)\n", This, value);
2264 if (!value)
2265 return E_INVALIDARG;
2267 *value = READYSTATE_COMPLETE;
2268 return S_OK;
2272 static HRESULT WINAPI domdoc_get_parseError(
2273 IXMLDOMDocument3 *iface,
2274 IXMLDOMParseError** errorObj )
2276 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2277 static const WCHAR err[] = {'e','r','r','o','r',0};
2278 BSTR error_string = NULL;
2280 FIXME("(%p)->(%p): creating a dummy parseError\n", iface, errorObj);
2282 if(This->error)
2283 error_string = SysAllocString(err);
2285 *errorObj = create_parseError(This->error, NULL, error_string, NULL, 0, 0, 0);
2286 if(!*errorObj) return E_OUTOFMEMORY;
2287 return S_OK;
2291 static HRESULT WINAPI domdoc_get_url(
2292 IXMLDOMDocument3 *iface,
2293 BSTR* url )
2295 domdoc *This = impl_from_IXMLDOMDocument3(iface);
2297 TRACE("(%p)->(%p)\n", This, url);
2299 if (!url)
2300 return E_INVALIDARG;
2302 if (This->properties->url)
2304 *url = SysAllocString(This->properties->url);
2305 if (!*url)
2306 return E_OUTOFMEMORY;
2308 return S_OK;
2310 else
2311 return return_null_bstr(url);
2315 static HRESULT WINAPI domdoc_get_async(
2316 IXMLDOMDocument3 *iface,
2317 VARIANT_BOOL* isAsync )
2319 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2321 TRACE("(%p)->(%p: %d)\n", This, isAsync, This->async);
2322 *isAsync = This->async;
2323 return S_OK;
2327 static HRESULT WINAPI domdoc_put_async(
2328 IXMLDOMDocument3 *iface,
2329 VARIANT_BOOL isAsync )
2331 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2333 TRACE("(%p)->(%d)\n", This, isAsync);
2334 This->async = isAsync;
2335 return S_OK;
2339 static HRESULT WINAPI domdoc_abort(
2340 IXMLDOMDocument3 *iface )
2342 domdoc *This = impl_from_IXMLDOMDocument3(iface);
2343 FIXME("%p\n", This);
2344 return E_NOTIMPL;
2347 /* don't rely on data to be in BSTR format, treat it as WCHAR string */
2348 static HRESULT WINAPI domdoc_loadXML(
2349 IXMLDOMDocument3 *iface,
2350 BSTR data,
2351 VARIANT_BOOL* isSuccessful )
2353 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2354 xmlDocPtr xmldoc = NULL;
2355 HRESULT hr = S_FALSE, hr2;
2357 TRACE("(%p)->(%s %p)\n", This, debugstr_w(data), isSuccessful );
2359 assert ( &This->node );
2361 if ( isSuccessful )
2363 *isSuccessful = VARIANT_FALSE;
2365 if (data)
2367 WCHAR *ptr = data;
2369 /* skip leading spaces if needed */
2370 if (This->properties->version == MSXML_DEFAULT || This->properties->version == MSXML26)
2371 while (*ptr && isspaceW(*ptr)) ptr++;
2373 xmldoc = doparse(This, (char*)ptr, strlenW(ptr)*sizeof(WCHAR), XML_CHAR_ENCODING_UTF16LE);
2374 if ( !xmldoc )
2376 This->error = E_FAIL;
2377 TRACE("failed to parse document\n");
2379 else
2381 hr = This->error = S_OK;
2382 *isSuccessful = VARIANT_TRUE;
2383 TRACE("parsed document %p\n", xmldoc);
2388 if(!xmldoc)
2389 xmldoc = xmlNewDoc(NULL);
2390 xmldoc->_private = create_priv();
2391 hr2 = attach_xmldoc(This, xmldoc);
2392 if( FAILED(hr2) )
2393 hr = hr2;
2395 return hr;
2398 static int XMLCALL domdoc_save_writecallback(void *ctx, const char *buffer, int len)
2400 DWORD written = -1;
2402 if(!WriteFile(ctx, buffer, len, &written, NULL))
2404 WARN("write error\n");
2405 return -1;
2407 else
2408 return written;
2411 static int XMLCALL domdoc_save_closecallback(void *ctx)
2413 return CloseHandle(ctx) ? 0 : -1;
2416 static int XMLCALL domdoc_stream_save_writecallback(void *ctx, const char *buffer, int len)
2418 ULONG written = 0;
2419 HRESULT hr;
2421 hr = IStream_Write((IStream*)ctx, buffer, len, &written);
2422 TRACE("0x%08x %p %d %u\n", hr, buffer, len, written);
2423 if (hr != S_OK)
2425 WARN("stream write error: 0x%08x\n", hr);
2426 return -1;
2428 else
2429 return len;
2432 static int XMLCALL domdoc_stream_save_closecallback(void *ctx)
2434 IStream_Release((IStream*)ctx);
2435 return 0;
2438 static HRESULT WINAPI domdoc_save(
2439 IXMLDOMDocument3 *iface,
2440 VARIANT destination )
2442 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2443 xmlSaveCtxtPtr ctx = NULL;
2444 xmlNodePtr xmldecl;
2445 HRESULT ret = S_OK;
2447 TRACE("(%p)->(%s)\n", This, debugstr_variant(&destination));
2449 switch (V_VT(&destination))
2451 case VT_UNKNOWN:
2453 IUnknown *pUnk = V_UNKNOWN(&destination);
2454 IXMLDOMDocument3 *document;
2455 IStream *stream;
2457 ret = IUnknown_QueryInterface(pUnk, &IID_IXMLDOMDocument3, (void**)&document);
2458 if(ret == S_OK)
2460 VARIANT_BOOL success;
2461 BSTR xml;
2463 ret = IXMLDOMDocument3_get_xml(iface, &xml);
2464 if(ret == S_OK)
2466 ret = IXMLDOMDocument3_loadXML(document, xml, &success);
2467 SysFreeString(xml);
2470 IXMLDOMDocument3_Release(document);
2471 return ret;
2474 ret = IUnknown_QueryInterface(pUnk, &IID_IStream, (void**)&stream);
2475 if(ret == S_OK)
2477 int options = get_doc(This)->standalone == -1 ? XML_SAVE_NO_DECL : 0;
2478 ctx = xmlSaveToIO(domdoc_stream_save_writecallback,
2479 domdoc_stream_save_closecallback, stream, NULL, options);
2481 if(!ctx)
2483 IStream_Release(stream);
2484 return E_FAIL;
2488 break;
2490 case VT_BSTR:
2491 case VT_BSTR | VT_BYREF:
2493 int options = get_doc(This)->standalone == -1 ? XML_SAVE_NO_DECL : 0;
2495 /* save with file path */
2496 HANDLE handle = CreateFileW( (V_VT(&destination) & VT_BYREF)? *V_BSTRREF(&destination) : V_BSTR(&destination),
2497 GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL );
2498 if( handle == INVALID_HANDLE_VALUE )
2500 WARN("failed to create file\n");
2501 return E_FAIL;
2504 /* disable top XML declaration */
2505 ctx = xmlSaveToIO(domdoc_save_writecallback, domdoc_save_closecallback,
2506 handle, NULL, options);
2507 if (!ctx)
2509 CloseHandle(handle);
2510 return E_FAIL;
2513 break;
2515 default:
2516 FIXME("Unhandled VARIANT: %s\n", debugstr_variant(&destination));
2517 return S_FALSE;
2520 xmldecl = xmldoc_unlink_xmldecl(get_doc(This));
2521 if (xmlSaveDoc(ctx, get_doc(This)) == -1) ret = S_FALSE;
2522 xmldoc_link_xmldecl(get_doc(This), xmldecl);
2524 /* will release resources through close callback */
2525 xmlSaveClose(ctx);
2527 return ret;
2530 static HRESULT WINAPI domdoc_get_validateOnParse(
2531 IXMLDOMDocument3 *iface,
2532 VARIANT_BOOL* isValidating )
2534 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2535 TRACE("(%p)->(%p: %d)\n", This, isValidating, This->validating);
2536 *isValidating = This->validating;
2537 return S_OK;
2541 static HRESULT WINAPI domdoc_put_validateOnParse(
2542 IXMLDOMDocument3 *iface,
2543 VARIANT_BOOL isValidating )
2545 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2546 TRACE("(%p)->(%d)\n", This, isValidating);
2547 This->validating = isValidating;
2548 return S_OK;
2552 static HRESULT WINAPI domdoc_get_resolveExternals(
2553 IXMLDOMDocument3 *iface,
2554 VARIANT_BOOL* isResolving )
2556 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2557 TRACE("(%p)->(%p: %d)\n", This, isResolving, This->resolving);
2558 *isResolving = This->resolving;
2559 return S_OK;
2563 static HRESULT WINAPI domdoc_put_resolveExternals(
2564 IXMLDOMDocument3 *iface,
2565 VARIANT_BOOL isResolving )
2567 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2568 TRACE("(%p)->(%d)\n", This, isResolving);
2569 This->resolving = isResolving;
2570 return S_OK;
2574 static HRESULT WINAPI domdoc_get_preserveWhiteSpace(
2575 IXMLDOMDocument3 *iface,
2576 VARIANT_BOOL* isPreserving )
2578 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2579 TRACE("(%p)->(%p: %d)\n", This, isPreserving, This->properties->preserving);
2580 *isPreserving = This->properties->preserving;
2581 return S_OK;
2585 static HRESULT WINAPI domdoc_put_preserveWhiteSpace(
2586 IXMLDOMDocument3 *iface,
2587 VARIANT_BOOL isPreserving )
2589 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2590 TRACE("(%p)->(%d)\n", This, isPreserving);
2591 This->properties->preserving = isPreserving;
2592 return S_OK;
2596 static HRESULT WINAPI domdoc_put_onreadystatechange(
2597 IXMLDOMDocument3 *iface,
2598 VARIANT event )
2600 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2602 TRACE("(%p)->(%s)\n", This, debugstr_variant(&event));
2603 return set_doc_event(This, EVENTID_READYSTATECHANGE, &event);
2607 static HRESULT WINAPI domdoc_put_onDataAvailable(IXMLDOMDocument3 *iface, VARIANT sink)
2609 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2610 FIXME("(%p)->(%s): stub\n", This, debugstr_variant(&sink));
2611 return E_NOTIMPL;
2614 static HRESULT WINAPI domdoc_put_onTransformNode(IXMLDOMDocument3 *iface, VARIANT sink )
2616 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2617 FIXME("(%p)->(%s): stub\n", This, debugstr_variant(&sink));
2618 return E_NOTIMPL;
2621 static HRESULT WINAPI domdoc_get_namespaces(
2622 IXMLDOMDocument3* iface,
2623 IXMLDOMSchemaCollection** collection )
2625 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2626 HRESULT hr;
2628 FIXME("(%p)->(%p): semi-stub\n", This, collection);
2630 if (!collection) return E_POINTER;
2632 if (!This->namespaces)
2634 hr = SchemaCache_create(This->properties->version, (void**)&This->namespaces);
2635 if (hr != S_OK) return hr;
2637 hr = cache_from_doc_ns(This->namespaces, &This->node);
2638 if (hr != S_OK)
2639 release_namespaces(This);
2642 if (This->namespaces)
2643 return IXMLDOMSchemaCollection2_QueryInterface(This->namespaces,
2644 &IID_IXMLDOMSchemaCollection, (void**)collection);
2646 return hr;
2649 static HRESULT WINAPI domdoc_get_schemas(
2650 IXMLDOMDocument3* iface,
2651 VARIANT* schema )
2653 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2654 IXMLDOMSchemaCollection2* cur_schema = This->properties->schemaCache;
2655 HRESULT hr = S_FALSE;
2657 TRACE("(%p)->(%p)\n", This, schema);
2659 V_VT(schema) = VT_NULL;
2660 /* just to reset pointer part, cause that's what application is expected to use */
2661 V_DISPATCH(schema) = NULL;
2663 if(cur_schema)
2665 hr = IXMLDOMSchemaCollection2_QueryInterface(cur_schema, &IID_IDispatch, (void**)&V_DISPATCH(schema));
2666 if(SUCCEEDED(hr))
2667 V_VT(schema) = VT_DISPATCH;
2669 return hr;
2672 static HRESULT WINAPI domdoc_putref_schemas(
2673 IXMLDOMDocument3* iface,
2674 VARIANT schema)
2676 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2677 HRESULT hr = E_FAIL;
2678 IXMLDOMSchemaCollection2* new_schema = NULL;
2680 FIXME("(%p)->(%s): semi-stub\n", This, debugstr_variant(&schema));
2681 switch(V_VT(&schema))
2683 case VT_UNKNOWN:
2684 if (V_UNKNOWN(&schema))
2686 hr = IUnknown_QueryInterface(V_UNKNOWN(&schema), &IID_IXMLDOMSchemaCollection, (void**)&new_schema);
2687 break;
2689 /* fallthrough */
2690 case VT_DISPATCH:
2691 if (V_DISPATCH(&schema))
2693 hr = IDispatch_QueryInterface(V_DISPATCH(&schema), &IID_IXMLDOMSchemaCollection, (void**)&new_schema);
2694 break;
2696 /* fallthrough */
2697 case VT_NULL:
2698 case VT_EMPTY:
2699 hr = S_OK;
2700 break;
2702 default:
2703 WARN("Can't get schema from vt %x\n", V_VT(&schema));
2706 if(SUCCEEDED(hr))
2708 IXMLDOMSchemaCollection2* old_schema = InterlockedExchangePointer((void**)&This->properties->schemaCache, new_schema);
2709 if(old_schema) IXMLDOMSchemaCollection2_Release(old_schema);
2712 return hr;
2715 static inline BOOL is_wellformed(xmlDocPtr doc)
2717 #ifdef HAVE_XMLDOC_PROPERTIES
2718 return doc->properties & XML_DOC_WELLFORMED;
2719 #else
2720 /* Not a full check, but catches the worst violations */
2721 xmlNodePtr child;
2722 int root = 0;
2724 for (child = doc->children; child != NULL; child = child->next)
2726 switch (child->type)
2728 case XML_ELEMENT_NODE:
2729 if (++root > 1)
2730 return FALSE;
2731 break;
2732 case XML_TEXT_NODE:
2733 case XML_CDATA_SECTION_NODE:
2734 return FALSE;
2735 break;
2736 default:
2737 break;
2741 return root == 1;
2742 #endif
2745 static void LIBXML2_LOG_CALLBACK validate_error(void* ctx, char const* msg, ...)
2747 va_list ap;
2748 va_start(ap, msg);
2749 LIBXML2_CALLBACK_ERR(domdoc_validateNode, msg, ap);
2750 va_end(ap);
2753 static void LIBXML2_LOG_CALLBACK validate_warning(void* ctx, char const* msg, ...)
2755 va_list ap;
2756 va_start(ap, msg);
2757 LIBXML2_CALLBACK_WARN(domdoc_validateNode, msg, ap);
2758 va_end(ap);
2761 static HRESULT WINAPI domdoc_validateNode(
2762 IXMLDOMDocument3* iface,
2763 IXMLDOMNode* node,
2764 IXMLDOMParseError** err)
2766 domdoc* This = impl_from_IXMLDOMDocument3(iface);
2767 LONG state, err_code = 0;
2768 HRESULT hr = S_OK;
2769 int validated = 0;
2771 TRACE("(%p)->(%p, %p)\n", This, node, err);
2772 IXMLDOMDocument3_get_readyState(iface, &state);
2773 if (state != READYSTATE_COMPLETE)
2775 if (err)
2776 *err = create_parseError(err_code, NULL, NULL, NULL, 0, 0, 0);
2777 return E_PENDING;
2780 if (!node)
2782 if (err)
2783 *err = create_parseError(err_code, NULL, NULL, NULL, 0, 0, 0);
2784 return E_POINTER;
2787 if (!get_node_obj(node)->node || get_node_obj(node)->node->doc != get_doc(This))
2789 if (err)
2790 *err = create_parseError(err_code, NULL, NULL, NULL, 0, 0, 0);
2791 return E_FAIL;
2794 if (!is_wellformed(get_doc(This)))
2796 ERR("doc not well-formed\n");
2797 if (err)
2798 *err = create_parseError(E_XML_NOTWF, NULL, NULL, NULL, 0, 0, 0);
2799 return S_FALSE;
2802 /* DTD validation */
2803 if (get_doc(This)->intSubset || get_doc(This)->extSubset)
2805 xmlValidCtxtPtr vctx = xmlNewValidCtxt();
2806 vctx->error = validate_error;
2807 vctx->warning = validate_warning;
2808 ++validated;
2810 if (!((node == (IXMLDOMNode*)iface)?
2811 xmlValidateDocument(vctx, get_doc(This)) :
2812 xmlValidateElement(vctx, get_doc(This), get_node_obj(node)->node)))
2814 /* TODO: get a real error code here */
2815 TRACE("DTD validation failed\n");
2816 err_code = E_XML_INVALID;
2817 hr = S_FALSE;
2819 xmlFreeValidCtxt(vctx);
2822 /* Schema validation */
2823 if (hr == S_OK && This->properties->schemaCache != NULL)
2826 hr = SchemaCache_validate_tree(This->properties->schemaCache, get_node_obj(node)->node);
2827 if (SUCCEEDED(hr))
2829 ++validated;
2830 /* TODO: get a real error code here */
2831 if (hr == S_OK)
2833 TRACE("schema validation succeeded\n");
2835 else
2837 ERR("schema validation failed\n");
2838 err_code = E_XML_INVALID;
2841 else
2843 /* not really OK, just didn't find a schema for the ns */
2844 hr = S_OK;
2848 if (!validated)
2850 ERR("no DTD or schema found\n");
2851 err_code = E_XML_NODTD;
2852 hr = S_FALSE;
2855 if (err)
2856 *err = create_parseError(err_code, NULL, NULL, NULL, 0, 0, 0);
2858 return hr;
2861 static HRESULT WINAPI domdoc_validate(
2862 IXMLDOMDocument3* iface,
2863 IXMLDOMParseError** err)
2865 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2866 TRACE("(%p)->(%p)\n", This, err);
2867 return IXMLDOMDocument3_validateNode(iface, (IXMLDOMNode*)iface, err);
2870 static HRESULT WINAPI domdoc_setProperty(
2871 IXMLDOMDocument3* iface,
2872 BSTR p,
2873 VARIANT value)
2875 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2877 TRACE("(%p)->(%s %s)\n", This, debugstr_w(p), debugstr_variant(&value));
2879 if (lstrcmpiW(p, PropertySelectionLanguageW) == 0)
2881 VARIANT varStr;
2882 HRESULT hr;
2883 BSTR bstr;
2885 V_VT(&varStr) = VT_EMPTY;
2886 if (V_VT(&value) != VT_BSTR)
2888 if (FAILED(hr = VariantChangeType(&varStr, &value, 0, VT_BSTR)))
2889 return hr;
2890 bstr = V_BSTR(&varStr);
2892 else
2893 bstr = V_BSTR(&value);
2895 hr = S_OK;
2896 if (lstrcmpiW(bstr, PropValueXPathW) == 0)
2897 This->properties->XPath = TRUE;
2898 else if (lstrcmpiW(bstr, PropValueXSLPatternW) == 0)
2899 This->properties->XPath = FALSE;
2900 else
2901 hr = E_FAIL;
2903 VariantClear(&varStr);
2904 return hr;
2906 else if (lstrcmpiW(p, PropertySelectionNamespacesW) == 0)
2908 xmlChar *nsStr = (xmlChar*)This->properties->selectNsStr;
2909 struct list *pNsList;
2910 VARIANT varStr;
2911 HRESULT hr;
2912 BSTR bstr;
2914 V_VT(&varStr) = VT_EMPTY;
2915 if (V_VT(&value) != VT_BSTR)
2917 if (FAILED(hr = VariantChangeType(&varStr, &value, 0, VT_BSTR)))
2918 return hr;
2919 bstr = V_BSTR(&varStr);
2921 else
2922 bstr = V_BSTR(&value);
2924 hr = S_OK;
2926 pNsList = &(This->properties->selectNsList);
2927 clear_selectNsList(pNsList);
2928 heap_free(nsStr);
2929 nsStr = xmlchar_from_wchar(bstr);
2931 TRACE("property value: \"%s\"\n", debugstr_w(bstr));
2933 This->properties->selectNsStr = nsStr;
2934 This->properties->selectNsStr_len = xmlStrlen(nsStr);
2935 if (bstr && *bstr)
2937 xmlChar *pTokBegin, *pTokEnd, *pTokInner;
2938 select_ns_entry* ns_entry = NULL;
2939 xmlXPathContextPtr ctx;
2941 ctx = xmlXPathNewContext(This->node.node->doc);
2942 pTokBegin = nsStr;
2944 /* skip leading spaces */
2945 while (*pTokBegin == ' ' || *pTokBegin == '\n' ||
2946 *pTokBegin == '\t' || *pTokBegin == '\r')
2947 ++pTokBegin;
2949 for (; *pTokBegin; pTokBegin = pTokEnd)
2951 if (ns_entry)
2952 memset(ns_entry, 0, sizeof(select_ns_entry));
2953 else
2954 ns_entry = heap_alloc_zero(sizeof(select_ns_entry));
2956 while (*pTokBegin == ' ')
2957 ++pTokBegin;
2958 pTokEnd = pTokBegin;
2959 while (*pTokEnd != ' ' && *pTokEnd != 0)
2960 ++pTokEnd;
2962 /* so it failed to advance which means we've got some trailing spaces */
2963 if (pTokEnd == pTokBegin) break;
2965 if (xmlStrncmp(pTokBegin, (xmlChar const*)"xmlns", 5) != 0)
2967 hr = E_FAIL;
2968 WARN("Syntax error in xmlns string: %s\n\tat token: %s\n",
2969 debugstr_w(bstr), debugstr_an((const char*)pTokBegin, pTokEnd-pTokBegin));
2970 continue;
2973 pTokBegin += 5;
2974 if (*pTokBegin == '=')
2976 /*valid for XSLPattern?*/
2977 FIXME("Setting default xmlns not supported - skipping.\n");
2978 continue;
2980 else if (*pTokBegin == ':')
2982 ns_entry->prefix = ++pTokBegin;
2983 for (pTokInner = pTokBegin; pTokInner != pTokEnd && *pTokInner != '='; ++pTokInner)
2986 if (pTokInner == pTokEnd)
2988 hr = E_FAIL;
2989 WARN("Syntax error in xmlns string: %s\n\tat token: %s\n",
2990 debugstr_w(bstr), debugstr_an((const char*)pTokBegin, pTokEnd-pTokBegin));
2991 continue;
2994 ns_entry->prefix_end = *pTokInner;
2995 *pTokInner = 0;
2996 ++pTokInner;
2998 if (pTokEnd-pTokInner > 1 &&
2999 ((*pTokInner == '\'' && *(pTokEnd-1) == '\'') ||
3000 (*pTokInner == '"' && *(pTokEnd-1) == '"')))
3002 ns_entry->href = ++pTokInner;
3003 ns_entry->href_end = *(pTokEnd-1);
3004 *(pTokEnd-1) = 0;
3005 list_add_tail(pNsList, &ns_entry->entry);
3006 /*let libxml figure out if they're valid from here ;)*/
3007 if (xmlXPathRegisterNs(ctx, ns_entry->prefix, ns_entry->href) != 0)
3009 hr = E_FAIL;
3011 ns_entry = NULL;
3012 continue;
3014 else
3016 WARN("Syntax error in xmlns string: %s\n\tat token: %s\n",
3017 debugstr_w(bstr), debugstr_an((const char*)pTokInner, pTokEnd-pTokInner));
3018 list_add_tail(pNsList, &ns_entry->entry);
3020 ns_entry = NULL;
3021 hr = E_FAIL;
3022 continue;
3025 else
3027 hr = E_FAIL;
3028 continue;
3031 heap_free(ns_entry);
3032 xmlXPathFreeContext(ctx);
3035 VariantClear(&varStr);
3036 return hr;
3038 else if (lstrcmpiW(p, PropertyProhibitDTDW) == 0 ||
3039 lstrcmpiW(p, PropertyNewParserW) == 0 ||
3040 lstrcmpiW(p, PropertyResolveExternalsW) == 0)
3042 /* Ignore */
3043 FIXME("Ignoring property %s, value %s\n", debugstr_w(p), debugstr_variant(&value));
3044 return S_OK;
3047 FIXME("Unknown property %s\n", debugstr_w(p));
3048 return E_FAIL;
3051 static HRESULT WINAPI domdoc_getProperty(
3052 IXMLDOMDocument3* iface,
3053 BSTR p,
3054 VARIANT* var)
3056 domdoc *This = impl_from_IXMLDOMDocument3( iface );
3058 TRACE("(%p)->(%s)\n", This, debugstr_w(p));
3060 if (!var)
3061 return E_INVALIDARG;
3063 if (lstrcmpiW(p, PropertySelectionLanguageW) == 0)
3065 V_VT(var) = VT_BSTR;
3066 V_BSTR(var) = This->properties->XPath ?
3067 SysAllocString(PropValueXPathW) :
3068 SysAllocString(PropValueXSLPatternW);
3069 return V_BSTR(var) ? S_OK : E_OUTOFMEMORY;
3071 else if (lstrcmpiW(p, PropertySelectionNamespacesW) == 0)
3073 int lenA, lenW;
3074 BSTR rebuiltStr, cur;
3075 const xmlChar *nsStr;
3076 struct list *pNsList;
3077 select_ns_entry* pNsEntry;
3079 V_VT(var) = VT_BSTR;
3080 nsStr = This->properties->selectNsStr;
3081 pNsList = &This->properties->selectNsList;
3082 lenA = This->properties->selectNsStr_len;
3083 lenW = MultiByteToWideChar(CP_UTF8, 0, (LPCSTR)nsStr, lenA+1, NULL, 0);
3084 rebuiltStr = heap_alloc(lenW*sizeof(WCHAR));
3085 MultiByteToWideChar(CP_UTF8, 0, (LPCSTR)nsStr, lenA+1, rebuiltStr, lenW);
3086 cur = rebuiltStr;
3087 /* this is fine because all of the chars that end tokens are ASCII*/
3088 LIST_FOR_EACH_ENTRY(pNsEntry, pNsList, select_ns_entry, entry)
3090 while (*cur != 0) ++cur;
3091 if (pNsEntry->prefix_end)
3093 *cur = pNsEntry->prefix_end;
3094 while (*cur != 0) ++cur;
3097 if (pNsEntry->href_end)
3099 *cur = pNsEntry->href_end;
3102 V_BSTR(var) = SysAllocString(rebuiltStr);
3103 heap_free(rebuiltStr);
3104 return S_OK;
3107 FIXME("Unknown property %s\n", debugstr_w(p));
3108 return E_FAIL;
3111 static HRESULT WINAPI domdoc_importNode(
3112 IXMLDOMDocument3* iface,
3113 IXMLDOMNode* node,
3114 VARIANT_BOOL deep,
3115 IXMLDOMNode** clone)
3117 domdoc *This = impl_from_IXMLDOMDocument3( iface );
3118 FIXME("(%p)->(%p %d %p): stub\n", This, node, deep, clone);
3119 return E_NOTIMPL;
3122 static const struct IXMLDOMDocument3Vtbl XMLDOMDocument3Vtbl =
3124 domdoc_QueryInterface,
3125 domdoc_AddRef,
3126 domdoc_Release,
3127 domdoc_GetTypeInfoCount,
3128 domdoc_GetTypeInfo,
3129 domdoc_GetIDsOfNames,
3130 domdoc_Invoke,
3131 domdoc_get_nodeName,
3132 domdoc_get_nodeValue,
3133 domdoc_put_nodeValue,
3134 domdoc_get_nodeType,
3135 domdoc_get_parentNode,
3136 domdoc_get_childNodes,
3137 domdoc_get_firstChild,
3138 domdoc_get_lastChild,
3139 domdoc_get_previousSibling,
3140 domdoc_get_nextSibling,
3141 domdoc_get_attributes,
3142 domdoc_insertBefore,
3143 domdoc_replaceChild,
3144 domdoc_removeChild,
3145 domdoc_appendChild,
3146 domdoc_hasChildNodes,
3147 domdoc_get_ownerDocument,
3148 domdoc_cloneNode,
3149 domdoc_get_nodeTypeString,
3150 domdoc_get_text,
3151 domdoc_put_text,
3152 domdoc_get_specified,
3153 domdoc_get_definition,
3154 domdoc_get_nodeTypedValue,
3155 domdoc_put_nodeTypedValue,
3156 domdoc_get_dataType,
3157 domdoc_put_dataType,
3158 domdoc_get_xml,
3159 domdoc_transformNode,
3160 domdoc_selectNodes,
3161 domdoc_selectSingleNode,
3162 domdoc_get_parsed,
3163 domdoc_get_namespaceURI,
3164 domdoc_get_prefix,
3165 domdoc_get_baseName,
3166 domdoc_transformNodeToObject,
3167 domdoc_get_doctype,
3168 domdoc_get_implementation,
3169 domdoc_get_documentElement,
3170 domdoc_put_documentElement,
3171 domdoc_createElement,
3172 domdoc_createDocumentFragment,
3173 domdoc_createTextNode,
3174 domdoc_createComment,
3175 domdoc_createCDATASection,
3176 domdoc_createProcessingInstruction,
3177 domdoc_createAttribute,
3178 domdoc_createEntityReference,
3179 domdoc_getElementsByTagName,
3180 domdoc_createNode,
3181 domdoc_nodeFromID,
3182 domdoc_load,
3183 domdoc_get_readyState,
3184 domdoc_get_parseError,
3185 domdoc_get_url,
3186 domdoc_get_async,
3187 domdoc_put_async,
3188 domdoc_abort,
3189 domdoc_loadXML,
3190 domdoc_save,
3191 domdoc_get_validateOnParse,
3192 domdoc_put_validateOnParse,
3193 domdoc_get_resolveExternals,
3194 domdoc_put_resolveExternals,
3195 domdoc_get_preserveWhiteSpace,
3196 domdoc_put_preserveWhiteSpace,
3197 domdoc_put_onreadystatechange,
3198 domdoc_put_onDataAvailable,
3199 domdoc_put_onTransformNode,
3200 domdoc_get_namespaces,
3201 domdoc_get_schemas,
3202 domdoc_putref_schemas,
3203 domdoc_validate,
3204 domdoc_setProperty,
3205 domdoc_getProperty,
3206 domdoc_validateNode,
3207 domdoc_importNode
3210 /* IConnectionPointContainer */
3211 static HRESULT WINAPI ConnectionPointContainer_QueryInterface(IConnectionPointContainer *iface,
3212 REFIID riid, void **ppv)
3214 domdoc *This = impl_from_IConnectionPointContainer(iface);
3215 return IXMLDOMDocument3_QueryInterface(&This->IXMLDOMDocument3_iface, riid, ppv);
3218 static ULONG WINAPI ConnectionPointContainer_AddRef(IConnectionPointContainer *iface)
3220 domdoc *This = impl_from_IConnectionPointContainer(iface);
3221 return IXMLDOMDocument3_AddRef(&This->IXMLDOMDocument3_iface);
3224 static ULONG WINAPI ConnectionPointContainer_Release(IConnectionPointContainer *iface)
3226 domdoc *This = impl_from_IConnectionPointContainer(iface);
3227 return IXMLDOMDocument3_Release(&This->IXMLDOMDocument3_iface);
3230 static HRESULT WINAPI ConnectionPointContainer_EnumConnectionPoints(IConnectionPointContainer *iface,
3231 IEnumConnectionPoints **ppEnum)
3233 domdoc *This = impl_from_IConnectionPointContainer(iface);
3234 FIXME("(%p)->(%p): stub\n", This, ppEnum);
3235 return E_NOTIMPL;
3238 static HRESULT WINAPI ConnectionPointContainer_FindConnectionPoint(IConnectionPointContainer *iface,
3239 REFIID riid, IConnectionPoint **cp)
3241 domdoc *This = impl_from_IConnectionPointContainer(iface);
3242 ConnectionPoint *iter;
3244 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), cp);
3246 *cp = NULL;
3248 for(iter = This->cp_list; iter; iter = iter->next)
3250 if (IsEqualGUID(iter->iid, riid))
3251 *cp = &iter->IConnectionPoint_iface;
3254 if (*cp)
3256 IConnectionPoint_AddRef(*cp);
3257 return S_OK;
3260 FIXME("unsupported riid %s\n", debugstr_guid(riid));
3261 return CONNECT_E_NOCONNECTION;
3265 static const struct IConnectionPointContainerVtbl ConnectionPointContainerVtbl =
3267 ConnectionPointContainer_QueryInterface,
3268 ConnectionPointContainer_AddRef,
3269 ConnectionPointContainer_Release,
3270 ConnectionPointContainer_EnumConnectionPoints,
3271 ConnectionPointContainer_FindConnectionPoint
3274 /* IConnectionPoint */
3275 static HRESULT WINAPI ConnectionPoint_QueryInterface(IConnectionPoint *iface,
3276 REFIID riid, void **ppv)
3278 ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3280 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv );
3282 *ppv = NULL;
3284 if (IsEqualGUID(&IID_IUnknown, riid) ||
3285 IsEqualGUID(&IID_IConnectionPoint, riid))
3287 *ppv = iface;
3290 if (*ppv)
3292 IConnectionPoint_AddRef(iface);
3293 return S_OK;
3296 WARN("Unsupported interface %s\n", debugstr_guid(riid));
3297 return E_NOINTERFACE;
3300 static ULONG WINAPI ConnectionPoint_AddRef(IConnectionPoint *iface)
3302 ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3303 return IConnectionPointContainer_AddRef(This->container);
3306 static ULONG WINAPI ConnectionPoint_Release(IConnectionPoint *iface)
3308 ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3309 return IConnectionPointContainer_Release(This->container);
3312 static HRESULT WINAPI ConnectionPoint_GetConnectionInterface(IConnectionPoint *iface, IID *iid)
3314 ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3316 TRACE("(%p)->(%p)\n", This, iid);
3318 if (!iid) return E_POINTER;
3320 *iid = *This->iid;
3321 return S_OK;
3324 static HRESULT WINAPI ConnectionPoint_GetConnectionPointContainer(IConnectionPoint *iface,
3325 IConnectionPointContainer **container)
3327 ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3329 TRACE("(%p)->(%p)\n", This, container);
3331 if (!container) return E_POINTER;
3333 *container = This->container;
3334 IConnectionPointContainer_AddRef(*container);
3335 return S_OK;
3338 static HRESULT WINAPI ConnectionPoint_Advise(IConnectionPoint *iface, IUnknown *unk_sink,
3339 DWORD *cookie)
3341 ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3342 IUnknown *sink;
3343 HRESULT hr;
3344 DWORD i;
3346 TRACE("(%p)->(%p %p)\n", This, unk_sink, cookie);
3348 hr = IUnknown_QueryInterface(unk_sink, This->iid, (void**)&sink);
3349 if(FAILED(hr) && !IsEqualGUID(&IID_IPropertyNotifySink, This->iid))
3350 hr = IUnknown_QueryInterface(unk_sink, &IID_IDispatch, (void**)&sink);
3351 if(FAILED(hr))
3352 return CONNECT_E_CANNOTCONNECT;
3354 if(This->sinks)
3356 for (i = 0; i < This->sinks_size; i++)
3357 if (!This->sinks[i].unk)
3358 break;
3360 if (i == This->sinks_size)
3361 This->sinks = heap_realloc(This->sinks,(++This->sinks_size)*sizeof(*This->sinks));
3363 else
3365 This->sinks = heap_alloc(sizeof(*This->sinks));
3366 This->sinks_size = 1;
3367 i = 0;
3370 This->sinks[i].unk = sink;
3371 if (cookie)
3372 *cookie = i+1;
3374 return S_OK;
3377 static HRESULT WINAPI ConnectionPoint_Unadvise(IConnectionPoint *iface, DWORD cookie)
3379 ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3381 TRACE("(%p)->(%d)\n", This, cookie);
3383 if (cookie == 0 || cookie > This->sinks_size || !This->sinks[cookie-1].unk)
3384 return CONNECT_E_NOCONNECTION;
3386 IUnknown_Release(This->sinks[cookie-1].unk);
3387 This->sinks[cookie-1].unk = NULL;
3389 return S_OK;
3392 static HRESULT WINAPI ConnectionPoint_EnumConnections(IConnectionPoint *iface,
3393 IEnumConnections **ppEnum)
3395 ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3396 FIXME("(%p)->(%p): stub\n", This, ppEnum);
3397 return E_NOTIMPL;
3400 static const IConnectionPointVtbl ConnectionPointVtbl =
3402 ConnectionPoint_QueryInterface,
3403 ConnectionPoint_AddRef,
3404 ConnectionPoint_Release,
3405 ConnectionPoint_GetConnectionInterface,
3406 ConnectionPoint_GetConnectionPointContainer,
3407 ConnectionPoint_Advise,
3408 ConnectionPoint_Unadvise,
3409 ConnectionPoint_EnumConnections
3412 static void ConnectionPoint_Init(ConnectionPoint *cp, struct domdoc *doc, REFIID riid)
3414 cp->IConnectionPoint_iface.lpVtbl = &ConnectionPointVtbl;
3415 cp->doc = doc;
3416 cp->iid = riid;
3417 cp->sinks = NULL;
3418 cp->sinks_size = 0;
3420 cp->next = doc->cp_list;
3421 doc->cp_list = cp;
3423 cp->container = &doc->IConnectionPointContainer_iface;
3426 /* domdoc implementation of IObjectWithSite */
3427 static HRESULT WINAPI
3428 domdoc_ObjectWithSite_QueryInterface( IObjectWithSite* iface, REFIID riid, void** ppvObject )
3430 domdoc *This = impl_from_IObjectWithSite(iface);
3431 return IXMLDOMDocument3_QueryInterface(&This->IXMLDOMDocument3_iface, riid, ppvObject);
3434 static ULONG WINAPI domdoc_ObjectWithSite_AddRef( IObjectWithSite* iface )
3436 domdoc *This = impl_from_IObjectWithSite(iface);
3437 return IXMLDOMDocument3_AddRef(&This->IXMLDOMDocument3_iface);
3440 static ULONG WINAPI domdoc_ObjectWithSite_Release( IObjectWithSite* iface )
3442 domdoc *This = impl_from_IObjectWithSite(iface);
3443 return IXMLDOMDocument3_Release(&This->IXMLDOMDocument3_iface);
3446 static HRESULT WINAPI domdoc_ObjectWithSite_GetSite( IObjectWithSite *iface, REFIID iid, void **ppvSite )
3448 domdoc *This = impl_from_IObjectWithSite(iface);
3450 TRACE("(%p)->(%s %p)\n", This, debugstr_guid( iid ), ppvSite );
3452 if ( !This->site )
3453 return E_FAIL;
3455 return IUnknown_QueryInterface( This->site, iid, ppvSite );
3458 static HRESULT WINAPI domdoc_ObjectWithSite_SetSite( IObjectWithSite *iface, IUnknown *punk )
3460 domdoc *This = impl_from_IObjectWithSite(iface);
3462 TRACE("(%p)->(%p)\n", iface, punk);
3464 if(!punk)
3466 if(This->site)
3468 IUnknown_Release( This->site );
3469 This->site = NULL;
3472 return S_OK;
3475 IUnknown_AddRef( punk );
3477 if(This->site)
3478 IUnknown_Release( This->site );
3480 This->site = punk;
3482 return S_OK;
3485 static const IObjectWithSiteVtbl domdocObjectSite =
3487 domdoc_ObjectWithSite_QueryInterface,
3488 domdoc_ObjectWithSite_AddRef,
3489 domdoc_ObjectWithSite_Release,
3490 domdoc_ObjectWithSite_SetSite,
3491 domdoc_ObjectWithSite_GetSite
3494 static HRESULT WINAPI domdoc_Safety_QueryInterface(IObjectSafety *iface, REFIID riid, void **ppv)
3496 domdoc *This = impl_from_IObjectSafety(iface);
3497 return IXMLDOMDocument3_QueryInterface(&This->IXMLDOMDocument3_iface, riid, ppv);
3500 static ULONG WINAPI domdoc_Safety_AddRef(IObjectSafety *iface)
3502 domdoc *This = impl_from_IObjectSafety(iface);
3503 return IXMLDOMDocument3_AddRef(&This->IXMLDOMDocument3_iface);
3506 static ULONG WINAPI domdoc_Safety_Release(IObjectSafety *iface)
3508 domdoc *This = impl_from_IObjectSafety(iface);
3509 return IXMLDOMDocument3_Release(&This->IXMLDOMDocument3_iface);
3512 #define SAFETY_SUPPORTED_OPTIONS (INTERFACESAFE_FOR_UNTRUSTED_CALLER|INTERFACESAFE_FOR_UNTRUSTED_DATA|INTERFACE_USES_SECURITY_MANAGER)
3514 static HRESULT WINAPI domdoc_Safety_GetInterfaceSafetyOptions(IObjectSafety *iface, REFIID riid,
3515 DWORD *supported, DWORD *enabled)
3517 domdoc *This = impl_from_IObjectSafety(iface);
3519 TRACE("(%p)->(%s %p %p)\n", This, debugstr_guid(riid), supported, enabled);
3521 if(!supported || !enabled) return E_POINTER;
3523 *supported = SAFETY_SUPPORTED_OPTIONS;
3524 *enabled = This->safeopt;
3526 return S_OK;
3529 static HRESULT WINAPI domdoc_Safety_SetInterfaceSafetyOptions(IObjectSafety *iface, REFIID riid,
3530 DWORD mask, DWORD enabled)
3532 domdoc *This = impl_from_IObjectSafety(iface);
3533 TRACE("(%p)->(%s %x %x)\n", This, debugstr_guid(riid), mask, enabled);
3535 if ((mask & ~SAFETY_SUPPORTED_OPTIONS) != 0)
3536 return E_FAIL;
3538 This->safeopt = (This->safeopt & ~mask) | (mask & enabled);
3540 return S_OK;
3543 #undef SAFETY_SUPPORTED_OPTIONS
3545 static const IObjectSafetyVtbl domdocObjectSafetyVtbl = {
3546 domdoc_Safety_QueryInterface,
3547 domdoc_Safety_AddRef,
3548 domdoc_Safety_Release,
3549 domdoc_Safety_GetInterfaceSafetyOptions,
3550 domdoc_Safety_SetInterfaceSafetyOptions
3553 static const tid_t domdoc_iface_tids[] = {
3554 IXMLDOMDocument3_tid,
3558 static dispex_static_data_t domdoc_dispex = {
3559 NULL,
3560 IXMLDOMDocument3_tid,
3561 NULL,
3562 domdoc_iface_tids
3565 HRESULT get_domdoc_from_xmldoc(xmlDocPtr xmldoc, IXMLDOMDocument3 **document)
3567 domdoc *doc;
3569 doc = heap_alloc( sizeof (*doc) );
3570 if( !doc )
3571 return E_OUTOFMEMORY;
3573 doc->IXMLDOMDocument3_iface.lpVtbl = &XMLDOMDocument3Vtbl;
3574 doc->IPersistStreamInit_iface.lpVtbl = &xmldoc_IPersistStreamInit_VTable;
3575 doc->IObjectWithSite_iface.lpVtbl = &domdocObjectSite;
3576 doc->IObjectSafety_iface.lpVtbl = &domdocObjectSafetyVtbl;
3577 doc->IConnectionPointContainer_iface.lpVtbl = &ConnectionPointContainerVtbl;
3578 doc->ref = 1;
3579 doc->async = VARIANT_TRUE;
3580 doc->validating = 0;
3581 doc->resolving = 0;
3582 doc->properties = properties_from_xmlDocPtr(xmldoc);
3583 doc->error = S_OK;
3584 doc->site = NULL;
3585 doc->safeopt = 0;
3586 doc->cp_list = NULL;
3587 doc->namespaces = NULL;
3588 memset(doc->events, 0, sizeof(doc->events));
3590 /* events connection points */
3591 ConnectionPoint_Init(&doc->cp_dispatch, doc, &IID_IDispatch);
3592 ConnectionPoint_Init(&doc->cp_propnotif, doc, &IID_IPropertyNotifySink);
3593 ConnectionPoint_Init(&doc->cp_domdocevents, doc, &DIID_XMLDOMDocumentEvents);
3595 init_xmlnode(&doc->node, (xmlNodePtr)xmldoc, (IXMLDOMNode*)&doc->IXMLDOMDocument3_iface,
3596 &domdoc_dispex);
3598 *document = &doc->IXMLDOMDocument3_iface;
3600 TRACE("returning iface %p\n", *document);
3601 return S_OK;
3604 HRESULT DOMDocument_create(MSXML_VERSION version, void **ppObj)
3606 xmlDocPtr xmldoc;
3607 HRESULT hr;
3609 TRACE("(%d, %p)\n", version, ppObj);
3611 xmldoc = xmlNewDoc(NULL);
3612 if(!xmldoc)
3613 return E_OUTOFMEMORY;
3615 xmldoc_init(xmldoc, version);
3617 hr = get_domdoc_from_xmldoc(xmldoc, (IXMLDOMDocument3**)ppObj);
3618 if(FAILED(hr))
3620 free_properties(properties_from_xmlDocPtr(xmldoc));
3621 heap_free(xmldoc->_private);
3622 xmlFreeDoc(xmldoc);
3623 return hr;
3626 return hr;
3629 IUnknown* create_domdoc( xmlNodePtr document )
3631 void* pObj = NULL;
3632 HRESULT hr;
3634 TRACE("(%p)\n", document);
3636 hr = get_domdoc_from_xmldoc((xmlDocPtr)document, (IXMLDOMDocument3**)&pObj);
3637 if (FAILED(hr))
3638 return NULL;
3640 return pObj;
3643 #else
3645 HRESULT DOMDocument_create(MSXML_VERSION version, void **ppObj)
3647 MESSAGE("This program tried to use a DOMDocument object, but\n"
3648 "libxml2 support was not present at compile time.\n");
3649 return E_NOTIMPL;
3652 #endif