vbscript: Moved Error object implementation to global.c.
[wine/multimedia.git] / dlls / msxml3 / domdoc.c
blobe981b94177420ef9130f1331e6c0b88dddbe4620
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 mod_pre[] = "*[local-name()='";
1850 static const xmlChar mod_post[] = "']";
1851 static const xmlChar prefix[] = "descendant::";
1852 const WCHAR *tokBegin, *tokEnd;
1853 int len;
1855 query = xmlStrdup(prefix);
1857 tokBegin = tagName;
1858 while (tokBegin && *tokBegin)
1860 switch (*tokBegin)
1862 case '/':
1863 query = xmlStrcat(query, BAD_CAST "/");
1864 ++tokBegin;
1865 break;
1866 case '*':
1867 query = xmlStrcat(query, BAD_CAST "*");
1868 ++tokBegin;
1869 break;
1870 default:
1871 query = xmlStrcat(query, mod_pre);
1872 tokEnd = tokBegin;
1873 while (*tokEnd && *tokEnd != '/')
1874 ++tokEnd;
1875 len = WideCharToMultiByte(CP_UTF8, 0, tokBegin, tokEnd-tokBegin, NULL, 0, NULL, NULL);
1876 tmp = xmlMalloc(len);
1877 WideCharToMultiByte(CP_UTF8, 0, tokBegin, tokEnd-tokBegin, (char*)tmp, len, NULL, NULL);
1878 query = xmlStrncat(query, tmp, len);
1879 xmlFree(tmp);
1880 tokBegin = tokEnd;
1881 query = xmlStrcat(query, mod_post);
1885 return query;
1888 static HRESULT WINAPI domdoc_getElementsByTagName(
1889 IXMLDOMDocument3 *iface,
1890 BSTR tagName,
1891 IXMLDOMNodeList** resultList )
1893 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1894 xmlChar *query;
1895 HRESULT hr;
1896 BOOL XPath;
1898 TRACE("(%p)->(%s, %p)\n", This, debugstr_w(tagName), resultList);
1900 if (!tagName || !resultList) return E_INVALIDARG;
1902 XPath = This->properties->XPath;
1903 This->properties->XPath = TRUE;
1904 query = tagName_to_XPath(tagName);
1905 hr = create_selection((xmlNodePtr)get_doc(This), query, resultList);
1906 xmlFree(query);
1907 This->properties->XPath = XPath;
1909 return hr;
1912 static HRESULT get_node_type(VARIANT Type, DOMNodeType * type)
1914 VARIANT tmp;
1915 HRESULT hr;
1917 VariantInit(&tmp);
1918 hr = VariantChangeType(&tmp, &Type, 0, VT_I4);
1919 if(FAILED(hr))
1920 return E_INVALIDARG;
1922 *type = V_I4(&tmp);
1924 return S_OK;
1927 static HRESULT WINAPI domdoc_createNode(
1928 IXMLDOMDocument3 *iface,
1929 VARIANT Type,
1930 BSTR name,
1931 BSTR namespaceURI,
1932 IXMLDOMNode** node )
1934 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1935 DOMNodeType node_type;
1936 xmlNodePtr xmlnode;
1937 xmlChar *xml_name, *href;
1938 HRESULT hr;
1940 TRACE("(%p)->(%s %s %s %p)\n", This, debugstr_variant(&Type), debugstr_w(name), debugstr_w(namespaceURI), node);
1942 if(!node) return E_INVALIDARG;
1944 hr = get_node_type(Type, &node_type);
1945 if(FAILED(hr)) return hr;
1947 TRACE("node_type %d\n", node_type);
1949 /* exit earlier for types that need name */
1950 switch(node_type)
1952 case NODE_ELEMENT:
1953 case NODE_ATTRIBUTE:
1954 case NODE_ENTITY_REFERENCE:
1955 case NODE_PROCESSING_INSTRUCTION:
1956 if (!name || *name == 0) return E_FAIL;
1957 break;
1958 default:
1959 break;
1962 xml_name = xmlchar_from_wchar(name);
1963 /* prevent empty href to be allocated */
1964 href = namespaceURI ? xmlchar_from_wchar(namespaceURI) : NULL;
1966 switch(node_type)
1968 case NODE_ELEMENT:
1970 xmlChar *local, *prefix;
1972 local = xmlSplitQName2(xml_name, &prefix);
1974 xmlnode = xmlNewDocNode(get_doc(This), NULL, local ? local : xml_name, NULL);
1976 /* allow to create default namespace xmlns= */
1977 if (local || (href && *href))
1979 xmlNsPtr ns = xmlNewNs(xmlnode, href, prefix);
1980 xmlSetNs(xmlnode, ns);
1983 xmlFree(local);
1984 xmlFree(prefix);
1986 break;
1988 case NODE_ATTRIBUTE:
1990 xmlChar *local, *prefix;
1992 local = xmlSplitQName2(xml_name, &prefix);
1994 xmlnode = (xmlNodePtr)xmlNewDocProp(get_doc(This), local ? local : xml_name, NULL);
1996 if (local || (href && *href))
1998 /* we need a floating namespace here, it can't be created linked to attribute from
1999 a start */
2000 xmlNsPtr ns = xmlNewNs(NULL, href, prefix);
2001 xmlSetNs(xmlnode, ns);
2004 xmlFree(local);
2005 xmlFree(prefix);
2007 break;
2009 case NODE_TEXT:
2010 xmlnode = (xmlNodePtr)xmlNewDocText(get_doc(This), NULL);
2011 break;
2012 case NODE_CDATA_SECTION:
2013 xmlnode = xmlNewCDataBlock(get_doc(This), NULL, 0);
2014 break;
2015 case NODE_ENTITY_REFERENCE:
2016 xmlnode = xmlNewReference(get_doc(This), xml_name);
2017 break;
2018 case NODE_PROCESSING_INSTRUCTION:
2019 #ifdef HAVE_XMLNEWDOCPI
2020 xmlnode = xmlNewDocPI(get_doc(This), xml_name, NULL);
2021 #else
2022 FIXME("xmlNewDocPI() not supported, use libxml2 2.6.15 or greater\n");
2023 xmlnode = NULL;
2024 #endif
2025 break;
2026 case NODE_COMMENT:
2027 xmlnode = xmlNewDocComment(get_doc(This), NULL);
2028 break;
2029 case NODE_DOCUMENT_FRAGMENT:
2030 xmlnode = xmlNewDocFragment(get_doc(This));
2031 break;
2032 /* unsupported types */
2033 case NODE_DOCUMENT:
2034 case NODE_DOCUMENT_TYPE:
2035 case NODE_ENTITY:
2036 case NODE_NOTATION:
2037 heap_free(xml_name);
2038 return E_INVALIDARG;
2039 default:
2040 FIXME("unhandled node type %d\n", node_type);
2041 xmlnode = NULL;
2042 break;
2045 *node = create_node(xmlnode);
2046 heap_free(xml_name);
2047 heap_free(href);
2049 if(*node)
2051 TRACE("created node (%d, %p, %p)\n", node_type, *node, xmlnode);
2052 xmldoc_add_orphan(xmlnode->doc, xmlnode);
2053 return S_OK;
2056 return E_FAIL;
2059 static HRESULT WINAPI domdoc_nodeFromID(
2060 IXMLDOMDocument3 *iface,
2061 BSTR idString,
2062 IXMLDOMNode** node )
2064 domdoc *This = impl_from_IXMLDOMDocument3(iface);
2065 FIXME("(%p)->(%s %p)\n", This, debugstr_w(idString), node);
2066 return E_NOTIMPL;
2069 static HRESULT domdoc_onDataAvailable(void *obj, char *ptr, DWORD len)
2071 domdoc *This = obj;
2072 xmlDocPtr xmldoc;
2074 xmldoc = doparse(This, ptr, len, XML_CHAR_ENCODING_NONE);
2075 if(xmldoc) {
2076 xmldoc->_private = create_priv();
2077 return attach_xmldoc(This, xmldoc);
2080 return E_FAIL;
2083 static HRESULT domdoc_load_moniker(domdoc *This, IMoniker *mon)
2085 bsc_t *bsc;
2086 HRESULT hr;
2088 hr = bind_url(mon, domdoc_onDataAvailable, This, &bsc);
2089 if(FAILED(hr))
2090 return hr;
2092 return detach_bsc(bsc);
2095 static HRESULT WINAPI domdoc_load(
2096 IXMLDOMDocument3 *iface,
2097 VARIANT source,
2098 VARIANT_BOOL* isSuccessful )
2100 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2101 LPWSTR filename = NULL;
2102 HRESULT hr = S_FALSE;
2103 xmlDocPtr xmldoc;
2105 TRACE("(%p)->(%s)\n", This, debugstr_variant(&source));
2107 if (!isSuccessful)
2108 return E_POINTER;
2109 *isSuccessful = VARIANT_FALSE;
2111 assert( &This->node );
2113 switch( V_VT(&source) )
2115 case VT_BSTR:
2116 filename = V_BSTR(&source);
2117 break;
2118 case VT_BSTR|VT_BYREF:
2119 if (!V_BSTRREF(&source)) return E_INVALIDARG;
2120 filename = *V_BSTRREF(&source);
2121 break;
2122 case VT_ARRAY|VT_UI1:
2124 SAFEARRAY *psa = V_ARRAY(&source);
2125 char *str;
2126 LONG len;
2127 UINT dim = SafeArrayGetDim(psa);
2129 switch (dim)
2131 case 0:
2132 ERR("SAFEARRAY == NULL\n");
2133 hr = This->error = E_INVALIDARG;
2134 break;
2135 case 1:
2136 /* Only takes UTF-8 strings.
2137 * NOT NULL-terminated. */
2138 SafeArrayAccessData(psa, (void**)&str);
2139 SafeArrayGetUBound(psa, 1, &len);
2141 if ((xmldoc = doparse(This, str, ++len, XML_CHAR_ENCODING_UTF8)))
2143 hr = This->error = S_OK;
2144 *isSuccessful = VARIANT_TRUE;
2145 TRACE("parsed document %p\n", xmldoc);
2147 else
2149 This->error = E_FAIL;
2150 TRACE("failed to parse document\n");
2153 SafeArrayUnaccessData(psa);
2155 if(xmldoc)
2157 xmldoc->_private = create_priv();
2158 return attach_xmldoc(This, xmldoc);
2160 break;
2161 default:
2162 FIXME("unhandled SAFEARRAY dim: %d\n", dim);
2163 hr = This->error = E_NOTIMPL;
2166 break;
2167 case VT_UNKNOWN:
2169 ISequentialStream *stream = NULL;
2170 IXMLDOMDocument3 *newdoc = NULL;
2172 if (!V_UNKNOWN(&source)) return E_INVALIDARG;
2174 hr = IUnknown_QueryInterface(V_UNKNOWN(&source), &IID_IXMLDOMDocument3, (void**)&newdoc);
2175 if(hr == S_OK)
2177 if(newdoc)
2179 domdoc *newDoc = impl_from_IXMLDOMDocument3( newdoc );
2181 xmldoc = xmlCopyDoc(get_doc(newDoc), 1);
2182 xmldoc->_private = create_priv();
2183 hr = attach_xmldoc(This, xmldoc);
2185 if(SUCCEEDED(hr))
2186 *isSuccessful = VARIANT_TRUE;
2188 return hr;
2192 hr = IUnknown_QueryInterface(V_UNKNOWN(&source), &IID_IStream, (void**)&stream);
2193 if (FAILED(hr))
2194 hr = IUnknown_QueryInterface(V_UNKNOWN(&source), &IID_ISequentialStream, (void**)&stream);
2196 if (hr == S_OK)
2198 hr = domdoc_load_from_stream(This, stream);
2199 if (hr == S_OK)
2200 *isSuccessful = VARIANT_TRUE;
2201 ISequentialStream_Release(stream);
2202 return hr;
2205 FIXME("unsupported IUnknown type (0x%08x) (%p)\n", hr, V_UNKNOWN(&source)->lpVtbl);
2206 break;
2208 default:
2209 FIXME("VT type not supported (%d)\n", V_VT(&source));
2212 if ( filename )
2214 IMoniker *mon;
2216 CoTaskMemFree(This->properties->url);
2217 This->properties->url = NULL;
2219 hr = create_moniker_from_url( filename, &mon);
2220 if ( SUCCEEDED(hr) )
2222 hr = domdoc_load_moniker( This, mon );
2223 if (hr == S_OK)
2224 IMoniker_GetDisplayName(mon, NULL, NULL, &This->properties->url);
2225 IMoniker_Release(mon);
2228 if ( FAILED(hr) )
2229 This->error = E_FAIL;
2230 else
2232 hr = This->error = S_OK;
2233 *isSuccessful = VARIANT_TRUE;
2237 if(!filename || FAILED(hr)) {
2238 xmldoc = xmlNewDoc(NULL);
2239 xmldoc->_private = create_priv();
2240 hr = attach_xmldoc(This, xmldoc);
2241 if(SUCCEEDED(hr))
2242 hr = S_FALSE;
2245 TRACE("ret (%d)\n", hr);
2247 return hr;
2251 static HRESULT WINAPI domdoc_get_readyState(
2252 IXMLDOMDocument3 *iface,
2253 LONG *value )
2255 domdoc *This = impl_from_IXMLDOMDocument3(iface);
2256 FIXME("stub! (%p)->(%p)\n", This, value);
2258 if (!value)
2259 return E_INVALIDARG;
2261 *value = READYSTATE_COMPLETE;
2262 return S_OK;
2266 static HRESULT WINAPI domdoc_get_parseError(
2267 IXMLDOMDocument3 *iface,
2268 IXMLDOMParseError** errorObj )
2270 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2271 static const WCHAR err[] = {'e','r','r','o','r',0};
2272 BSTR error_string = NULL;
2274 FIXME("(%p)->(%p): creating a dummy parseError\n", iface, errorObj);
2276 if(This->error)
2277 error_string = SysAllocString(err);
2279 *errorObj = create_parseError(This->error, NULL, error_string, NULL, 0, 0, 0);
2280 if(!*errorObj) return E_OUTOFMEMORY;
2281 return S_OK;
2285 static HRESULT WINAPI domdoc_get_url(
2286 IXMLDOMDocument3 *iface,
2287 BSTR* url )
2289 domdoc *This = impl_from_IXMLDOMDocument3(iface);
2291 TRACE("(%p)->(%p)\n", This, url);
2293 if (!url)
2294 return E_INVALIDARG;
2296 if (This->properties->url)
2298 *url = SysAllocString(This->properties->url);
2299 if (!*url)
2300 return E_OUTOFMEMORY;
2302 return S_OK;
2304 else
2305 return return_null_bstr(url);
2309 static HRESULT WINAPI domdoc_get_async(
2310 IXMLDOMDocument3 *iface,
2311 VARIANT_BOOL* isAsync )
2313 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2315 TRACE("(%p)->(%p: %d)\n", This, isAsync, This->async);
2316 *isAsync = This->async;
2317 return S_OK;
2321 static HRESULT WINAPI domdoc_put_async(
2322 IXMLDOMDocument3 *iface,
2323 VARIANT_BOOL isAsync )
2325 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2327 TRACE("(%p)->(%d)\n", This, isAsync);
2328 This->async = isAsync;
2329 return S_OK;
2333 static HRESULT WINAPI domdoc_abort(
2334 IXMLDOMDocument3 *iface )
2336 domdoc *This = impl_from_IXMLDOMDocument3(iface);
2337 FIXME("%p\n", This);
2338 return E_NOTIMPL;
2341 /* don't rely on data to be in BSTR format, treat it as WCHAR string */
2342 static HRESULT WINAPI domdoc_loadXML(
2343 IXMLDOMDocument3 *iface,
2344 BSTR data,
2345 VARIANT_BOOL* isSuccessful )
2347 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2348 xmlDocPtr xmldoc = NULL;
2349 HRESULT hr = S_FALSE, hr2;
2351 TRACE("(%p)->(%s %p)\n", This, debugstr_w(data), isSuccessful );
2353 assert ( &This->node );
2355 if ( isSuccessful )
2357 *isSuccessful = VARIANT_FALSE;
2359 if (data)
2361 WCHAR *ptr = data;
2363 /* skip leading spaces if needed */
2364 if (This->properties->version == MSXML_DEFAULT || This->properties->version == MSXML26)
2365 while (*ptr && isspaceW(*ptr)) ptr++;
2367 xmldoc = doparse(This, (char*)ptr, strlenW(ptr)*sizeof(WCHAR), XML_CHAR_ENCODING_UTF16LE);
2368 if ( !xmldoc )
2370 This->error = E_FAIL;
2371 TRACE("failed to parse document\n");
2373 else
2375 hr = This->error = S_OK;
2376 *isSuccessful = VARIANT_TRUE;
2377 TRACE("parsed document %p\n", xmldoc);
2382 if(!xmldoc)
2383 xmldoc = xmlNewDoc(NULL);
2384 xmldoc->_private = create_priv();
2385 hr2 = attach_xmldoc(This, xmldoc);
2386 if( FAILED(hr2) )
2387 hr = hr2;
2389 return hr;
2392 static int XMLCALL domdoc_save_writecallback(void *ctx, const char *buffer, int len)
2394 DWORD written = -1;
2396 if(!WriteFile(ctx, buffer, len, &written, NULL))
2398 WARN("write error\n");
2399 return -1;
2401 else
2402 return written;
2405 static int XMLCALL domdoc_save_closecallback(void *ctx)
2407 return CloseHandle(ctx) ? 0 : -1;
2410 static int XMLCALL domdoc_stream_save_writecallback(void *ctx, const char *buffer, int len)
2412 ULONG written = 0;
2413 HRESULT hr;
2415 hr = IStream_Write((IStream*)ctx, buffer, len, &written);
2416 TRACE("0x%08x %p %d %u\n", hr, buffer, len, written);
2417 if (hr != S_OK)
2419 WARN("stream write error: 0x%08x\n", hr);
2420 return -1;
2422 else
2423 return len;
2426 static int XMLCALL domdoc_stream_save_closecallback(void *ctx)
2428 IStream_Release((IStream*)ctx);
2429 return 0;
2432 static HRESULT WINAPI domdoc_save(
2433 IXMLDOMDocument3 *iface,
2434 VARIANT destination )
2436 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2437 xmlSaveCtxtPtr ctx = NULL;
2438 xmlNodePtr xmldecl;
2439 HRESULT ret = S_OK;
2441 TRACE("(%p)->(%s)\n", This, debugstr_variant(&destination));
2443 switch (V_VT(&destination))
2445 case VT_UNKNOWN:
2447 IUnknown *pUnk = V_UNKNOWN(&destination);
2448 IXMLDOMDocument3 *document;
2449 IStream *stream;
2451 ret = IUnknown_QueryInterface(pUnk, &IID_IXMLDOMDocument3, (void**)&document);
2452 if(ret == S_OK)
2454 VARIANT_BOOL success;
2455 BSTR xml;
2457 ret = IXMLDOMDocument3_get_xml(iface, &xml);
2458 if(ret == S_OK)
2460 ret = IXMLDOMDocument3_loadXML(document, xml, &success);
2461 SysFreeString(xml);
2464 IXMLDOMDocument3_Release(document);
2465 return ret;
2468 ret = IUnknown_QueryInterface(pUnk, &IID_IStream, (void**)&stream);
2469 if(ret == S_OK)
2471 int options = get_doc(This)->standalone == -1 ? XML_SAVE_NO_DECL : 0;
2472 ctx = xmlSaveToIO(domdoc_stream_save_writecallback,
2473 domdoc_stream_save_closecallback, stream, NULL, options);
2475 if(!ctx)
2477 IStream_Release(stream);
2478 return E_FAIL;
2482 break;
2484 case VT_BSTR:
2485 case VT_BSTR | VT_BYREF:
2487 int options = get_doc(This)->standalone == -1 ? XML_SAVE_NO_DECL : 0;
2489 /* save with file path */
2490 HANDLE handle = CreateFileW( (V_VT(&destination) & VT_BYREF)? *V_BSTRREF(&destination) : V_BSTR(&destination),
2491 GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL );
2492 if( handle == INVALID_HANDLE_VALUE )
2494 WARN("failed to create file\n");
2495 return E_FAIL;
2498 /* disable top XML declaration */
2499 ctx = xmlSaveToIO(domdoc_save_writecallback, domdoc_save_closecallback,
2500 handle, NULL, options);
2501 if (!ctx)
2503 CloseHandle(handle);
2504 return E_FAIL;
2507 break;
2509 default:
2510 FIXME("Unhandled VARIANT: %s\n", debugstr_variant(&destination));
2511 return S_FALSE;
2514 xmldecl = xmldoc_unlink_xmldecl(get_doc(This));
2515 if (xmlSaveDoc(ctx, get_doc(This)) == -1) ret = S_FALSE;
2516 xmldoc_link_xmldecl(get_doc(This), xmldecl);
2518 /* will release resources through close callback */
2519 xmlSaveClose(ctx);
2521 return ret;
2524 static HRESULT WINAPI domdoc_get_validateOnParse(
2525 IXMLDOMDocument3 *iface,
2526 VARIANT_BOOL* isValidating )
2528 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2529 TRACE("(%p)->(%p: %d)\n", This, isValidating, This->validating);
2530 *isValidating = This->validating;
2531 return S_OK;
2535 static HRESULT WINAPI domdoc_put_validateOnParse(
2536 IXMLDOMDocument3 *iface,
2537 VARIANT_BOOL isValidating )
2539 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2540 TRACE("(%p)->(%d)\n", This, isValidating);
2541 This->validating = isValidating;
2542 return S_OK;
2546 static HRESULT WINAPI domdoc_get_resolveExternals(
2547 IXMLDOMDocument3 *iface,
2548 VARIANT_BOOL* isResolving )
2550 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2551 TRACE("(%p)->(%p: %d)\n", This, isResolving, This->resolving);
2552 *isResolving = This->resolving;
2553 return S_OK;
2557 static HRESULT WINAPI domdoc_put_resolveExternals(
2558 IXMLDOMDocument3 *iface,
2559 VARIANT_BOOL isResolving )
2561 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2562 TRACE("(%p)->(%d)\n", This, isResolving);
2563 This->resolving = isResolving;
2564 return S_OK;
2568 static HRESULT WINAPI domdoc_get_preserveWhiteSpace(
2569 IXMLDOMDocument3 *iface,
2570 VARIANT_BOOL* isPreserving )
2572 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2573 TRACE("(%p)->(%p: %d)\n", This, isPreserving, This->properties->preserving);
2574 *isPreserving = This->properties->preserving;
2575 return S_OK;
2579 static HRESULT WINAPI domdoc_put_preserveWhiteSpace(
2580 IXMLDOMDocument3 *iface,
2581 VARIANT_BOOL isPreserving )
2583 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2584 TRACE("(%p)->(%d)\n", This, isPreserving);
2585 This->properties->preserving = isPreserving;
2586 return S_OK;
2590 static HRESULT WINAPI domdoc_put_onreadystatechange(
2591 IXMLDOMDocument3 *iface,
2592 VARIANT event )
2594 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2596 TRACE("(%p)->(%s)\n", This, debugstr_variant(&event));
2597 return set_doc_event(This, EVENTID_READYSTATECHANGE, &event);
2601 static HRESULT WINAPI domdoc_put_onDataAvailable(IXMLDOMDocument3 *iface, VARIANT sink)
2603 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2604 FIXME("(%p)->(%s): stub\n", This, debugstr_variant(&sink));
2605 return E_NOTIMPL;
2608 static HRESULT WINAPI domdoc_put_onTransformNode(IXMLDOMDocument3 *iface, VARIANT sink )
2610 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2611 FIXME("(%p)->(%s): stub\n", This, debugstr_variant(&sink));
2612 return E_NOTIMPL;
2615 static HRESULT WINAPI domdoc_get_namespaces(
2616 IXMLDOMDocument3* iface,
2617 IXMLDOMSchemaCollection** collection )
2619 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2620 HRESULT hr;
2622 FIXME("(%p)->(%p): semi-stub\n", This, collection);
2624 if (!collection) return E_POINTER;
2626 if (!This->namespaces)
2628 hr = SchemaCache_create(This->properties->version, (void**)&This->namespaces);
2629 if (hr != S_OK) return hr;
2631 hr = cache_from_doc_ns(This->namespaces, &This->node);
2632 if (hr != S_OK)
2633 release_namespaces(This);
2636 if (This->namespaces)
2637 return IXMLDOMSchemaCollection2_QueryInterface(This->namespaces,
2638 &IID_IXMLDOMSchemaCollection, (void**)collection);
2640 return hr;
2643 static HRESULT WINAPI domdoc_get_schemas(
2644 IXMLDOMDocument3* iface,
2645 VARIANT* schema )
2647 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2648 IXMLDOMSchemaCollection2* cur_schema = This->properties->schemaCache;
2649 HRESULT hr = S_FALSE;
2651 TRACE("(%p)->(%p)\n", This, schema);
2653 V_VT(schema) = VT_NULL;
2654 /* just to reset pointer part, cause that's what application is expected to use */
2655 V_DISPATCH(schema) = NULL;
2657 if(cur_schema)
2659 hr = IXMLDOMSchemaCollection2_QueryInterface(cur_schema, &IID_IDispatch, (void**)&V_DISPATCH(schema));
2660 if(SUCCEEDED(hr))
2661 V_VT(schema) = VT_DISPATCH;
2663 return hr;
2666 static HRESULT WINAPI domdoc_putref_schemas(
2667 IXMLDOMDocument3* iface,
2668 VARIANT schema)
2670 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2671 HRESULT hr = E_FAIL;
2672 IXMLDOMSchemaCollection2* new_schema = NULL;
2674 FIXME("(%p)->(%s): semi-stub\n", This, debugstr_variant(&schema));
2675 switch(V_VT(&schema))
2677 case VT_UNKNOWN:
2678 if (V_UNKNOWN(&schema))
2680 hr = IUnknown_QueryInterface(V_UNKNOWN(&schema), &IID_IXMLDOMSchemaCollection, (void**)&new_schema);
2681 break;
2683 /* fallthrough */
2684 case VT_DISPATCH:
2685 if (V_DISPATCH(&schema))
2687 hr = IDispatch_QueryInterface(V_DISPATCH(&schema), &IID_IXMLDOMSchemaCollection, (void**)&new_schema);
2688 break;
2690 /* fallthrough */
2691 case VT_NULL:
2692 case VT_EMPTY:
2693 hr = S_OK;
2694 break;
2696 default:
2697 WARN("Can't get schema from vt %x\n", V_VT(&schema));
2700 if(SUCCEEDED(hr))
2702 IXMLDOMSchemaCollection2* old_schema = InterlockedExchangePointer((void**)&This->properties->schemaCache, new_schema);
2703 if(old_schema) IXMLDOMSchemaCollection2_Release(old_schema);
2706 return hr;
2709 static inline BOOL is_wellformed(xmlDocPtr doc)
2711 #ifdef HAVE_XMLDOC_PROPERTIES
2712 return doc->properties & XML_DOC_WELLFORMED;
2713 #else
2714 /* Not a full check, but catches the worst violations */
2715 xmlNodePtr child;
2716 int root = 0;
2718 for (child = doc->children; child != NULL; child = child->next)
2720 switch (child->type)
2722 case XML_ELEMENT_NODE:
2723 if (++root > 1)
2724 return FALSE;
2725 break;
2726 case XML_TEXT_NODE:
2727 case XML_CDATA_SECTION_NODE:
2728 return FALSE;
2729 break;
2730 default:
2731 break;
2735 return root == 1;
2736 #endif
2739 static void LIBXML2_LOG_CALLBACK validate_error(void* ctx, char const* msg, ...)
2741 va_list ap;
2742 va_start(ap, msg);
2743 LIBXML2_CALLBACK_ERR(domdoc_validateNode, msg, ap);
2744 va_end(ap);
2747 static void LIBXML2_LOG_CALLBACK validate_warning(void* ctx, char const* msg, ...)
2749 va_list ap;
2750 va_start(ap, msg);
2751 LIBXML2_CALLBACK_WARN(domdoc_validateNode, msg, ap);
2752 va_end(ap);
2755 static HRESULT WINAPI domdoc_validateNode(
2756 IXMLDOMDocument3* iface,
2757 IXMLDOMNode* node,
2758 IXMLDOMParseError** err)
2760 domdoc* This = impl_from_IXMLDOMDocument3(iface);
2761 LONG state, err_code = 0;
2762 HRESULT hr = S_OK;
2763 int validated = 0;
2765 TRACE("(%p)->(%p, %p)\n", This, node, err);
2766 IXMLDOMDocument3_get_readyState(iface, &state);
2767 if (state != READYSTATE_COMPLETE)
2769 if (err)
2770 *err = create_parseError(err_code, NULL, NULL, NULL, 0, 0, 0);
2771 return E_PENDING;
2774 if (!node)
2776 if (err)
2777 *err = create_parseError(err_code, NULL, NULL, NULL, 0, 0, 0);
2778 return E_POINTER;
2781 if (!get_node_obj(node)->node || get_node_obj(node)->node->doc != get_doc(This))
2783 if (err)
2784 *err = create_parseError(err_code, NULL, NULL, NULL, 0, 0, 0);
2785 return E_FAIL;
2788 if (!is_wellformed(get_doc(This)))
2790 ERR("doc not well-formed\n");
2791 if (err)
2792 *err = create_parseError(E_XML_NOTWF, NULL, NULL, NULL, 0, 0, 0);
2793 return S_FALSE;
2796 /* DTD validation */
2797 if (get_doc(This)->intSubset || get_doc(This)->extSubset)
2799 xmlValidCtxtPtr vctx = xmlNewValidCtxt();
2800 vctx->error = validate_error;
2801 vctx->warning = validate_warning;
2802 ++validated;
2804 if (!((node == (IXMLDOMNode*)iface)?
2805 xmlValidateDocument(vctx, get_doc(This)) :
2806 xmlValidateElement(vctx, get_doc(This), get_node_obj(node)->node)))
2808 /* TODO: get a real error code here */
2809 TRACE("DTD validation failed\n");
2810 err_code = E_XML_INVALID;
2811 hr = S_FALSE;
2813 xmlFreeValidCtxt(vctx);
2816 /* Schema validation */
2817 if (hr == S_OK && This->properties->schemaCache != NULL)
2820 hr = SchemaCache_validate_tree(This->properties->schemaCache, get_node_obj(node)->node);
2821 if (SUCCEEDED(hr))
2823 ++validated;
2824 /* TODO: get a real error code here */
2825 if (hr == S_OK)
2827 TRACE("schema validation succeeded\n");
2829 else
2831 ERR("schema validation failed\n");
2832 err_code = E_XML_INVALID;
2835 else
2837 /* not really OK, just didn't find a schema for the ns */
2838 hr = S_OK;
2842 if (!validated)
2844 ERR("no DTD or schema found\n");
2845 err_code = E_XML_NODTD;
2846 hr = S_FALSE;
2849 if (err)
2850 *err = create_parseError(err_code, NULL, NULL, NULL, 0, 0, 0);
2852 return hr;
2855 static HRESULT WINAPI domdoc_validate(
2856 IXMLDOMDocument3* iface,
2857 IXMLDOMParseError** err)
2859 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2860 TRACE("(%p)->(%p)\n", This, err);
2861 return IXMLDOMDocument3_validateNode(iface, (IXMLDOMNode*)iface, err);
2864 static HRESULT WINAPI domdoc_setProperty(
2865 IXMLDOMDocument3* iface,
2866 BSTR p,
2867 VARIANT value)
2869 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2871 TRACE("(%p)->(%s %s)\n", This, debugstr_w(p), debugstr_variant(&value));
2873 if (lstrcmpiW(p, PropertySelectionLanguageW) == 0)
2875 VARIANT varStr;
2876 HRESULT hr;
2877 BSTR bstr;
2879 V_VT(&varStr) = VT_EMPTY;
2880 if (V_VT(&value) != VT_BSTR)
2882 if (FAILED(hr = VariantChangeType(&varStr, &value, 0, VT_BSTR)))
2883 return hr;
2884 bstr = V_BSTR(&varStr);
2886 else
2887 bstr = V_BSTR(&value);
2889 hr = S_OK;
2890 if (lstrcmpiW(bstr, PropValueXPathW) == 0)
2891 This->properties->XPath = TRUE;
2892 else if (lstrcmpiW(bstr, PropValueXSLPatternW) == 0)
2893 This->properties->XPath = FALSE;
2894 else
2895 hr = E_FAIL;
2897 VariantClear(&varStr);
2898 return hr;
2900 else if (lstrcmpiW(p, PropertySelectionNamespacesW) == 0)
2902 xmlChar *nsStr = (xmlChar*)This->properties->selectNsStr;
2903 struct list *pNsList;
2904 VARIANT varStr;
2905 HRESULT hr;
2906 BSTR bstr;
2908 V_VT(&varStr) = VT_EMPTY;
2909 if (V_VT(&value) != VT_BSTR)
2911 if (FAILED(hr = VariantChangeType(&varStr, &value, 0, VT_BSTR)))
2912 return hr;
2913 bstr = V_BSTR(&varStr);
2915 else
2916 bstr = V_BSTR(&value);
2918 hr = S_OK;
2920 pNsList = &(This->properties->selectNsList);
2921 clear_selectNsList(pNsList);
2922 heap_free(nsStr);
2923 nsStr = xmlchar_from_wchar(bstr);
2925 TRACE("property value: \"%s\"\n", debugstr_w(bstr));
2927 This->properties->selectNsStr = nsStr;
2928 This->properties->selectNsStr_len = xmlStrlen(nsStr);
2929 if (bstr && *bstr)
2931 xmlChar *pTokBegin, *pTokEnd, *pTokInner;
2932 select_ns_entry* ns_entry = NULL;
2933 xmlXPathContextPtr ctx;
2935 ctx = xmlXPathNewContext(This->node.node->doc);
2936 pTokBegin = nsStr;
2938 /* skip leading spaces */
2939 while (*pTokBegin == ' ' || *pTokBegin == '\n' ||
2940 *pTokBegin == '\t' || *pTokBegin == '\r')
2941 ++pTokBegin;
2943 for (; *pTokBegin; pTokBegin = pTokEnd)
2945 if (ns_entry)
2946 memset(ns_entry, 0, sizeof(select_ns_entry));
2947 else
2948 ns_entry = heap_alloc_zero(sizeof(select_ns_entry));
2950 while (*pTokBegin == ' ')
2951 ++pTokBegin;
2952 pTokEnd = pTokBegin;
2953 while (*pTokEnd != ' ' && *pTokEnd != 0)
2954 ++pTokEnd;
2956 /* so it failed to advance which means we've got some trailing spaces */
2957 if (pTokEnd == pTokBegin) break;
2959 if (xmlStrncmp(pTokBegin, (xmlChar const*)"xmlns", 5) != 0)
2961 hr = E_FAIL;
2962 WARN("Syntax error in xmlns string: %s\n\tat token: %s\n",
2963 debugstr_w(bstr), debugstr_an((const char*)pTokBegin, pTokEnd-pTokBegin));
2964 continue;
2967 pTokBegin += 5;
2968 if (*pTokBegin == '=')
2970 /*valid for XSLPattern?*/
2971 FIXME("Setting default xmlns not supported - skipping.\n");
2972 continue;
2974 else if (*pTokBegin == ':')
2976 ns_entry->prefix = ++pTokBegin;
2977 for (pTokInner = pTokBegin; pTokInner != pTokEnd && *pTokInner != '='; ++pTokInner)
2980 if (pTokInner == pTokEnd)
2982 hr = E_FAIL;
2983 WARN("Syntax error in xmlns string: %s\n\tat token: %s\n",
2984 debugstr_w(bstr), debugstr_an((const char*)pTokBegin, pTokEnd-pTokBegin));
2985 continue;
2988 ns_entry->prefix_end = *pTokInner;
2989 *pTokInner = 0;
2990 ++pTokInner;
2992 if (pTokEnd-pTokInner > 1 &&
2993 ((*pTokInner == '\'' && *(pTokEnd-1) == '\'') ||
2994 (*pTokInner == '"' && *(pTokEnd-1) == '"')))
2996 ns_entry->href = ++pTokInner;
2997 ns_entry->href_end = *(pTokEnd-1);
2998 *(pTokEnd-1) = 0;
2999 list_add_tail(pNsList, &ns_entry->entry);
3000 /*let libxml figure out if they're valid from here ;)*/
3001 if (xmlXPathRegisterNs(ctx, ns_entry->prefix, ns_entry->href) != 0)
3003 hr = E_FAIL;
3005 ns_entry = NULL;
3006 continue;
3008 else
3010 WARN("Syntax error in xmlns string: %s\n\tat token: %s\n",
3011 debugstr_w(bstr), debugstr_an((const char*)pTokInner, pTokEnd-pTokInner));
3012 list_add_tail(pNsList, &ns_entry->entry);
3014 ns_entry = NULL;
3015 hr = E_FAIL;
3016 continue;
3019 else
3021 hr = E_FAIL;
3022 continue;
3025 heap_free(ns_entry);
3026 xmlXPathFreeContext(ctx);
3029 VariantClear(&varStr);
3030 return hr;
3032 else if (lstrcmpiW(p, PropertyProhibitDTDW) == 0 ||
3033 lstrcmpiW(p, PropertyNewParserW) == 0 ||
3034 lstrcmpiW(p, PropertyResolveExternalsW) == 0)
3036 /* Ignore */
3037 FIXME("Ignoring property %s, value %s\n", debugstr_w(p), debugstr_variant(&value));
3038 return S_OK;
3041 FIXME("Unknown property %s\n", debugstr_w(p));
3042 return E_FAIL;
3045 static HRESULT WINAPI domdoc_getProperty(
3046 IXMLDOMDocument3* iface,
3047 BSTR p,
3048 VARIANT* var)
3050 domdoc *This = impl_from_IXMLDOMDocument3( iface );
3052 TRACE("(%p)->(%s)\n", This, debugstr_w(p));
3054 if (!var)
3055 return E_INVALIDARG;
3057 if (lstrcmpiW(p, PropertySelectionLanguageW) == 0)
3059 V_VT(var) = VT_BSTR;
3060 V_BSTR(var) = This->properties->XPath ?
3061 SysAllocString(PropValueXPathW) :
3062 SysAllocString(PropValueXSLPatternW);
3063 return V_BSTR(var) ? S_OK : E_OUTOFMEMORY;
3065 else if (lstrcmpiW(p, PropertySelectionNamespacesW) == 0)
3067 int lenA, lenW;
3068 BSTR rebuiltStr, cur;
3069 const xmlChar *nsStr;
3070 struct list *pNsList;
3071 select_ns_entry* pNsEntry;
3073 V_VT(var) = VT_BSTR;
3074 nsStr = This->properties->selectNsStr;
3075 pNsList = &This->properties->selectNsList;
3076 lenA = This->properties->selectNsStr_len;
3077 lenW = MultiByteToWideChar(CP_UTF8, 0, (LPCSTR)nsStr, lenA+1, NULL, 0);
3078 rebuiltStr = heap_alloc(lenW*sizeof(WCHAR));
3079 MultiByteToWideChar(CP_UTF8, 0, (LPCSTR)nsStr, lenA+1, rebuiltStr, lenW);
3080 cur = rebuiltStr;
3081 /* this is fine because all of the chars that end tokens are ASCII*/
3082 LIST_FOR_EACH_ENTRY(pNsEntry, pNsList, select_ns_entry, entry)
3084 while (*cur != 0) ++cur;
3085 if (pNsEntry->prefix_end)
3087 *cur = pNsEntry->prefix_end;
3088 while (*cur != 0) ++cur;
3091 if (pNsEntry->href_end)
3093 *cur = pNsEntry->href_end;
3096 V_BSTR(var) = SysAllocString(rebuiltStr);
3097 heap_free(rebuiltStr);
3098 return S_OK;
3101 FIXME("Unknown property %s\n", debugstr_w(p));
3102 return E_FAIL;
3105 static HRESULT WINAPI domdoc_importNode(
3106 IXMLDOMDocument3* iface,
3107 IXMLDOMNode* node,
3108 VARIANT_BOOL deep,
3109 IXMLDOMNode** clone)
3111 domdoc *This = impl_from_IXMLDOMDocument3( iface );
3112 FIXME("(%p)->(%p %d %p): stub\n", This, node, deep, clone);
3113 return E_NOTIMPL;
3116 static const struct IXMLDOMDocument3Vtbl XMLDOMDocument3Vtbl =
3118 domdoc_QueryInterface,
3119 domdoc_AddRef,
3120 domdoc_Release,
3121 domdoc_GetTypeInfoCount,
3122 domdoc_GetTypeInfo,
3123 domdoc_GetIDsOfNames,
3124 domdoc_Invoke,
3125 domdoc_get_nodeName,
3126 domdoc_get_nodeValue,
3127 domdoc_put_nodeValue,
3128 domdoc_get_nodeType,
3129 domdoc_get_parentNode,
3130 domdoc_get_childNodes,
3131 domdoc_get_firstChild,
3132 domdoc_get_lastChild,
3133 domdoc_get_previousSibling,
3134 domdoc_get_nextSibling,
3135 domdoc_get_attributes,
3136 domdoc_insertBefore,
3137 domdoc_replaceChild,
3138 domdoc_removeChild,
3139 domdoc_appendChild,
3140 domdoc_hasChildNodes,
3141 domdoc_get_ownerDocument,
3142 domdoc_cloneNode,
3143 domdoc_get_nodeTypeString,
3144 domdoc_get_text,
3145 domdoc_put_text,
3146 domdoc_get_specified,
3147 domdoc_get_definition,
3148 domdoc_get_nodeTypedValue,
3149 domdoc_put_nodeTypedValue,
3150 domdoc_get_dataType,
3151 domdoc_put_dataType,
3152 domdoc_get_xml,
3153 domdoc_transformNode,
3154 domdoc_selectNodes,
3155 domdoc_selectSingleNode,
3156 domdoc_get_parsed,
3157 domdoc_get_namespaceURI,
3158 domdoc_get_prefix,
3159 domdoc_get_baseName,
3160 domdoc_transformNodeToObject,
3161 domdoc_get_doctype,
3162 domdoc_get_implementation,
3163 domdoc_get_documentElement,
3164 domdoc_put_documentElement,
3165 domdoc_createElement,
3166 domdoc_createDocumentFragment,
3167 domdoc_createTextNode,
3168 domdoc_createComment,
3169 domdoc_createCDATASection,
3170 domdoc_createProcessingInstruction,
3171 domdoc_createAttribute,
3172 domdoc_createEntityReference,
3173 domdoc_getElementsByTagName,
3174 domdoc_createNode,
3175 domdoc_nodeFromID,
3176 domdoc_load,
3177 domdoc_get_readyState,
3178 domdoc_get_parseError,
3179 domdoc_get_url,
3180 domdoc_get_async,
3181 domdoc_put_async,
3182 domdoc_abort,
3183 domdoc_loadXML,
3184 domdoc_save,
3185 domdoc_get_validateOnParse,
3186 domdoc_put_validateOnParse,
3187 domdoc_get_resolveExternals,
3188 domdoc_put_resolveExternals,
3189 domdoc_get_preserveWhiteSpace,
3190 domdoc_put_preserveWhiteSpace,
3191 domdoc_put_onreadystatechange,
3192 domdoc_put_onDataAvailable,
3193 domdoc_put_onTransformNode,
3194 domdoc_get_namespaces,
3195 domdoc_get_schemas,
3196 domdoc_putref_schemas,
3197 domdoc_validate,
3198 domdoc_setProperty,
3199 domdoc_getProperty,
3200 domdoc_validateNode,
3201 domdoc_importNode
3204 /* IConnectionPointContainer */
3205 static HRESULT WINAPI ConnectionPointContainer_QueryInterface(IConnectionPointContainer *iface,
3206 REFIID riid, void **ppv)
3208 domdoc *This = impl_from_IConnectionPointContainer(iface);
3209 return IXMLDOMDocument3_QueryInterface(&This->IXMLDOMDocument3_iface, riid, ppv);
3212 static ULONG WINAPI ConnectionPointContainer_AddRef(IConnectionPointContainer *iface)
3214 domdoc *This = impl_from_IConnectionPointContainer(iface);
3215 return IXMLDOMDocument3_AddRef(&This->IXMLDOMDocument3_iface);
3218 static ULONG WINAPI ConnectionPointContainer_Release(IConnectionPointContainer *iface)
3220 domdoc *This = impl_from_IConnectionPointContainer(iface);
3221 return IXMLDOMDocument3_Release(&This->IXMLDOMDocument3_iface);
3224 static HRESULT WINAPI ConnectionPointContainer_EnumConnectionPoints(IConnectionPointContainer *iface,
3225 IEnumConnectionPoints **ppEnum)
3227 domdoc *This = impl_from_IConnectionPointContainer(iface);
3228 FIXME("(%p)->(%p): stub\n", This, ppEnum);
3229 return E_NOTIMPL;
3232 static HRESULT WINAPI ConnectionPointContainer_FindConnectionPoint(IConnectionPointContainer *iface,
3233 REFIID riid, IConnectionPoint **cp)
3235 domdoc *This = impl_from_IConnectionPointContainer(iface);
3236 ConnectionPoint *iter;
3238 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), cp);
3240 *cp = NULL;
3242 for(iter = This->cp_list; iter; iter = iter->next)
3244 if (IsEqualGUID(iter->iid, riid))
3245 *cp = &iter->IConnectionPoint_iface;
3248 if (*cp)
3250 IConnectionPoint_AddRef(*cp);
3251 return S_OK;
3254 FIXME("unsupported riid %s\n", debugstr_guid(riid));
3255 return CONNECT_E_NOCONNECTION;
3259 static const struct IConnectionPointContainerVtbl ConnectionPointContainerVtbl =
3261 ConnectionPointContainer_QueryInterface,
3262 ConnectionPointContainer_AddRef,
3263 ConnectionPointContainer_Release,
3264 ConnectionPointContainer_EnumConnectionPoints,
3265 ConnectionPointContainer_FindConnectionPoint
3268 /* IConnectionPoint */
3269 static HRESULT WINAPI ConnectionPoint_QueryInterface(IConnectionPoint *iface,
3270 REFIID riid, void **ppv)
3272 ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3274 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv );
3276 *ppv = NULL;
3278 if (IsEqualGUID(&IID_IUnknown, riid) ||
3279 IsEqualGUID(&IID_IConnectionPoint, riid))
3281 *ppv = iface;
3284 if (*ppv)
3286 IConnectionPoint_AddRef(iface);
3287 return S_OK;
3290 WARN("Unsupported interface %s\n", debugstr_guid(riid));
3291 return E_NOINTERFACE;
3294 static ULONG WINAPI ConnectionPoint_AddRef(IConnectionPoint *iface)
3296 ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3297 return IConnectionPointContainer_AddRef(This->container);
3300 static ULONG WINAPI ConnectionPoint_Release(IConnectionPoint *iface)
3302 ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3303 return IConnectionPointContainer_Release(This->container);
3306 static HRESULT WINAPI ConnectionPoint_GetConnectionInterface(IConnectionPoint *iface, IID *iid)
3308 ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3310 TRACE("(%p)->(%p)\n", This, iid);
3312 if (!iid) return E_POINTER;
3314 *iid = *This->iid;
3315 return S_OK;
3318 static HRESULT WINAPI ConnectionPoint_GetConnectionPointContainer(IConnectionPoint *iface,
3319 IConnectionPointContainer **container)
3321 ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3323 TRACE("(%p)->(%p)\n", This, container);
3325 if (!container) return E_POINTER;
3327 *container = This->container;
3328 IConnectionPointContainer_AddRef(*container);
3329 return S_OK;
3332 static HRESULT WINAPI ConnectionPoint_Advise(IConnectionPoint *iface, IUnknown *unk_sink,
3333 DWORD *cookie)
3335 ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3336 IUnknown *sink;
3337 HRESULT hr;
3338 DWORD i;
3340 TRACE("(%p)->(%p %p)\n", This, unk_sink, cookie);
3342 hr = IUnknown_QueryInterface(unk_sink, This->iid, (void**)&sink);
3343 if(FAILED(hr) && !IsEqualGUID(&IID_IPropertyNotifySink, This->iid))
3344 hr = IUnknown_QueryInterface(unk_sink, &IID_IDispatch, (void**)&sink);
3345 if(FAILED(hr))
3346 return CONNECT_E_CANNOTCONNECT;
3348 if(This->sinks)
3350 for (i = 0; i < This->sinks_size; i++)
3351 if (!This->sinks[i].unk)
3352 break;
3354 if (i == This->sinks_size)
3355 This->sinks = heap_realloc(This->sinks,(++This->sinks_size)*sizeof(*This->sinks));
3357 else
3359 This->sinks = heap_alloc(sizeof(*This->sinks));
3360 This->sinks_size = 1;
3361 i = 0;
3364 This->sinks[i].unk = sink;
3365 if (cookie)
3366 *cookie = i+1;
3368 return S_OK;
3371 static HRESULT WINAPI ConnectionPoint_Unadvise(IConnectionPoint *iface, DWORD cookie)
3373 ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3375 TRACE("(%p)->(%d)\n", This, cookie);
3377 if (cookie == 0 || cookie > This->sinks_size || !This->sinks[cookie-1].unk)
3378 return CONNECT_E_NOCONNECTION;
3380 IUnknown_Release(This->sinks[cookie-1].unk);
3381 This->sinks[cookie-1].unk = NULL;
3383 return S_OK;
3386 static HRESULT WINAPI ConnectionPoint_EnumConnections(IConnectionPoint *iface,
3387 IEnumConnections **ppEnum)
3389 ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3390 FIXME("(%p)->(%p): stub\n", This, ppEnum);
3391 return E_NOTIMPL;
3394 static const IConnectionPointVtbl ConnectionPointVtbl =
3396 ConnectionPoint_QueryInterface,
3397 ConnectionPoint_AddRef,
3398 ConnectionPoint_Release,
3399 ConnectionPoint_GetConnectionInterface,
3400 ConnectionPoint_GetConnectionPointContainer,
3401 ConnectionPoint_Advise,
3402 ConnectionPoint_Unadvise,
3403 ConnectionPoint_EnumConnections
3406 static void ConnectionPoint_Init(ConnectionPoint *cp, struct domdoc *doc, REFIID riid)
3408 cp->IConnectionPoint_iface.lpVtbl = &ConnectionPointVtbl;
3409 cp->doc = doc;
3410 cp->iid = riid;
3411 cp->sinks = NULL;
3412 cp->sinks_size = 0;
3414 cp->next = doc->cp_list;
3415 doc->cp_list = cp;
3417 cp->container = &doc->IConnectionPointContainer_iface;
3420 /* domdoc implementation of IObjectWithSite */
3421 static HRESULT WINAPI
3422 domdoc_ObjectWithSite_QueryInterface( IObjectWithSite* iface, REFIID riid, void** ppvObject )
3424 domdoc *This = impl_from_IObjectWithSite(iface);
3425 return IXMLDOMDocument3_QueryInterface(&This->IXMLDOMDocument3_iface, riid, ppvObject);
3428 static ULONG WINAPI domdoc_ObjectWithSite_AddRef( IObjectWithSite* iface )
3430 domdoc *This = impl_from_IObjectWithSite(iface);
3431 return IXMLDOMDocument3_AddRef(&This->IXMLDOMDocument3_iface);
3434 static ULONG WINAPI domdoc_ObjectWithSite_Release( IObjectWithSite* iface )
3436 domdoc *This = impl_from_IObjectWithSite(iface);
3437 return IXMLDOMDocument3_Release(&This->IXMLDOMDocument3_iface);
3440 static HRESULT WINAPI domdoc_ObjectWithSite_GetSite( IObjectWithSite *iface, REFIID iid, void **ppvSite )
3442 domdoc *This = impl_from_IObjectWithSite(iface);
3444 TRACE("(%p)->(%s %p)\n", This, debugstr_guid( iid ), ppvSite );
3446 if ( !This->site )
3447 return E_FAIL;
3449 return IUnknown_QueryInterface( This->site, iid, ppvSite );
3452 static HRESULT WINAPI domdoc_ObjectWithSite_SetSite( IObjectWithSite *iface, IUnknown *punk )
3454 domdoc *This = impl_from_IObjectWithSite(iface);
3456 TRACE("(%p)->(%p)\n", iface, punk);
3458 if(!punk)
3460 if(This->site)
3462 IUnknown_Release( This->site );
3463 This->site = NULL;
3466 return S_OK;
3469 IUnknown_AddRef( punk );
3471 if(This->site)
3472 IUnknown_Release( This->site );
3474 This->site = punk;
3476 return S_OK;
3479 static const IObjectWithSiteVtbl domdocObjectSite =
3481 domdoc_ObjectWithSite_QueryInterface,
3482 domdoc_ObjectWithSite_AddRef,
3483 domdoc_ObjectWithSite_Release,
3484 domdoc_ObjectWithSite_SetSite,
3485 domdoc_ObjectWithSite_GetSite
3488 static HRESULT WINAPI domdoc_Safety_QueryInterface(IObjectSafety *iface, REFIID riid, void **ppv)
3490 domdoc *This = impl_from_IObjectSafety(iface);
3491 return IXMLDOMDocument3_QueryInterface(&This->IXMLDOMDocument3_iface, riid, ppv);
3494 static ULONG WINAPI domdoc_Safety_AddRef(IObjectSafety *iface)
3496 domdoc *This = impl_from_IObjectSafety(iface);
3497 return IXMLDOMDocument3_AddRef(&This->IXMLDOMDocument3_iface);
3500 static ULONG WINAPI domdoc_Safety_Release(IObjectSafety *iface)
3502 domdoc *This = impl_from_IObjectSafety(iface);
3503 return IXMLDOMDocument3_Release(&This->IXMLDOMDocument3_iface);
3506 #define SAFETY_SUPPORTED_OPTIONS (INTERFACESAFE_FOR_UNTRUSTED_CALLER|INTERFACESAFE_FOR_UNTRUSTED_DATA|INTERFACE_USES_SECURITY_MANAGER)
3508 static HRESULT WINAPI domdoc_Safety_GetInterfaceSafetyOptions(IObjectSafety *iface, REFIID riid,
3509 DWORD *supported, DWORD *enabled)
3511 domdoc *This = impl_from_IObjectSafety(iface);
3513 TRACE("(%p)->(%s %p %p)\n", This, debugstr_guid(riid), supported, enabled);
3515 if(!supported || !enabled) return E_POINTER;
3517 *supported = SAFETY_SUPPORTED_OPTIONS;
3518 *enabled = This->safeopt;
3520 return S_OK;
3523 static HRESULT WINAPI domdoc_Safety_SetInterfaceSafetyOptions(IObjectSafety *iface, REFIID riid,
3524 DWORD mask, DWORD enabled)
3526 domdoc *This = impl_from_IObjectSafety(iface);
3527 TRACE("(%p)->(%s %x %x)\n", This, debugstr_guid(riid), mask, enabled);
3529 if ((mask & ~SAFETY_SUPPORTED_OPTIONS) != 0)
3530 return E_FAIL;
3532 This->safeopt = (This->safeopt & ~mask) | (mask & enabled);
3534 return S_OK;
3537 #undef SAFETY_SUPPORTED_OPTIONS
3539 static const IObjectSafetyVtbl domdocObjectSafetyVtbl = {
3540 domdoc_Safety_QueryInterface,
3541 domdoc_Safety_AddRef,
3542 domdoc_Safety_Release,
3543 domdoc_Safety_GetInterfaceSafetyOptions,
3544 domdoc_Safety_SetInterfaceSafetyOptions
3547 static const tid_t domdoc_iface_tids[] = {
3548 IXMLDOMDocument3_tid,
3552 static dispex_static_data_t domdoc_dispex = {
3553 NULL,
3554 IXMLDOMDocument3_tid,
3555 NULL,
3556 domdoc_iface_tids
3559 HRESULT get_domdoc_from_xmldoc(xmlDocPtr xmldoc, IXMLDOMDocument3 **document)
3561 domdoc *doc;
3563 doc = heap_alloc( sizeof (*doc) );
3564 if( !doc )
3565 return E_OUTOFMEMORY;
3567 doc->IXMLDOMDocument3_iface.lpVtbl = &XMLDOMDocument3Vtbl;
3568 doc->IPersistStreamInit_iface.lpVtbl = &xmldoc_IPersistStreamInit_VTable;
3569 doc->IObjectWithSite_iface.lpVtbl = &domdocObjectSite;
3570 doc->IObjectSafety_iface.lpVtbl = &domdocObjectSafetyVtbl;
3571 doc->IConnectionPointContainer_iface.lpVtbl = &ConnectionPointContainerVtbl;
3572 doc->ref = 1;
3573 doc->async = VARIANT_TRUE;
3574 doc->validating = 0;
3575 doc->resolving = 0;
3576 doc->properties = properties_from_xmlDocPtr(xmldoc);
3577 doc->error = S_OK;
3578 doc->site = NULL;
3579 doc->safeopt = 0;
3580 doc->cp_list = NULL;
3581 doc->namespaces = NULL;
3582 memset(doc->events, 0, sizeof(doc->events));
3584 /* events connection points */
3585 ConnectionPoint_Init(&doc->cp_dispatch, doc, &IID_IDispatch);
3586 ConnectionPoint_Init(&doc->cp_propnotif, doc, &IID_IPropertyNotifySink);
3587 ConnectionPoint_Init(&doc->cp_domdocevents, doc, &DIID_XMLDOMDocumentEvents);
3589 init_xmlnode(&doc->node, (xmlNodePtr)xmldoc, (IXMLDOMNode*)&doc->IXMLDOMDocument3_iface,
3590 &domdoc_dispex);
3592 *document = &doc->IXMLDOMDocument3_iface;
3594 TRACE("returning iface %p\n", *document);
3595 return S_OK;
3598 HRESULT DOMDocument_create(MSXML_VERSION version, void **ppObj)
3600 xmlDocPtr xmldoc;
3601 HRESULT hr;
3603 TRACE("(%d, %p)\n", version, ppObj);
3605 xmldoc = xmlNewDoc(NULL);
3606 if(!xmldoc)
3607 return E_OUTOFMEMORY;
3609 xmldoc_init(xmldoc, version);
3611 hr = get_domdoc_from_xmldoc(xmldoc, (IXMLDOMDocument3**)ppObj);
3612 if(FAILED(hr))
3614 free_properties(properties_from_xmlDocPtr(xmldoc));
3615 heap_free(xmldoc->_private);
3616 xmlFreeDoc(xmldoc);
3617 return hr;
3620 return hr;
3623 IUnknown* create_domdoc( xmlNodePtr document )
3625 void* pObj = NULL;
3626 HRESULT hr;
3628 TRACE("(%p)\n", document);
3630 hr = get_domdoc_from_xmldoc((xmlDocPtr)document, (IXMLDOMDocument3**)&pObj);
3631 if (FAILED(hr))
3632 return NULL;
3634 return pObj;
3637 #else
3639 HRESULT DOMDocument_create(MSXML_VERSION version, void **ppObj)
3641 MESSAGE("This program tried to use a DOMDocument object, but\n"
3642 "libxml2 support was not present at compile time.\n");
3643 return E_NOTIMPL;
3646 #endif