msxml3: Fix crash when merging Text nodes.
[wine.git] / dlls / msxml3 / domdoc.c
blob184a01fe67ab7bb6b6054149a8f46b2486b924b5
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
24 #include "config.h"
26 #include <stdarg.h>
27 #include <assert.h>
28 #ifdef HAVE_LIBXML2
29 # include <libxml/parser.h>
30 # include <libxml/xmlerror.h>
31 # include <libxml/xpathInternals.h>
32 # include <libxml/xmlsave.h>
33 # include <libxml/SAX2.h>
34 # include <libxml/parserInternals.h>
35 #endif
37 #include "windef.h"
38 #include "winbase.h"
39 #include "winuser.h"
40 #include "winnls.h"
41 #include "ole2.h"
42 #include "olectl.h"
43 #include "msxml6.h"
44 #include "wininet.h"
45 #include "winreg.h"
46 #include "shlwapi.h"
47 #include "ocidl.h"
48 #include "objsafe.h"
50 #include "wine/debug.h"
52 #include "msxml_private.h"
54 #ifdef HAVE_LIBXML2
56 WINE_DEFAULT_DEBUG_CHANNEL(msxml);
58 /* not defined in older versions */
59 #define XML_SAVE_FORMAT 1
60 #define XML_SAVE_NO_DECL 2
61 #define XML_SAVE_NO_EMPTY 4
62 #define XML_SAVE_NO_XHTML 8
63 #define XML_SAVE_XHTML 16
64 #define XML_SAVE_AS_XML 32
65 #define XML_SAVE_AS_HTML 64
67 static const WCHAR PropertySelectionLanguageW[] = {'S','e','l','e','c','t','i','o','n','L','a','n','g','u','a','g','e',0};
68 static const WCHAR PropertySelectionNamespacesW[] = {'S','e','l','e','c','t','i','o','n','N','a','m','e','s','p','a','c','e','s',0};
69 static const WCHAR PropertyProhibitDTDW[] = {'P','r','o','h','i','b','i','t','D','T','D',0};
70 static const WCHAR PropertyNewParserW[] = {'N','e','w','P','a','r','s','e','r',0};
71 static const WCHAR PropValueXPathW[] = {'X','P','a','t','h',0};
72 static const WCHAR PropValueXSLPatternW[] = {'X','S','L','P','a','t','t','e','r','n',0};
73 static const WCHAR PropertyResolveExternalsW[] = {'R','e','s','o','l','v','e','E','x','t','e','r','n','a','l','s',0};
75 /* Anything that passes the test_get_ownerDocument()
76 * tests can go here (data shared between all instances).
77 * We need to preserve this when reloading a document,
78 * and also need access to it from the libxml backend. */
79 typedef struct {
80 MSXML_VERSION version;
81 VARIANT_BOOL preserving;
82 IXMLDOMSchemaCollection2* schemaCache;
83 struct list selectNsList;
84 xmlChar const* selectNsStr;
85 LONG selectNsStr_len;
86 BOOL XPath;
87 WCHAR *url;
88 } domdoc_properties;
90 typedef struct ConnectionPoint ConnectionPoint;
91 typedef struct domdoc domdoc;
93 struct ConnectionPoint
95 IConnectionPoint IConnectionPoint_iface;
96 const IID *iid;
98 ConnectionPoint *next;
99 IConnectionPointContainer *container;
100 domdoc *doc;
102 union
104 IUnknown *unk;
105 IDispatch *disp;
106 IPropertyNotifySink *propnotif;
107 } *sinks;
108 DWORD sinks_size;
111 typedef enum {
112 EVENTID_READYSTATECHANGE = 0,
113 EVENTID_DATAAVAILABLE,
114 EVENTID_TRANSFORMNODE,
115 EVENTID_LAST
116 } eventid_t;
118 struct domdoc
120 xmlnode node;
121 IXMLDOMDocument3 IXMLDOMDocument3_iface;
122 IPersistStreamInit IPersistStreamInit_iface;
123 IObjectWithSite IObjectWithSite_iface;
124 IObjectSafety IObjectSafety_iface;
125 IConnectionPointContainer IConnectionPointContainer_iface;
126 LONG ref;
127 VARIANT_BOOL async;
128 VARIANT_BOOL validating;
129 VARIANT_BOOL resolving;
130 domdoc_properties* properties;
131 HRESULT error;
133 /* IObjectWithSite */
134 IUnknown *site;
136 /* IObjectSafety */
137 DWORD safeopt;
139 /* connection list */
140 ConnectionPoint *cp_list;
141 ConnectionPoint cp_domdocevents;
142 ConnectionPoint cp_propnotif;
143 ConnectionPoint cp_dispatch;
145 /* events */
146 IDispatch *events[EVENTID_LAST];
148 IXMLDOMSchemaCollection2 *namespaces;
151 static HRESULT set_doc_event(domdoc *doc, eventid_t eid, const VARIANT *v)
153 IDispatch *disp;
155 switch (V_VT(v))
157 case VT_UNKNOWN:
158 if (V_UNKNOWN(v))
159 IUnknown_QueryInterface(V_UNKNOWN(v), &IID_IDispatch, (void**)&disp);
160 else
161 disp = NULL;
162 break;
163 case VT_DISPATCH:
164 disp = V_DISPATCH(v);
165 if (disp) IDispatch_AddRef(disp);
166 break;
167 default:
168 return DISP_E_TYPEMISMATCH;
171 if (doc->events[eid]) IDispatch_Release(doc->events[eid]);
172 doc->events[eid] = disp;
174 return S_OK;
177 static inline ConnectionPoint *impl_from_IConnectionPoint(IConnectionPoint *iface)
179 return CONTAINING_RECORD(iface, ConnectionPoint, IConnectionPoint_iface);
183 In native windows, the whole lifetime management of XMLDOMNodes is
184 managed automatically using reference counts. Wine emulates that by
185 maintaining a reference count to the document that is increased for
186 each IXMLDOMNode pointer passed out for this document. If all these
187 pointers are gone, the document is unreachable and gets freed, that
188 is, all nodes in the tree of the document get freed.
190 You are able to create nodes that are associated to a document (in
191 fact, in msxml's XMLDOM model, all nodes are associated to a document),
192 but not in the tree of that document, for example using the createFoo
193 functions from IXMLDOMDocument. These nodes do not get cleaned up
194 by libxml, so we have to do it ourselves.
196 To catch these nodes, a list of "orphan nodes" is introduced.
197 It contains pointers to all roots of node trees that are
198 associated with the document without being part of the document
199 tree. All nodes with parent==NULL (except for the document root nodes)
200 should be in the orphan node list of their document. All orphan nodes
201 get freed together with the document itself.
204 typedef struct _xmldoc_priv {
205 LONG refs;
206 struct list orphans;
207 domdoc_properties* properties;
208 } xmldoc_priv;
210 typedef struct _orphan_entry {
211 struct list entry;
212 xmlNode * node;
213 } orphan_entry;
215 typedef struct _select_ns_entry {
216 struct list entry;
217 xmlChar const* prefix;
218 xmlChar prefix_end;
219 xmlChar const* href;
220 xmlChar href_end;
221 } select_ns_entry;
223 static inline xmldoc_priv * priv_from_xmlDocPtr(const xmlDocPtr doc)
225 return doc->_private;
228 static inline domdoc_properties * properties_from_xmlDocPtr(xmlDocPtr doc)
230 return priv_from_xmlDocPtr(doc)->properties;
233 BOOL is_xpathmode(const xmlDocPtr doc)
235 return properties_from_xmlDocPtr(doc)->XPath;
238 void set_xpathmode(xmlDocPtr doc, BOOL xpath)
240 properties_from_xmlDocPtr(doc)->XPath = xpath;
243 int registerNamespaces(xmlXPathContextPtr ctxt)
245 int n = 0;
246 const select_ns_entry* ns = NULL;
247 const struct list* pNsList = &properties_from_xmlDocPtr(ctxt->doc)->selectNsList;
249 TRACE("(%p)\n", ctxt);
251 LIST_FOR_EACH_ENTRY( ns, pNsList, select_ns_entry, entry )
253 xmlXPathRegisterNs(ctxt, ns->prefix, ns->href);
254 ++n;
257 return n;
260 static inline void clear_selectNsList(struct list* pNsList)
262 select_ns_entry *ns, *ns2;
263 LIST_FOR_EACH_ENTRY_SAFE( ns, ns2, pNsList, select_ns_entry, entry )
265 heap_free( ns );
267 list_init(pNsList);
270 static xmldoc_priv * create_priv(void)
272 xmldoc_priv *priv;
273 priv = heap_alloc( sizeof (*priv) );
275 if (priv)
277 priv->refs = 0;
278 list_init( &priv->orphans );
279 priv->properties = NULL;
282 return priv;
285 static domdoc_properties *create_properties(MSXML_VERSION version)
287 domdoc_properties *properties = heap_alloc(sizeof(domdoc_properties));
289 list_init(&properties->selectNsList);
290 properties->preserving = VARIANT_FALSE;
291 properties->schemaCache = NULL;
292 properties->selectNsStr = heap_alloc_zero(sizeof(xmlChar));
293 properties->selectNsStr_len = 0;
295 /* properties that are dependent on object versions */
296 properties->version = version;
297 properties->XPath = (version == MSXML4 || version == MSXML6);
299 /* document url */
300 properties->url = NULL;
302 return properties;
305 static domdoc_properties* copy_properties(domdoc_properties const* properties)
307 domdoc_properties* pcopy = heap_alloc(sizeof(domdoc_properties));
308 select_ns_entry const* ns = NULL;
309 select_ns_entry* new_ns = NULL;
310 int len = (properties->selectNsStr_len+1)*sizeof(xmlChar);
311 ptrdiff_t offset;
313 if (pcopy)
315 pcopy->version = properties->version;
316 pcopy->preserving = properties->preserving;
317 pcopy->schemaCache = properties->schemaCache;
318 if (pcopy->schemaCache)
319 IXMLDOMSchemaCollection2_AddRef(pcopy->schemaCache);
320 pcopy->XPath = properties->XPath;
321 pcopy->selectNsStr_len = properties->selectNsStr_len;
322 list_init( &pcopy->selectNsList );
323 pcopy->selectNsStr = heap_alloc(len);
324 memcpy((xmlChar*)pcopy->selectNsStr, properties->selectNsStr, len);
325 offset = pcopy->selectNsStr - properties->selectNsStr;
327 LIST_FOR_EACH_ENTRY( ns, (&properties->selectNsList), select_ns_entry, entry )
329 new_ns = heap_alloc(sizeof(select_ns_entry));
330 memcpy(new_ns, ns, sizeof(select_ns_entry));
331 new_ns->href += offset;
332 new_ns->prefix += offset;
333 list_add_tail(&pcopy->selectNsList, &new_ns->entry);
336 if (properties->url)
338 int len = strlenW(properties->url);
340 pcopy->url = CoTaskMemAlloc((len+1)*sizeof(WCHAR));
341 memcpy(pcopy->url, properties->url, len*sizeof(WCHAR));
342 pcopy->url[len] = 0;
344 else
345 pcopy->url = NULL;
348 return pcopy;
351 static void free_properties(domdoc_properties* properties)
353 if (properties)
355 if (properties->schemaCache)
356 IXMLDOMSchemaCollection2_Release(properties->schemaCache);
357 clear_selectNsList(&properties->selectNsList);
358 heap_free((xmlChar*)properties->selectNsStr);
359 CoTaskMemFree(properties->url);
360 heap_free(properties);
364 static void release_namespaces(domdoc *This)
366 if (This->namespaces)
368 IXMLDOMSchemaCollection2_Release(This->namespaces);
369 This->namespaces = NULL;
373 /* links a "<?xml" node as a first child */
374 void xmldoc_link_xmldecl(xmlDocPtr doc, xmlNodePtr node)
376 assert(doc != NULL);
377 if (doc->standalone != -1) xmlAddPrevSibling( doc->children, node );
380 /* unlinks a first "<?xml" child if it was created */
381 xmlNodePtr xmldoc_unlink_xmldecl(xmlDocPtr doc)
383 static const xmlChar xmlA[] = "xml";
384 xmlNodePtr node, first_child;
386 assert(doc != NULL);
388 /* xml declaration node could be created automatically after parsing or added
389 to a tree later */
390 first_child = doc->children;
391 if (first_child && first_child->type == XML_PI_NODE && xmlStrEqual(first_child->name, xmlA))
393 node = first_child;
394 xmlUnlinkNode( node );
396 else
397 node = NULL;
399 return node;
402 BOOL is_preserving_whitespace(xmlNodePtr node)
404 domdoc_properties* properties = NULL;
405 /* during parsing the xmlDoc._private stuff is not there */
406 if (priv_from_xmlDocPtr(node->doc))
407 properties = properties_from_xmlDocPtr(node->doc);
408 return ((properties && properties->preserving == VARIANT_TRUE) ||
409 xmlNodeGetSpacePreserve(node) == 1);
412 static inline BOOL strn_isspace(xmlChar const* str, int len)
414 for (; str && len > 0 && *str; ++str, --len)
415 if (!isspace(*str))
416 break;
418 return len == 0;
421 static void sax_characters(void *ctx, const xmlChar *ch, int len)
423 xmlParserCtxtPtr ctxt;
424 const domdoc *This;
426 ctxt = (xmlParserCtxtPtr) ctx;
427 This = (const domdoc*) ctxt->_private;
429 if (ctxt->node)
431 xmlChar cur = *(ctxt->input->cur);
433 /* Characters are reported with multiple calls, for example each charref is reported with a separate
434 call and then parser appends it to a single text node or creates a new node if not created.
435 It's not possible to tell if it's ignorable data or not just looking at data itself cause it could be
436 space chars that separate charrefs or similar case. We only need to skip leading and trailing spaces,
437 or whole node if it has nothing but space chars, so to detect leading space node->last is checked that
438 contains text node pointer if already created, trailing spaces are detected directly looking at parser input
439 for next '<' opening bracket - similar logic is used by libxml2 itself. Basically 'cur' == '<' means the last
440 chunk of char data, in case it's not the last chunk we check for previously added node type and if it's not
441 a text node it's safe to ignore.
443 Note that during domdoc_loadXML() the xmlDocPtr->_private data is not available. */
445 if (!This->properties->preserving &&
446 !is_preserving_whitespace(ctxt->node) &&
447 strn_isspace(ch, len) &&
448 (!ctxt->node->last ||
449 ((ctxt->node->last && (cur == '<' || ctxt->node->last->type != XML_TEXT_NODE))
451 return;
454 xmlSAX2Characters(ctxt, ch, len);
457 static void LIBXML2_LOG_CALLBACK sax_error(void* ctx, char const* msg, ...)
459 va_list ap;
460 va_start(ap, msg);
461 LIBXML2_CALLBACK_ERR(doparse, msg, ap);
462 va_end(ap);
465 static void LIBXML2_LOG_CALLBACK sax_warning(void* ctx, char const* msg, ...)
467 va_list ap;
468 va_start(ap, msg);
469 LIBXML2_CALLBACK_WARN(doparse, msg, ap);
470 va_end(ap);
473 static void sax_serror(void* ctx, xmlErrorPtr err)
475 LIBXML2_CALLBACK_SERROR(doparse, err);
478 static xmlDocPtr doparse(domdoc* This, char const* ptr, int len, xmlCharEncoding encoding)
480 xmlDocPtr doc = NULL;
481 xmlParserCtxtPtr pctx;
482 static xmlSAXHandler sax_handler = {
483 xmlSAX2InternalSubset, /* internalSubset */
484 xmlSAX2IsStandalone, /* isStandalone */
485 xmlSAX2HasInternalSubset, /* hasInternalSubset */
486 xmlSAX2HasExternalSubset, /* hasExternalSubset */
487 xmlSAX2ResolveEntity, /* resolveEntity */
488 xmlSAX2GetEntity, /* getEntity */
489 xmlSAX2EntityDecl, /* entityDecl */
490 xmlSAX2NotationDecl, /* notationDecl */
491 xmlSAX2AttributeDecl, /* attributeDecl */
492 xmlSAX2ElementDecl, /* elementDecl */
493 xmlSAX2UnparsedEntityDecl, /* unparsedEntityDecl */
494 xmlSAX2SetDocumentLocator, /* setDocumentLocator */
495 xmlSAX2StartDocument, /* startDocument */
496 xmlSAX2EndDocument, /* endDocument */
497 xmlSAX2StartElement, /* startElement */
498 xmlSAX2EndElement, /* endElement */
499 xmlSAX2Reference, /* reference */
500 sax_characters, /* characters */
501 sax_characters, /* ignorableWhitespace */
502 xmlSAX2ProcessingInstruction, /* processingInstruction */
503 xmlSAX2Comment, /* comment */
504 sax_warning, /* warning */
505 sax_error, /* error */
506 sax_error, /* fatalError */
507 xmlSAX2GetParameterEntity, /* getParameterEntity */
508 xmlSAX2CDataBlock, /* cdataBlock */
509 xmlSAX2ExternalSubset, /* externalSubset */
510 0, /* initialized */
511 NULL, /* _private */
512 xmlSAX2StartElementNs, /* startElementNs */
513 xmlSAX2EndElementNs, /* endElementNs */
514 sax_serror /* serror */
517 pctx = xmlCreateMemoryParserCtxt(ptr, len);
518 if (!pctx)
520 ERR("Failed to create parser context\n");
521 return NULL;
524 if (pctx->sax) xmlFree(pctx->sax);
525 pctx->sax = &sax_handler;
526 pctx->_private = This;
527 pctx->recovery = 0;
529 if (encoding != XML_CHAR_ENCODING_NONE)
530 xmlSwitchEncoding(pctx, encoding);
532 xmlParseDocument(pctx);
534 if (pctx->wellFormed)
536 doc = pctx->myDoc;
538 else
540 xmlFreeDoc(pctx->myDoc);
541 pctx->myDoc = NULL;
543 pctx->sax = NULL;
544 xmlFreeParserCtxt(pctx);
546 /* TODO: put this in one of the SAX callbacks */
547 /* create first child as a <?xml...?> */
548 if (doc && doc->standalone != -1)
550 xmlNodePtr node;
551 char buff[30];
552 xmlChar *xmlbuff = (xmlChar*)buff;
554 node = xmlNewDocPI( doc, (xmlChar*)"xml", NULL );
556 /* version attribute can't be omitted */
557 sprintf(buff, "version=\"%s\"", doc->version ? (char*)doc->version : "1.0");
558 xmlNodeAddContent( node, xmlbuff );
560 if (doc->encoding)
562 sprintf(buff, " encoding=\"%s\"", doc->encoding);
563 xmlNodeAddContent( node, xmlbuff );
566 if (doc->standalone != -2)
568 sprintf(buff, " standalone=\"%s\"", doc->standalone == 0 ? "no" : "yes");
569 xmlNodeAddContent( node, xmlbuff );
572 xmldoc_link_xmldecl( doc, node );
575 return doc;
578 void xmldoc_init(xmlDocPtr doc, MSXML_VERSION version)
580 doc->_private = create_priv();
581 priv_from_xmlDocPtr(doc)->properties = create_properties(version);
584 LONG xmldoc_add_refs(xmlDocPtr doc, LONG refs)
586 LONG ref = InterlockedExchangeAdd(&priv_from_xmlDocPtr(doc)->refs, refs) + refs;
587 TRACE("(%p)->(%d)\n", doc, ref);
588 return ref;
591 LONG xmldoc_add_ref(xmlDocPtr doc)
593 return xmldoc_add_refs(doc, 1);
596 LONG xmldoc_release_refs(xmlDocPtr doc, LONG refs)
598 xmldoc_priv *priv = priv_from_xmlDocPtr(doc);
599 LONG ref = InterlockedExchangeAdd(&priv->refs, -refs) - refs;
600 TRACE("(%p)->(%d)\n", doc, ref);
602 if (ref < 0)
603 WARN("negative refcount, expect troubles\n");
605 if (ref == 0)
607 orphan_entry *orphan, *orphan2;
608 TRACE("freeing docptr %p\n", doc);
610 LIST_FOR_EACH_ENTRY_SAFE( orphan, orphan2, &priv->orphans, orphan_entry, entry )
612 xmlFreeNode( orphan->node );
613 heap_free( orphan );
615 free_properties(priv->properties);
616 heap_free(doc->_private);
618 xmlFreeDoc(doc);
621 return ref;
624 LONG xmldoc_release(xmlDocPtr doc)
626 return xmldoc_release_refs(doc, 1);
629 HRESULT xmldoc_add_orphan(xmlDocPtr doc, xmlNodePtr node)
631 xmldoc_priv *priv = priv_from_xmlDocPtr(doc);
632 orphan_entry *entry;
634 entry = heap_alloc( sizeof (*entry) );
635 if(!entry)
636 return E_OUTOFMEMORY;
638 entry->node = node;
639 list_add_head( &priv->orphans, &entry->entry );
640 return S_OK;
643 HRESULT xmldoc_remove_orphan(xmlDocPtr doc, xmlNodePtr node)
645 xmldoc_priv *priv = priv_from_xmlDocPtr(doc);
646 orphan_entry *entry, *entry2;
648 LIST_FOR_EACH_ENTRY_SAFE( entry, entry2, &priv->orphans, orphan_entry, entry )
650 if( entry->node == node )
652 list_remove( &entry->entry );
653 heap_free( entry );
654 return S_OK;
658 return S_FALSE;
661 static inline xmlDocPtr get_doc( domdoc *This )
663 return This->node.node->doc;
666 static HRESULT attach_xmldoc(domdoc *This, xmlDocPtr xml )
668 release_namespaces(This);
670 if(This->node.node)
672 priv_from_xmlDocPtr(get_doc(This))->properties = NULL;
673 if (xmldoc_release(get_doc(This)) != 0)
674 priv_from_xmlDocPtr(get_doc(This))->properties =
675 copy_properties(This->properties);
678 This->node.node = (xmlNodePtr) xml;
680 if(This->node.node)
682 xmldoc_add_ref(get_doc(This));
683 priv_from_xmlDocPtr(get_doc(This))->properties = This->properties;
686 return S_OK;
689 static inline domdoc *impl_from_IXMLDOMDocument3( IXMLDOMDocument3 *iface )
691 return CONTAINING_RECORD(iface, domdoc, IXMLDOMDocument3_iface);
694 static inline domdoc *impl_from_IPersistStreamInit(IPersistStreamInit *iface)
696 return CONTAINING_RECORD(iface, domdoc, IPersistStreamInit_iface);
699 static inline domdoc *impl_from_IObjectWithSite(IObjectWithSite *iface)
701 return CONTAINING_RECORD(iface, domdoc, IObjectWithSite_iface);
704 static inline domdoc *impl_from_IObjectSafety(IObjectSafety *iface)
706 return CONTAINING_RECORD(iface, domdoc, IObjectSafety_iface);
709 static inline domdoc *impl_from_IConnectionPointContainer(IConnectionPointContainer *iface)
711 return CONTAINING_RECORD(iface, domdoc, IConnectionPointContainer_iface);
714 /************************************************************************
715 * domdoc implementation of IPersistStream.
717 static HRESULT WINAPI PersistStreamInit_QueryInterface(
718 IPersistStreamInit *iface, REFIID riid, void **ppvObj)
720 domdoc* This = impl_from_IPersistStreamInit(iface);
721 return IXMLDOMDocument3_QueryInterface(&This->IXMLDOMDocument3_iface, riid, ppvObj);
724 static ULONG WINAPI PersistStreamInit_AddRef(
725 IPersistStreamInit *iface)
727 domdoc* This = impl_from_IPersistStreamInit(iface);
728 return IXMLDOMDocument3_AddRef(&This->IXMLDOMDocument3_iface);
731 static ULONG WINAPI PersistStreamInit_Release(
732 IPersistStreamInit *iface)
734 domdoc* This = impl_from_IPersistStreamInit(iface);
735 return IXMLDOMDocument3_Release(&This->IXMLDOMDocument3_iface);
738 static HRESULT WINAPI PersistStreamInit_GetClassID(
739 IPersistStreamInit *iface, CLSID *classid)
741 domdoc* This = impl_from_IPersistStreamInit(iface);
742 TRACE("(%p)->(%p)\n", This, classid);
744 if(!classid)
745 return E_POINTER;
747 *classid = *DOMDocument_version(This->properties->version);
749 return S_OK;
752 static HRESULT WINAPI PersistStreamInit_IsDirty(
753 IPersistStreamInit *iface)
755 domdoc *This = impl_from_IPersistStreamInit(iface);
756 FIXME("(%p): stub!\n", This);
757 return S_FALSE;
760 static HRESULT domdoc_load_from_stream(domdoc *doc, ISequentialStream *stream)
762 DWORD read, written, len;
763 xmlDocPtr xmldoc = NULL;
764 IStream *hstream;
765 HGLOBAL hglobal;
766 BYTE buf[4096];
767 HRESULT hr;
768 char *ptr;
770 hstream = NULL;
771 hr = CreateStreamOnHGlobal(NULL, TRUE, &hstream);
772 if (FAILED(hr))
773 return hr;
777 ISequentialStream_Read(stream, buf, sizeof(buf), &read);
778 hr = IStream_Write(hstream, buf, read, &written);
779 } while(SUCCEEDED(hr) && written != 0 && read != 0);
781 if (FAILED(hr))
783 ERR("failed to copy stream 0x%08x\n", hr);
784 IStream_Release(hstream);
785 return hr;
788 hr = GetHGlobalFromStream(hstream, &hglobal);
789 if (FAILED(hr))
790 return hr;
792 len = GlobalSize(hglobal);
793 ptr = GlobalLock(hglobal);
794 if (len)
795 xmldoc = doparse(doc, ptr, len, XML_CHAR_ENCODING_NONE);
796 GlobalUnlock(hglobal);
798 if (!xmldoc)
800 ERR("Failed to parse xml\n");
801 return E_FAIL;
804 xmldoc->_private = create_priv();
806 return attach_xmldoc(doc, xmldoc);
809 static HRESULT WINAPI PersistStreamInit_Load(IPersistStreamInit *iface, IStream *stream)
811 domdoc *This = impl_from_IPersistStreamInit(iface);
813 TRACE("(%p)->(%p)\n", This, stream);
815 if (!stream)
816 return E_INVALIDARG;
818 return domdoc_load_from_stream(This, (ISequentialStream*)stream);
821 static HRESULT WINAPI PersistStreamInit_Save(
822 IPersistStreamInit *iface, IStream *stream, BOOL clr_dirty)
824 domdoc *This = impl_from_IPersistStreamInit(iface);
825 BSTR xmlString;
826 HRESULT hr;
828 TRACE("(%p)->(%p %d)\n", This, stream, clr_dirty);
830 hr = IXMLDOMDocument3_get_xml(&This->IXMLDOMDocument3_iface, &xmlString);
831 if(hr == S_OK)
833 DWORD len = SysStringLen(xmlString) * sizeof(WCHAR);
835 hr = IStream_Write( stream, xmlString, len, NULL );
836 SysFreeString(xmlString);
839 TRACE("ret 0x%08x\n", hr);
841 return hr;
844 static HRESULT WINAPI PersistStreamInit_GetSizeMax(
845 IPersistStreamInit *iface, ULARGE_INTEGER *pcbSize)
847 domdoc *This = impl_from_IPersistStreamInit(iface);
848 TRACE("(%p)->(%p)\n", This, pcbSize);
849 return E_NOTIMPL;
852 static HRESULT WINAPI PersistStreamInit_InitNew(
853 IPersistStreamInit *iface)
855 domdoc *This = impl_from_IPersistStreamInit(iface);
856 TRACE("(%p)\n", This);
857 return S_OK;
860 static const IPersistStreamInitVtbl xmldoc_IPersistStreamInit_VTable =
862 PersistStreamInit_QueryInterface,
863 PersistStreamInit_AddRef,
864 PersistStreamInit_Release,
865 PersistStreamInit_GetClassID,
866 PersistStreamInit_IsDirty,
867 PersistStreamInit_Load,
868 PersistStreamInit_Save,
869 PersistStreamInit_GetSizeMax,
870 PersistStreamInit_InitNew
873 /* IXMLDOMDocument3 interface */
875 static const tid_t domdoc_se_tids[] = {
876 IXMLDOMNode_tid,
877 IXMLDOMDocument_tid,
878 IXMLDOMDocument2_tid,
879 IXMLDOMDocument3_tid,
880 NULL_tid
883 static HRESULT WINAPI domdoc_QueryInterface( IXMLDOMDocument3 *iface, REFIID riid, void** ppvObject )
885 domdoc *This = impl_from_IXMLDOMDocument3( iface );
887 TRACE("(%p)->(%s %p)\n", This, debugstr_guid( riid ), ppvObject );
889 *ppvObject = NULL;
891 if ( IsEqualGUID( riid, &IID_IUnknown ) ||
892 IsEqualGUID( riid, &IID_IDispatch ) ||
893 IsEqualGUID( riid, &IID_IXMLDOMNode ) ||
894 IsEqualGUID( riid, &IID_IXMLDOMDocument ) ||
895 IsEqualGUID( riid, &IID_IXMLDOMDocument2 )||
896 IsEqualGUID( riid, &IID_IXMLDOMDocument3 ))
898 *ppvObject = iface;
900 else if (IsEqualGUID(&IID_IPersistStream, riid) ||
901 IsEqualGUID(&IID_IPersistStreamInit, riid))
903 *ppvObject = &This->IPersistStreamInit_iface;
905 else if (IsEqualGUID(&IID_IObjectWithSite, riid))
907 *ppvObject = &This->IObjectWithSite_iface;
909 else if (IsEqualGUID(&IID_IObjectSafety, riid))
911 *ppvObject = &This->IObjectSafety_iface;
913 else if( IsEqualGUID( riid, &IID_ISupportErrorInfo ))
915 return node_create_supporterrorinfo(domdoc_se_tids, ppvObject);
917 else if(node_query_interface(&This->node, riid, ppvObject))
919 return *ppvObject ? S_OK : E_NOINTERFACE;
921 else if (IsEqualGUID( riid, &IID_IConnectionPointContainer ))
923 *ppvObject = &This->IConnectionPointContainer_iface;
925 else
927 TRACE("interface %s not implemented\n", debugstr_guid(riid));
928 return E_NOINTERFACE;
931 IUnknown_AddRef((IUnknown*)*ppvObject);
933 return S_OK;
936 static ULONG WINAPI domdoc_AddRef( IXMLDOMDocument3 *iface )
938 domdoc *This = impl_from_IXMLDOMDocument3( iface );
939 ULONG ref = InterlockedIncrement( &This->ref );
940 TRACE("(%p)->(%d)\n", This, ref );
941 return ref;
944 static ULONG WINAPI domdoc_Release( IXMLDOMDocument3 *iface )
946 domdoc *This = impl_from_IXMLDOMDocument3( iface );
947 LONG ref = InterlockedDecrement( &This->ref );
949 TRACE("(%p)->(%d)\n", This, ref );
951 if ( ref == 0 )
953 int eid;
955 if (This->site)
956 IUnknown_Release( This->site );
957 destroy_xmlnode(&This->node);
959 for (eid = 0; eid < EVENTID_LAST; eid++)
960 if (This->events[eid]) IDispatch_Release(This->events[eid]);
962 release_namespaces(This);
963 heap_free(This);
966 return ref;
969 static HRESULT WINAPI domdoc_GetTypeInfoCount( IXMLDOMDocument3 *iface, UINT* pctinfo )
971 domdoc *This = impl_from_IXMLDOMDocument3( iface );
972 return IDispatchEx_GetTypeInfoCount(&This->node.dispex.IDispatchEx_iface, pctinfo);
975 static HRESULT WINAPI domdoc_GetTypeInfo(
976 IXMLDOMDocument3 *iface,
977 UINT iTInfo, LCID lcid, ITypeInfo** ppTInfo )
979 domdoc *This = impl_from_IXMLDOMDocument3( iface );
980 return IDispatchEx_GetTypeInfo(&This->node.dispex.IDispatchEx_iface, iTInfo, lcid, ppTInfo);
983 static HRESULT WINAPI domdoc_GetIDsOfNames(
984 IXMLDOMDocument3 *iface,
985 REFIID riid,
986 LPOLESTR* rgszNames,
987 UINT cNames,
988 LCID lcid,
989 DISPID* rgDispId)
991 domdoc *This = impl_from_IXMLDOMDocument3( iface );
992 return IDispatchEx_GetIDsOfNames(&This->node.dispex.IDispatchEx_iface,
993 riid, rgszNames, cNames, lcid, rgDispId);
996 static HRESULT WINAPI domdoc_Invoke(
997 IXMLDOMDocument3 *iface,
998 DISPID dispIdMember,
999 REFIID riid,
1000 LCID lcid,
1001 WORD wFlags,
1002 DISPPARAMS* pDispParams,
1003 VARIANT* pVarResult,
1004 EXCEPINFO* pExcepInfo,
1005 UINT* puArgErr)
1007 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1008 return IDispatchEx_Invoke(&This->node.dispex.IDispatchEx_iface,
1009 dispIdMember, riid, lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
1012 static HRESULT WINAPI domdoc_get_nodeName(
1013 IXMLDOMDocument3 *iface,
1014 BSTR* name )
1016 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1018 static const WCHAR documentW[] = {'#','d','o','c','u','m','e','n','t',0};
1020 TRACE("(%p)->(%p)\n", This, name);
1022 return return_bstr(documentW, name);
1026 static HRESULT WINAPI domdoc_get_nodeValue(
1027 IXMLDOMDocument3 *iface,
1028 VARIANT* value )
1030 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1032 TRACE("(%p)->(%p)\n", This, value);
1034 if(!value)
1035 return E_INVALIDARG;
1037 V_VT(value) = VT_NULL;
1038 V_BSTR(value) = NULL; /* tests show that we should do this */
1039 return S_FALSE;
1043 static HRESULT WINAPI domdoc_put_nodeValue(
1044 IXMLDOMDocument3 *iface,
1045 VARIANT value)
1047 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1048 TRACE("(%p)->(%s)\n", This, debugstr_variant(&value));
1049 return E_FAIL;
1053 static HRESULT WINAPI domdoc_get_nodeType(
1054 IXMLDOMDocument3 *iface,
1055 DOMNodeType* type )
1057 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1059 TRACE("(%p)->(%p)\n", This, type);
1061 *type = NODE_DOCUMENT;
1062 return S_OK;
1066 static HRESULT WINAPI domdoc_get_parentNode(
1067 IXMLDOMDocument3 *iface,
1068 IXMLDOMNode** parent )
1070 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1072 TRACE("(%p)->(%p)\n", This, parent);
1074 return node_get_parent(&This->node, parent);
1078 static HRESULT WINAPI domdoc_get_childNodes(
1079 IXMLDOMDocument3 *iface,
1080 IXMLDOMNodeList** childList )
1082 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1084 TRACE("(%p)->(%p)\n", This, childList);
1086 return node_get_child_nodes(&This->node, childList);
1090 static HRESULT WINAPI domdoc_get_firstChild(
1091 IXMLDOMDocument3 *iface,
1092 IXMLDOMNode** firstChild )
1094 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1096 TRACE("(%p)->(%p)\n", This, firstChild);
1098 return node_get_first_child(&This->node, firstChild);
1102 static HRESULT WINAPI domdoc_get_lastChild(
1103 IXMLDOMDocument3 *iface,
1104 IXMLDOMNode** lastChild )
1106 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1108 TRACE("(%p)->(%p)\n", This, lastChild);
1110 return node_get_last_child(&This->node, lastChild);
1114 static HRESULT WINAPI domdoc_get_previousSibling(
1115 IXMLDOMDocument3 *iface,
1116 IXMLDOMNode** previousSibling )
1118 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1120 TRACE("(%p)->(%p)\n", This, previousSibling);
1122 return return_null_node(previousSibling);
1126 static HRESULT WINAPI domdoc_get_nextSibling(
1127 IXMLDOMDocument3 *iface,
1128 IXMLDOMNode** nextSibling )
1130 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1132 TRACE("(%p)->(%p)\n", This, nextSibling);
1134 return return_null_node(nextSibling);
1138 static HRESULT WINAPI domdoc_get_attributes(
1139 IXMLDOMDocument3 *iface,
1140 IXMLDOMNamedNodeMap** attributeMap )
1142 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1144 TRACE("(%p)->(%p)\n", This, attributeMap);
1146 return return_null_ptr((void**)attributeMap);
1150 static HRESULT WINAPI domdoc_insertBefore(
1151 IXMLDOMDocument3 *iface,
1152 IXMLDOMNode* newChild,
1153 VARIANT refChild,
1154 IXMLDOMNode** outNewChild )
1156 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1157 DOMNodeType type;
1158 HRESULT hr;
1160 TRACE("(%p)->(%p %s %p)\n", This, newChild, debugstr_variant(&refChild), outNewChild);
1162 hr = IXMLDOMNode_get_nodeType(newChild, &type);
1163 if (hr != S_OK) return hr;
1165 TRACE("new node type %d\n", type);
1166 switch (type)
1168 case NODE_ATTRIBUTE:
1169 case NODE_DOCUMENT:
1170 case NODE_CDATA_SECTION:
1171 if (outNewChild) *outNewChild = NULL;
1172 return E_FAIL;
1173 default:
1174 return node_insert_before(&This->node, newChild, &refChild, outNewChild);
1178 static HRESULT WINAPI domdoc_replaceChild(
1179 IXMLDOMDocument3 *iface,
1180 IXMLDOMNode* newChild,
1181 IXMLDOMNode* oldChild,
1182 IXMLDOMNode** outOldChild)
1184 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1186 TRACE("(%p)->(%p %p %p)\n", This, newChild, oldChild, outOldChild);
1188 return node_replace_child(&This->node, newChild, oldChild, outOldChild);
1192 static HRESULT WINAPI domdoc_removeChild(
1193 IXMLDOMDocument3 *iface,
1194 IXMLDOMNode *child,
1195 IXMLDOMNode **oldChild)
1197 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1198 TRACE("(%p)->(%p %p)\n", This, child, oldChild);
1199 return node_remove_child(&This->node, child, oldChild);
1203 static HRESULT WINAPI domdoc_appendChild(
1204 IXMLDOMDocument3 *iface,
1205 IXMLDOMNode *child,
1206 IXMLDOMNode **outChild)
1208 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1209 TRACE("(%p)->(%p %p)\n", This, child, outChild);
1210 return node_append_child(&This->node, child, outChild);
1214 static HRESULT WINAPI domdoc_hasChildNodes(
1215 IXMLDOMDocument3 *iface,
1216 VARIANT_BOOL *ret)
1218 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1219 TRACE("(%p)->(%p)\n", This, ret);
1220 return node_has_childnodes(&This->node, ret);
1224 static HRESULT WINAPI domdoc_get_ownerDocument(
1225 IXMLDOMDocument3 *iface,
1226 IXMLDOMDocument **doc)
1228 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1229 TRACE("(%p)->(%p)\n", This, doc);
1230 return node_get_owner_doc(&This->node, doc);
1234 static HRESULT WINAPI domdoc_cloneNode(
1235 IXMLDOMDocument3 *iface,
1236 VARIANT_BOOL deep,
1237 IXMLDOMNode** outNode)
1239 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1240 TRACE("(%p)->(%d %p)\n", This, deep, outNode);
1241 return node_clone( &This->node, deep, outNode );
1245 static HRESULT WINAPI domdoc_get_nodeTypeString(
1246 IXMLDOMDocument3 *iface,
1247 BSTR *p)
1249 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1250 static const WCHAR documentW[] = {'d','o','c','u','m','e','n','t',0};
1252 TRACE("(%p)->(%p)\n", This, p);
1254 return return_bstr(documentW, p);
1258 static HRESULT WINAPI domdoc_get_text(
1259 IXMLDOMDocument3 *iface,
1260 BSTR *p)
1262 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1263 TRACE("(%p)->(%p)\n", This, p);
1264 return node_get_text(&This->node, p);
1268 static HRESULT WINAPI domdoc_put_text(
1269 IXMLDOMDocument3 *iface,
1270 BSTR text )
1272 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1273 TRACE("(%p)->(%s)\n", This, debugstr_w(text));
1274 return E_FAIL;
1278 static HRESULT WINAPI domdoc_get_specified(
1279 IXMLDOMDocument3 *iface,
1280 VARIANT_BOOL* isSpecified )
1282 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1283 FIXME("(%p)->(%p) stub!\n", This, isSpecified);
1284 *isSpecified = VARIANT_TRUE;
1285 return S_OK;
1289 static HRESULT WINAPI domdoc_get_definition(
1290 IXMLDOMDocument3 *iface,
1291 IXMLDOMNode** definitionNode )
1293 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1294 FIXME("(%p)->(%p)\n", This, definitionNode);
1295 return E_NOTIMPL;
1299 static HRESULT WINAPI domdoc_get_nodeTypedValue(
1300 IXMLDOMDocument3 *iface,
1301 VARIANT* v )
1303 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1304 TRACE("(%p)->(%p)\n", This, v);
1305 return return_null_var(v);
1308 static HRESULT WINAPI domdoc_put_nodeTypedValue(
1309 IXMLDOMDocument3 *iface,
1310 VARIANT typedValue )
1312 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1313 FIXME("(%p)->(%s)\n", This, debugstr_variant(&typedValue));
1314 return E_NOTIMPL;
1318 static HRESULT WINAPI domdoc_get_dataType(
1319 IXMLDOMDocument3 *iface,
1320 VARIANT* typename )
1322 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1323 TRACE("(%p)->(%p)\n", This, typename);
1324 return return_null_var( typename );
1328 static HRESULT WINAPI domdoc_put_dataType(
1329 IXMLDOMDocument3 *iface,
1330 BSTR dataTypeName )
1332 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1334 FIXME("(%p)->(%s)\n", This, debugstr_w(dataTypeName));
1336 if(!dataTypeName)
1337 return E_INVALIDARG;
1339 return E_FAIL;
1342 static int XMLCALL domdoc_get_xml_writecallback(void *ctx, const char *data, int len)
1344 return xmlBufferAdd((xmlBufferPtr)ctx, (xmlChar*)data, len) == 0 ? len : 0;
1347 static HRESULT WINAPI domdoc_get_xml(
1348 IXMLDOMDocument3 *iface,
1349 BSTR* p)
1351 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1352 xmlSaveCtxtPtr ctxt;
1353 xmlBufferPtr buf;
1354 int options;
1355 long ret;
1357 TRACE("(%p)->(%p)\n", This, p);
1359 if(!p)
1360 return E_INVALIDARG;
1362 *p = NULL;
1364 buf = xmlBufferCreate();
1365 if(!buf)
1366 return E_OUTOFMEMORY;
1368 options = XML_SAVE_FORMAT | XML_SAVE_NO_DECL;
1369 ctxt = xmlSaveToIO(domdoc_get_xml_writecallback, NULL, buf, "UTF-8", options);
1371 if(!ctxt)
1373 xmlBufferFree(buf);
1374 return E_OUTOFMEMORY;
1377 ret = xmlSaveDoc(ctxt, get_doc(This));
1378 /* flushes on close */
1379 xmlSaveClose(ctxt);
1381 TRACE("%ld, len=%d\n", ret, xmlBufferLength(buf));
1382 if(ret != -1 && xmlBufferLength(buf) > 0)
1384 BSTR content;
1386 content = bstr_from_xmlChar(xmlBufferContent(buf));
1387 content = EnsureCorrectEOL(content);
1389 *p = content;
1391 else
1393 *p = SysAllocStringLen(NULL, 0);
1396 xmlBufferFree(buf);
1398 return *p ? S_OK : E_OUTOFMEMORY;
1402 static HRESULT WINAPI domdoc_transformNode(
1403 IXMLDOMDocument3 *iface,
1404 IXMLDOMNode *node,
1405 BSTR *p)
1407 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1408 TRACE("(%p)->(%p %p)\n", This, node, p);
1409 return node_transform_node(&This->node, node, p);
1413 static HRESULT WINAPI domdoc_selectNodes(
1414 IXMLDOMDocument3 *iface,
1415 BSTR p,
1416 IXMLDOMNodeList **outList)
1418 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1419 TRACE("(%p)->(%s %p)\n", This, debugstr_w(p), outList);
1420 return node_select_nodes(&This->node, p, outList);
1424 static HRESULT WINAPI domdoc_selectSingleNode(
1425 IXMLDOMDocument3 *iface,
1426 BSTR p,
1427 IXMLDOMNode **outNode)
1429 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1430 TRACE("(%p)->(%s %p)\n", This, debugstr_w(p), outNode);
1431 return node_select_singlenode(&This->node, p, outNode);
1435 static HRESULT WINAPI domdoc_get_parsed(
1436 IXMLDOMDocument3 *iface,
1437 VARIANT_BOOL* isParsed )
1439 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1440 FIXME("(%p)->(%p) stub!\n", This, isParsed);
1441 *isParsed = VARIANT_TRUE;
1442 return S_OK;
1445 static HRESULT WINAPI domdoc_get_namespaceURI(
1446 IXMLDOMDocument3 *iface,
1447 BSTR* namespaceURI )
1449 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1450 TRACE("(%p)->(%p)\n", This, namespaceURI);
1451 return return_null_bstr( namespaceURI );
1454 static HRESULT WINAPI domdoc_get_prefix(
1455 IXMLDOMDocument3 *iface,
1456 BSTR* prefix )
1458 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1459 TRACE("(%p)->(%p)\n", This, prefix);
1460 return return_null_bstr( prefix );
1464 static HRESULT WINAPI domdoc_get_baseName(
1465 IXMLDOMDocument3 *iface,
1466 BSTR* name )
1468 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1469 TRACE("(%p)->(%p)\n", This, name);
1470 return return_null_bstr( name );
1474 static HRESULT WINAPI domdoc_transformNodeToObject(
1475 IXMLDOMDocument3 *iface,
1476 IXMLDOMNode* stylesheet,
1477 VARIANT outputObject)
1479 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1480 FIXME("(%p)->(%p %s)\n", This, stylesheet, debugstr_variant(&outputObject));
1481 return E_NOTIMPL;
1485 static HRESULT WINAPI domdoc_get_doctype(
1486 IXMLDOMDocument3 *iface,
1487 IXMLDOMDocumentType** doctype )
1489 domdoc *This = impl_from_IXMLDOMDocument3(iface);
1490 IXMLDOMNode *node;
1491 xmlDtdPtr dtd;
1492 HRESULT hr;
1494 TRACE("(%p)->(%p)\n", This, doctype);
1496 if (!doctype) return E_INVALIDARG;
1498 *doctype = NULL;
1500 dtd = xmlGetIntSubset(get_doc(This));
1501 if (!dtd) return S_FALSE;
1503 node = create_node((xmlNodePtr)dtd);
1504 if (!node) return S_FALSE;
1506 hr = IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMDocumentType, (void**)doctype);
1507 IXMLDOMNode_Release(node);
1509 return hr;
1513 static HRESULT WINAPI domdoc_get_implementation(
1514 IXMLDOMDocument3 *iface,
1515 IXMLDOMImplementation** impl )
1517 domdoc *This = impl_from_IXMLDOMDocument3(iface);
1519 TRACE("(%p)->(%p)\n", This, impl);
1521 if(!impl)
1522 return E_INVALIDARG;
1524 *impl = (IXMLDOMImplementation*)create_doc_Implementation();
1526 return S_OK;
1529 static HRESULT WINAPI domdoc_get_documentElement(
1530 IXMLDOMDocument3 *iface,
1531 IXMLDOMElement** DOMElement )
1533 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1534 IXMLDOMNode *element_node;
1535 xmlNodePtr root;
1536 HRESULT hr;
1538 TRACE("(%p)->(%p)\n", This, DOMElement);
1540 if(!DOMElement)
1541 return E_INVALIDARG;
1543 *DOMElement = NULL;
1545 root = xmlDocGetRootElement( get_doc(This) );
1546 if ( !root )
1547 return S_FALSE;
1549 element_node = create_node( root );
1550 if(!element_node) return S_FALSE;
1552 hr = IXMLDOMNode_QueryInterface(element_node, &IID_IXMLDOMElement, (void**)DOMElement);
1553 IXMLDOMNode_Release(element_node);
1555 return hr;
1559 static HRESULT WINAPI domdoc_put_documentElement(
1560 IXMLDOMDocument3 *iface,
1561 IXMLDOMElement* DOMElement )
1563 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1564 IXMLDOMNode *elementNode;
1565 xmlNodePtr oldRoot;
1566 xmlDocPtr old_doc;
1567 xmlnode *xmlNode;
1568 int refcount = 0;
1569 HRESULT hr;
1571 TRACE("(%p)->(%p)\n", This, DOMElement);
1573 hr = IXMLDOMElement_QueryInterface( DOMElement, &IID_IXMLDOMNode, (void**)&elementNode );
1574 if(FAILED(hr))
1575 return hr;
1577 xmlNode = get_node_obj( elementNode );
1578 if(!xmlNode) return E_FAIL;
1580 if(!xmlNode->node->parent)
1581 if(xmldoc_remove_orphan(xmlNode->node->doc, xmlNode->node) != S_OK)
1582 WARN("%p is not an orphan of %p\n", xmlNode->node->doc, xmlNode->node);
1584 old_doc = xmlNode->node->doc;
1585 if (old_doc != get_doc(This))
1586 refcount = xmlnode_get_inst_cnt(xmlNode);
1588 /* old root is still orphaned by its document, update refcount from new root */
1589 if (refcount) xmldoc_add_refs(get_doc(This), refcount);
1590 oldRoot = xmlDocSetRootElement( get_doc(This), xmlNode->node);
1591 if (refcount) xmldoc_release_refs(old_doc, refcount);
1592 IXMLDOMNode_Release( elementNode );
1594 if(oldRoot)
1595 xmldoc_add_orphan(oldRoot->doc, oldRoot);
1597 return S_OK;
1601 static HRESULT WINAPI domdoc_createElement(
1602 IXMLDOMDocument3 *iface,
1603 BSTR tagname,
1604 IXMLDOMElement** element )
1606 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1607 IXMLDOMNode *node;
1608 VARIANT type;
1609 HRESULT hr;
1611 TRACE("(%p)->(%s %p)\n", This, debugstr_w(tagname), element);
1613 if (!element || !tagname) return E_INVALIDARG;
1615 V_VT(&type) = VT_I1;
1616 V_I1(&type) = NODE_ELEMENT;
1618 hr = IXMLDOMDocument3_createNode(iface, type, tagname, NULL, &node);
1619 if (hr == S_OK)
1621 IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMElement, (void**)element);
1622 IXMLDOMNode_Release(node);
1625 return hr;
1629 static HRESULT WINAPI domdoc_createDocumentFragment(
1630 IXMLDOMDocument3 *iface,
1631 IXMLDOMDocumentFragment** frag )
1633 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1634 IXMLDOMNode *node;
1635 VARIANT type;
1636 HRESULT hr;
1638 TRACE("(%p)->(%p)\n", This, frag);
1640 if (!frag) return E_INVALIDARG;
1642 *frag = NULL;
1644 V_VT(&type) = VT_I1;
1645 V_I1(&type) = NODE_DOCUMENT_FRAGMENT;
1647 hr = IXMLDOMDocument3_createNode(iface, type, NULL, NULL, &node);
1648 if (hr == S_OK)
1650 IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMDocumentFragment, (void**)frag);
1651 IXMLDOMNode_Release(node);
1654 return hr;
1658 static HRESULT WINAPI domdoc_createTextNode(
1659 IXMLDOMDocument3 *iface,
1660 BSTR data,
1661 IXMLDOMText** text )
1663 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1664 IXMLDOMNode *node;
1665 VARIANT type;
1666 HRESULT hr;
1668 TRACE("(%p)->(%s %p)\n", This, debugstr_w(data), text);
1670 if (!text) return E_INVALIDARG;
1672 *text = NULL;
1674 V_VT(&type) = VT_I1;
1675 V_I1(&type) = NODE_TEXT;
1677 hr = IXMLDOMDocument3_createNode(iface, type, NULL, NULL, &node);
1678 if (hr == S_OK)
1680 IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMText, (void**)text);
1681 IXMLDOMNode_Release(node);
1682 hr = IXMLDOMText_put_data(*text, data);
1685 return hr;
1689 static HRESULT WINAPI domdoc_createComment(
1690 IXMLDOMDocument3 *iface,
1691 BSTR data,
1692 IXMLDOMComment** comment )
1694 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1695 VARIANT type;
1696 HRESULT hr;
1697 IXMLDOMNode *node;
1699 TRACE("(%p)->(%s %p)\n", This, debugstr_w(data), comment);
1701 if (!comment) return E_INVALIDARG;
1703 *comment = NULL;
1705 V_VT(&type) = VT_I1;
1706 V_I1(&type) = NODE_COMMENT;
1708 hr = IXMLDOMDocument3_createNode(iface, type, NULL, NULL, &node);
1709 if (hr == S_OK)
1711 IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMComment, (void**)comment);
1712 IXMLDOMNode_Release(node);
1713 hr = IXMLDOMComment_put_data(*comment, data);
1716 return hr;
1720 static HRESULT WINAPI domdoc_createCDATASection(
1721 IXMLDOMDocument3 *iface,
1722 BSTR data,
1723 IXMLDOMCDATASection** cdata )
1725 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1726 IXMLDOMNode *node;
1727 VARIANT type;
1728 HRESULT hr;
1730 TRACE("(%p)->(%s %p)\n", This, debugstr_w(data), cdata);
1732 if (!cdata) return E_INVALIDARG;
1734 *cdata = NULL;
1736 V_VT(&type) = VT_I1;
1737 V_I1(&type) = NODE_CDATA_SECTION;
1739 hr = IXMLDOMDocument3_createNode(iface, type, NULL, NULL, &node);
1740 if (hr == S_OK)
1742 IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMCDATASection, (void**)cdata);
1743 IXMLDOMNode_Release(node);
1744 hr = IXMLDOMCDATASection_put_data(*cdata, data);
1747 return hr;
1751 static HRESULT WINAPI domdoc_createProcessingInstruction(
1752 IXMLDOMDocument3 *iface,
1753 BSTR target,
1754 BSTR data,
1755 IXMLDOMProcessingInstruction** pi )
1757 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1758 IXMLDOMNode *node;
1759 VARIANT type;
1760 HRESULT hr;
1762 TRACE("(%p)->(%s %s %p)\n", This, debugstr_w(target), debugstr_w(data), pi);
1764 if (!pi) return E_INVALIDARG;
1766 *pi = NULL;
1768 V_VT(&type) = VT_I1;
1769 V_I1(&type) = NODE_PROCESSING_INSTRUCTION;
1771 hr = IXMLDOMDocument3_createNode(iface, type, target, NULL, &node);
1772 if (hr == S_OK)
1774 xmlnode *node_obj;
1776 /* this is to bypass check in ::put_data() that blocks "<?xml" PIs */
1777 node_obj = get_node_obj(node);
1778 hr = node_set_content(node_obj, data);
1780 IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMProcessingInstruction, (void**)pi);
1781 IXMLDOMNode_Release(node);
1784 return hr;
1788 static HRESULT WINAPI domdoc_createAttribute(
1789 IXMLDOMDocument3 *iface,
1790 BSTR name,
1791 IXMLDOMAttribute** attribute )
1793 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1794 IXMLDOMNode *node;
1795 VARIANT type;
1796 HRESULT hr;
1798 TRACE("(%p)->(%s %p)\n", This, debugstr_w(name), attribute);
1800 if (!attribute || !name) return E_INVALIDARG;
1802 V_VT(&type) = VT_I1;
1803 V_I1(&type) = NODE_ATTRIBUTE;
1805 hr = IXMLDOMDocument3_createNode(iface, type, name, NULL, &node);
1806 if (hr == S_OK)
1808 IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMAttribute, (void**)attribute);
1809 IXMLDOMNode_Release(node);
1812 return hr;
1816 static HRESULT WINAPI domdoc_createEntityReference(
1817 IXMLDOMDocument3 *iface,
1818 BSTR name,
1819 IXMLDOMEntityReference** entityref )
1821 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1822 IXMLDOMNode *node;
1823 VARIANT type;
1824 HRESULT hr;
1826 TRACE("(%p)->(%s %p)\n", This, debugstr_w(name), entityref);
1828 if (!entityref) return E_INVALIDARG;
1830 *entityref = NULL;
1832 V_VT(&type) = VT_I1;
1833 V_I1(&type) = NODE_ENTITY_REFERENCE;
1835 hr = IXMLDOMDocument3_createNode(iface, type, name, NULL, &node);
1836 if (hr == S_OK)
1838 IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMEntityReference, (void**)entityref);
1839 IXMLDOMNode_Release(node);
1842 return hr;
1845 xmlChar* tagName_to_XPath(const BSTR tagName)
1847 xmlChar *query, *tmp;
1848 static const xmlChar everything[] = "/descendant::node()";
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 /* Special case - empty tagname - means select all nodes,
1856 except document itself. */
1857 if (!*tagName)
1858 return xmlStrdup(everything);
1860 query = xmlStrdup(prefix);
1862 tokBegin = tagName;
1863 while (tokBegin && *tokBegin)
1865 switch (*tokBegin)
1867 case '/':
1868 query = xmlStrcat(query, BAD_CAST "/");
1869 ++tokBegin;
1870 break;
1871 case '*':
1872 query = xmlStrcat(query, BAD_CAST "*");
1873 ++tokBegin;
1874 break;
1875 default:
1876 query = xmlStrcat(query, mod_pre);
1877 tokEnd = tokBegin;
1878 while (*tokEnd && *tokEnd != '/')
1879 ++tokEnd;
1880 len = WideCharToMultiByte(CP_UTF8, 0, tokBegin, tokEnd-tokBegin, NULL, 0, NULL, NULL);
1881 tmp = xmlMalloc(len);
1882 WideCharToMultiByte(CP_UTF8, 0, tokBegin, tokEnd-tokBegin, (char*)tmp, len, NULL, NULL);
1883 query = xmlStrncat(query, tmp, len);
1884 xmlFree(tmp);
1885 tokBegin = tokEnd;
1886 query = xmlStrcat(query, mod_post);
1890 return query;
1893 static HRESULT WINAPI domdoc_getElementsByTagName(
1894 IXMLDOMDocument3 *iface,
1895 BSTR tagName,
1896 IXMLDOMNodeList** resultList )
1898 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1899 xmlChar *query;
1900 HRESULT hr;
1901 BOOL XPath;
1903 TRACE("(%p)->(%s, %p)\n", This, debugstr_w(tagName), resultList);
1905 if (!tagName || !resultList) return E_INVALIDARG;
1907 XPath = This->properties->XPath;
1908 This->properties->XPath = TRUE;
1909 query = tagName_to_XPath(tagName);
1910 hr = create_selection((xmlNodePtr)get_doc(This), query, resultList);
1911 xmlFree(query);
1912 This->properties->XPath = XPath;
1914 return hr;
1917 static HRESULT get_node_type(VARIANT Type, DOMNodeType * type)
1919 VARIANT tmp;
1920 HRESULT hr;
1922 VariantInit(&tmp);
1923 hr = VariantChangeType(&tmp, &Type, 0, VT_I4);
1924 if(FAILED(hr))
1925 return E_INVALIDARG;
1927 *type = V_I4(&tmp);
1929 return S_OK;
1932 static HRESULT WINAPI domdoc_createNode(
1933 IXMLDOMDocument3 *iface,
1934 VARIANT Type,
1935 BSTR name,
1936 BSTR namespaceURI,
1937 IXMLDOMNode** node )
1939 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1940 DOMNodeType node_type;
1941 xmlNodePtr xmlnode;
1942 xmlChar *xml_name, *href;
1943 HRESULT hr;
1945 TRACE("(%p)->(%s %s %s %p)\n", This, debugstr_variant(&Type), debugstr_w(name), debugstr_w(namespaceURI), node);
1947 if(!node) return E_INVALIDARG;
1949 hr = get_node_type(Type, &node_type);
1950 if(FAILED(hr)) return hr;
1952 TRACE("node_type %d\n", node_type);
1954 /* exit earlier for types that need name */
1955 switch(node_type)
1957 case NODE_ELEMENT:
1958 case NODE_ATTRIBUTE:
1959 case NODE_ENTITY_REFERENCE:
1960 case NODE_PROCESSING_INSTRUCTION:
1961 if (!name || *name == 0) return E_FAIL;
1962 break;
1963 default:
1964 break;
1967 xml_name = xmlchar_from_wchar(name);
1968 /* prevent empty href from being allocated */
1969 href = namespaceURI ? xmlchar_from_wchar(namespaceURI) : NULL;
1971 switch(node_type)
1973 case NODE_ELEMENT:
1975 xmlChar *local, *prefix;
1977 local = xmlSplitQName2(xml_name, &prefix);
1979 xmlnode = xmlNewDocNode(get_doc(This), NULL, local ? local : xml_name, NULL);
1981 /* allow creating the default namespace xmlns= */
1982 if (local || (href && *href))
1984 xmlNsPtr ns = xmlNewNs(xmlnode, href, prefix);
1985 xmlSetNs(xmlnode, ns);
1988 xmlFree(local);
1989 xmlFree(prefix);
1991 break;
1993 case NODE_ATTRIBUTE:
1995 xmlChar *local, *prefix;
1997 local = xmlSplitQName2(xml_name, &prefix);
1999 xmlnode = (xmlNodePtr)xmlNewDocProp(get_doc(This), local ? local : xml_name, NULL);
2001 if (local || (href && *href))
2003 /* we need a floating namespace here, it can't be created linked to attribute from
2004 a start */
2005 xmlNsPtr ns = xmlNewNs(NULL, href, prefix);
2006 xmlSetNs(xmlnode, ns);
2009 xmlFree(local);
2010 xmlFree(prefix);
2012 break;
2014 case NODE_TEXT:
2015 xmlnode = (xmlNodePtr)xmlNewDocText(get_doc(This), NULL);
2016 break;
2017 case NODE_CDATA_SECTION:
2018 xmlnode = xmlNewCDataBlock(get_doc(This), NULL, 0);
2019 break;
2020 case NODE_ENTITY_REFERENCE:
2021 xmlnode = xmlNewReference(get_doc(This), xml_name);
2022 break;
2023 case NODE_PROCESSING_INSTRUCTION:
2024 #ifdef HAVE_XMLNEWDOCPI
2025 xmlnode = xmlNewDocPI(get_doc(This), xml_name, NULL);
2026 #else
2027 FIXME("xmlNewDocPI() not supported, use libxml2 2.6.15 or greater\n");
2028 xmlnode = NULL;
2029 #endif
2030 break;
2031 case NODE_COMMENT:
2032 xmlnode = xmlNewDocComment(get_doc(This), NULL);
2033 break;
2034 case NODE_DOCUMENT_FRAGMENT:
2035 xmlnode = xmlNewDocFragment(get_doc(This));
2036 break;
2037 /* unsupported types */
2038 case NODE_DOCUMENT:
2039 case NODE_DOCUMENT_TYPE:
2040 case NODE_ENTITY:
2041 case NODE_NOTATION:
2042 heap_free(xml_name);
2043 return E_INVALIDARG;
2044 default:
2045 FIXME("unhandled node type %d\n", node_type);
2046 xmlnode = NULL;
2047 break;
2050 *node = create_node(xmlnode);
2051 heap_free(xml_name);
2052 heap_free(href);
2054 if(*node)
2056 TRACE("created node (%d, %p, %p)\n", node_type, *node, xmlnode);
2057 xmldoc_add_orphan(xmlnode->doc, xmlnode);
2058 return S_OK;
2061 return E_FAIL;
2064 static HRESULT WINAPI domdoc_nodeFromID(
2065 IXMLDOMDocument3 *iface,
2066 BSTR idString,
2067 IXMLDOMNode** node )
2069 domdoc *This = impl_from_IXMLDOMDocument3(iface);
2070 FIXME("(%p)->(%s %p)\n", This, debugstr_w(idString), node);
2071 return E_NOTIMPL;
2074 static HRESULT domdoc_onDataAvailable(void *obj, char *ptr, DWORD len)
2076 domdoc *This = obj;
2077 xmlDocPtr xmldoc;
2079 xmldoc = doparse(This, ptr, len, XML_CHAR_ENCODING_NONE);
2080 if(xmldoc) {
2081 xmldoc->_private = create_priv();
2082 return attach_xmldoc(This, xmldoc);
2085 return E_FAIL;
2088 static HRESULT domdoc_load_moniker(domdoc *This, IMoniker *mon)
2090 bsc_t *bsc;
2091 HRESULT hr;
2093 hr = bind_url(mon, domdoc_onDataAvailable, This, &bsc);
2094 if(FAILED(hr))
2095 return hr;
2097 return detach_bsc(bsc);
2100 static HRESULT WINAPI domdoc_load(
2101 IXMLDOMDocument3 *iface,
2102 VARIANT source,
2103 VARIANT_BOOL* isSuccessful )
2105 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2106 LPWSTR filename = NULL;
2107 HRESULT hr = S_FALSE;
2108 xmlDocPtr xmldoc;
2110 TRACE("(%p)->(%s)\n", This, debugstr_variant(&source));
2112 if (!isSuccessful)
2113 return E_POINTER;
2114 *isSuccessful = VARIANT_FALSE;
2116 assert( &This->node );
2118 switch( V_VT(&source) )
2120 case VT_BSTR:
2121 filename = V_BSTR(&source);
2122 break;
2123 case VT_BSTR|VT_BYREF:
2124 if (!V_BSTRREF(&source)) return E_INVALIDARG;
2125 filename = *V_BSTRREF(&source);
2126 break;
2127 case VT_ARRAY|VT_UI1:
2129 SAFEARRAY *psa = V_ARRAY(&source);
2130 char *str;
2131 LONG len;
2132 UINT dim = SafeArrayGetDim(psa);
2134 switch (dim)
2136 case 0:
2137 ERR("SAFEARRAY == NULL\n");
2138 hr = This->error = E_INVALIDARG;
2139 break;
2140 case 1:
2141 /* Only takes UTF-8 strings.
2142 * NOT NULL-terminated. */
2143 hr = SafeArrayAccessData(psa, (void**)&str);
2144 if (FAILED(hr))
2146 This->error = hr;
2147 WARN("failed to access array data, 0x%08x\n", hr);
2148 break;
2150 SafeArrayGetUBound(psa, 1, &len);
2152 if ((xmldoc = doparse(This, str, ++len, XML_CHAR_ENCODING_UTF8)))
2154 hr = This->error = S_OK;
2155 *isSuccessful = VARIANT_TRUE;
2156 TRACE("parsed document %p\n", xmldoc);
2158 else
2160 This->error = E_FAIL;
2161 TRACE("failed to parse document\n");
2164 SafeArrayUnaccessData(psa);
2166 if(xmldoc)
2168 xmldoc->_private = create_priv();
2169 return attach_xmldoc(This, xmldoc);
2171 break;
2172 default:
2173 FIXME("unhandled SAFEARRAY dim: %d\n", dim);
2174 hr = This->error = E_NOTIMPL;
2177 break;
2178 case VT_UNKNOWN:
2180 ISequentialStream *stream = NULL;
2181 IXMLDOMDocument3 *newdoc = NULL;
2183 if (!V_UNKNOWN(&source)) return E_INVALIDARG;
2185 hr = IUnknown_QueryInterface(V_UNKNOWN(&source), &IID_IXMLDOMDocument3, (void**)&newdoc);
2186 if(hr == S_OK)
2188 if(newdoc)
2190 domdoc *newDoc = impl_from_IXMLDOMDocument3( newdoc );
2192 xmldoc = xmlCopyDoc(get_doc(newDoc), 1);
2193 xmldoc->_private = create_priv();
2194 hr = attach_xmldoc(This, xmldoc);
2196 if(SUCCEEDED(hr))
2197 *isSuccessful = VARIANT_TRUE;
2199 return hr;
2203 hr = IUnknown_QueryInterface(V_UNKNOWN(&source), &IID_IStream, (void**)&stream);
2204 if (FAILED(hr))
2205 hr = IUnknown_QueryInterface(V_UNKNOWN(&source), &IID_ISequentialStream, (void**)&stream);
2207 if (hr == S_OK)
2209 hr = domdoc_load_from_stream(This, stream);
2210 if (hr == S_OK)
2211 *isSuccessful = VARIANT_TRUE;
2212 ISequentialStream_Release(stream);
2213 return hr;
2216 FIXME("unsupported IUnknown type (0x%08x) (%p)\n", hr, V_UNKNOWN(&source)->lpVtbl);
2217 break;
2219 default:
2220 FIXME("VT type not supported (%d)\n", V_VT(&source));
2223 if ( filename )
2225 IMoniker *mon;
2227 CoTaskMemFree(This->properties->url);
2228 This->properties->url = NULL;
2230 hr = create_moniker_from_url( filename, &mon);
2231 if ( SUCCEEDED(hr) )
2233 hr = domdoc_load_moniker( This, mon );
2234 if (hr == S_OK)
2235 IMoniker_GetDisplayName(mon, NULL, NULL, &This->properties->url);
2236 IMoniker_Release(mon);
2239 if ( FAILED(hr) )
2240 This->error = E_FAIL;
2241 else
2243 hr = This->error = S_OK;
2244 *isSuccessful = VARIANT_TRUE;
2248 if(!filename || FAILED(hr)) {
2249 xmldoc = xmlNewDoc(NULL);
2250 xmldoc->_private = create_priv();
2251 hr = attach_xmldoc(This, xmldoc);
2252 if(SUCCEEDED(hr))
2253 hr = S_FALSE;
2256 TRACE("ret (%d)\n", hr);
2258 return hr;
2262 static HRESULT WINAPI domdoc_get_readyState(
2263 IXMLDOMDocument3 *iface,
2264 LONG *value )
2266 domdoc *This = impl_from_IXMLDOMDocument3(iface);
2267 FIXME("stub! (%p)->(%p)\n", This, value);
2269 if (!value)
2270 return E_INVALIDARG;
2272 *value = READYSTATE_COMPLETE;
2273 return S_OK;
2277 static HRESULT WINAPI domdoc_get_parseError(
2278 IXMLDOMDocument3 *iface,
2279 IXMLDOMParseError** errorObj )
2281 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2282 static const WCHAR err[] = {'e','r','r','o','r',0};
2283 BSTR error_string = NULL;
2285 FIXME("(%p)->(%p): creating a dummy parseError\n", iface, errorObj);
2287 if(This->error)
2288 error_string = SysAllocString(err);
2290 *errorObj = create_parseError(This->error, NULL, error_string, NULL, 0, 0, 0);
2291 if(!*errorObj) return E_OUTOFMEMORY;
2292 return S_OK;
2296 static HRESULT WINAPI domdoc_get_url(
2297 IXMLDOMDocument3 *iface,
2298 BSTR* url )
2300 domdoc *This = impl_from_IXMLDOMDocument3(iface);
2302 TRACE("(%p)->(%p)\n", This, url);
2304 if (!url)
2305 return E_INVALIDARG;
2307 if (This->properties->url)
2309 *url = SysAllocString(This->properties->url);
2310 if (!*url)
2311 return E_OUTOFMEMORY;
2313 return S_OK;
2315 else
2316 return return_null_bstr(url);
2320 static HRESULT WINAPI domdoc_get_async(
2321 IXMLDOMDocument3 *iface,
2322 VARIANT_BOOL* isAsync )
2324 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2326 TRACE("(%p)->(%p: %d)\n", This, isAsync, This->async);
2327 *isAsync = This->async;
2328 return S_OK;
2332 static HRESULT WINAPI domdoc_put_async(
2333 IXMLDOMDocument3 *iface,
2334 VARIANT_BOOL isAsync )
2336 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2338 TRACE("(%p)->(%d)\n", This, isAsync);
2339 This->async = isAsync;
2340 return S_OK;
2344 static HRESULT WINAPI domdoc_abort(
2345 IXMLDOMDocument3 *iface )
2347 domdoc *This = impl_from_IXMLDOMDocument3(iface);
2348 FIXME("%p\n", This);
2349 return E_NOTIMPL;
2352 /* don't rely on data to be in BSTR format, treat it as WCHAR string */
2353 static HRESULT WINAPI domdoc_loadXML(
2354 IXMLDOMDocument3 *iface,
2355 BSTR data,
2356 VARIANT_BOOL* isSuccessful )
2358 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2359 xmlDocPtr xmldoc = NULL;
2360 HRESULT hr = S_FALSE, hr2;
2362 TRACE("(%p)->(%s %p)\n", This, debugstr_w(data), isSuccessful );
2364 assert ( &This->node );
2366 if ( isSuccessful )
2368 *isSuccessful = VARIANT_FALSE;
2370 if (data)
2372 WCHAR *ptr = data;
2374 /* skip leading spaces if needed */
2375 if (This->properties->version == MSXML_DEFAULT || This->properties->version == MSXML26)
2376 while (*ptr && isspaceW(*ptr)) ptr++;
2378 xmldoc = doparse(This, (char*)ptr, strlenW(ptr)*sizeof(WCHAR), XML_CHAR_ENCODING_UTF16LE);
2379 if ( !xmldoc )
2381 This->error = E_FAIL;
2382 TRACE("failed to parse document\n");
2384 else
2386 hr = This->error = S_OK;
2387 *isSuccessful = VARIANT_TRUE;
2388 TRACE("parsed document %p\n", xmldoc);
2393 if(!xmldoc)
2394 xmldoc = xmlNewDoc(NULL);
2395 xmldoc->_private = create_priv();
2396 hr2 = attach_xmldoc(This, xmldoc);
2397 if( FAILED(hr2) )
2398 hr = hr2;
2400 return hr;
2403 static int XMLCALL domdoc_save_writecallback(void *ctx, const char *buffer, int len)
2405 DWORD written = -1;
2407 if(!WriteFile(ctx, buffer, len, &written, NULL))
2409 WARN("write error\n");
2410 return -1;
2412 else
2413 return written;
2416 static int XMLCALL domdoc_save_closecallback(void *ctx)
2418 return CloseHandle(ctx) ? 0 : -1;
2421 static int XMLCALL domdoc_stream_save_writecallback(void *ctx, const char *buffer, int len)
2423 ULONG written = 0;
2424 HRESULT hr;
2426 hr = IStream_Write((IStream*)ctx, buffer, len, &written);
2427 TRACE("0x%08x %p %d %u\n", hr, buffer, len, written);
2428 if (hr != S_OK)
2430 WARN("stream write error: 0x%08x\n", hr);
2431 return -1;
2433 else
2434 return len;
2437 static int XMLCALL domdoc_stream_save_closecallback(void *ctx)
2439 IStream_Release((IStream*)ctx);
2440 return 0;
2443 static HRESULT WINAPI domdoc_save(
2444 IXMLDOMDocument3 *iface,
2445 VARIANT destination )
2447 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2448 xmlSaveCtxtPtr ctx = NULL;
2449 xmlNodePtr xmldecl;
2450 HRESULT ret = S_OK;
2452 TRACE("(%p)->(%s)\n", This, debugstr_variant(&destination));
2454 switch (V_VT(&destination))
2456 case VT_UNKNOWN:
2458 IUnknown *pUnk = V_UNKNOWN(&destination);
2459 IXMLDOMDocument3 *document;
2460 IStream *stream;
2462 ret = IUnknown_QueryInterface(pUnk, &IID_IXMLDOMDocument3, (void**)&document);
2463 if(ret == S_OK)
2465 VARIANT_BOOL success;
2466 BSTR xml;
2468 ret = IXMLDOMDocument3_get_xml(iface, &xml);
2469 if(ret == S_OK)
2471 ret = IXMLDOMDocument3_loadXML(document, xml, &success);
2472 SysFreeString(xml);
2475 IXMLDOMDocument3_Release(document);
2476 return ret;
2479 ret = IUnknown_QueryInterface(pUnk, &IID_IStream, (void**)&stream);
2480 if(ret == S_OK)
2482 int options = get_doc(This)->standalone == -1 ? XML_SAVE_NO_DECL : 0;
2483 ctx = xmlSaveToIO(domdoc_stream_save_writecallback,
2484 domdoc_stream_save_closecallback, stream, NULL, options);
2486 if(!ctx)
2488 IStream_Release(stream);
2489 return E_FAIL;
2493 break;
2495 case VT_BSTR:
2496 case VT_BSTR | VT_BYREF:
2498 int options = get_doc(This)->standalone == -1 ? XML_SAVE_NO_DECL : 0;
2500 /* save with file path */
2501 HANDLE handle = CreateFileW( (V_VT(&destination) & VT_BYREF)? *V_BSTRREF(&destination) : V_BSTR(&destination),
2502 GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL );
2503 if( handle == INVALID_HANDLE_VALUE )
2505 WARN("failed to create file\n");
2506 return E_FAIL;
2509 /* disable top XML declaration */
2510 ctx = xmlSaveToIO(domdoc_save_writecallback, domdoc_save_closecallback,
2511 handle, NULL, options);
2512 if (!ctx)
2514 CloseHandle(handle);
2515 return E_FAIL;
2518 break;
2520 default:
2521 FIXME("Unhandled VARIANT: %s\n", debugstr_variant(&destination));
2522 return S_FALSE;
2525 xmldecl = xmldoc_unlink_xmldecl(get_doc(This));
2526 if (xmlSaveDoc(ctx, get_doc(This)) == -1) ret = S_FALSE;
2527 xmldoc_link_xmldecl(get_doc(This), xmldecl);
2529 /* will release resources through close callback */
2530 xmlSaveClose(ctx);
2532 return ret;
2535 static HRESULT WINAPI domdoc_get_validateOnParse(
2536 IXMLDOMDocument3 *iface,
2537 VARIANT_BOOL* isValidating )
2539 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2540 TRACE("(%p)->(%p: %d)\n", This, isValidating, This->validating);
2541 *isValidating = This->validating;
2542 return S_OK;
2546 static HRESULT WINAPI domdoc_put_validateOnParse(
2547 IXMLDOMDocument3 *iface,
2548 VARIANT_BOOL isValidating )
2550 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2551 TRACE("(%p)->(%d)\n", This, isValidating);
2552 This->validating = isValidating;
2553 return S_OK;
2557 static HRESULT WINAPI domdoc_get_resolveExternals(
2558 IXMLDOMDocument3 *iface,
2559 VARIANT_BOOL* isResolving )
2561 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2562 TRACE("(%p)->(%p: %d)\n", This, isResolving, This->resolving);
2563 *isResolving = This->resolving;
2564 return S_OK;
2568 static HRESULT WINAPI domdoc_put_resolveExternals(
2569 IXMLDOMDocument3 *iface,
2570 VARIANT_BOOL isResolving )
2572 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2573 TRACE("(%p)->(%d)\n", This, isResolving);
2574 This->resolving = isResolving;
2575 return S_OK;
2579 static HRESULT WINAPI domdoc_get_preserveWhiteSpace(
2580 IXMLDOMDocument3 *iface,
2581 VARIANT_BOOL* isPreserving )
2583 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2584 TRACE("(%p)->(%p: %d)\n", This, isPreserving, This->properties->preserving);
2585 *isPreserving = This->properties->preserving;
2586 return S_OK;
2590 static HRESULT WINAPI domdoc_put_preserveWhiteSpace(
2591 IXMLDOMDocument3 *iface,
2592 VARIANT_BOOL isPreserving )
2594 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2595 TRACE("(%p)->(%d)\n", This, isPreserving);
2596 This->properties->preserving = isPreserving;
2597 return S_OK;
2601 static HRESULT WINAPI domdoc_put_onreadystatechange(
2602 IXMLDOMDocument3 *iface,
2603 VARIANT event )
2605 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2607 TRACE("(%p)->(%s)\n", This, debugstr_variant(&event));
2608 return set_doc_event(This, EVENTID_READYSTATECHANGE, &event);
2612 static HRESULT WINAPI domdoc_put_onDataAvailable(IXMLDOMDocument3 *iface, VARIANT sink)
2614 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2615 FIXME("(%p)->(%s): stub\n", This, debugstr_variant(&sink));
2616 return E_NOTIMPL;
2619 static HRESULT WINAPI domdoc_put_onTransformNode(IXMLDOMDocument3 *iface, VARIANT sink )
2621 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2622 FIXME("(%p)->(%s): stub\n", This, debugstr_variant(&sink));
2623 return E_NOTIMPL;
2626 static HRESULT WINAPI domdoc_get_namespaces(
2627 IXMLDOMDocument3* iface,
2628 IXMLDOMSchemaCollection** collection )
2630 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2631 HRESULT hr;
2633 FIXME("(%p)->(%p): semi-stub\n", This, collection);
2635 if (!collection) return E_POINTER;
2637 if (!This->namespaces)
2639 hr = SchemaCache_create(This->properties->version, (void**)&This->namespaces);
2640 if (hr != S_OK) return hr;
2642 hr = cache_from_doc_ns(This->namespaces, &This->node);
2643 if (hr != S_OK)
2644 release_namespaces(This);
2647 if (This->namespaces)
2648 return IXMLDOMSchemaCollection2_QueryInterface(This->namespaces,
2649 &IID_IXMLDOMSchemaCollection, (void**)collection);
2651 return hr;
2654 static HRESULT WINAPI domdoc_get_schemas(
2655 IXMLDOMDocument3* iface,
2656 VARIANT* schema )
2658 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2659 IXMLDOMSchemaCollection2* cur_schema = This->properties->schemaCache;
2660 HRESULT hr = S_FALSE;
2662 TRACE("(%p)->(%p)\n", This, schema);
2664 V_VT(schema) = VT_NULL;
2665 /* just to reset pointer part, cause that's what application is expected to use */
2666 V_DISPATCH(schema) = NULL;
2668 if(cur_schema)
2670 hr = IXMLDOMSchemaCollection2_QueryInterface(cur_schema, &IID_IDispatch, (void**)&V_DISPATCH(schema));
2671 if(SUCCEEDED(hr))
2672 V_VT(schema) = VT_DISPATCH;
2674 return hr;
2677 static HRESULT WINAPI domdoc_putref_schemas(
2678 IXMLDOMDocument3* iface,
2679 VARIANT schema)
2681 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2682 HRESULT hr = E_FAIL;
2683 IXMLDOMSchemaCollection2* new_schema = NULL;
2685 FIXME("(%p)->(%s): semi-stub\n", This, debugstr_variant(&schema));
2686 switch(V_VT(&schema))
2688 case VT_UNKNOWN:
2689 if (V_UNKNOWN(&schema))
2691 hr = IUnknown_QueryInterface(V_UNKNOWN(&schema), &IID_IXMLDOMSchemaCollection, (void**)&new_schema);
2692 break;
2694 /* fallthrough */
2695 case VT_DISPATCH:
2696 if (V_DISPATCH(&schema))
2698 hr = IDispatch_QueryInterface(V_DISPATCH(&schema), &IID_IXMLDOMSchemaCollection, (void**)&new_schema);
2699 break;
2701 /* fallthrough */
2702 case VT_NULL:
2703 case VT_EMPTY:
2704 hr = S_OK;
2705 break;
2707 default:
2708 WARN("Can't get schema from vt %x\n", V_VT(&schema));
2711 if(SUCCEEDED(hr))
2713 IXMLDOMSchemaCollection2* old_schema = InterlockedExchangePointer((void**)&This->properties->schemaCache, new_schema);
2714 if(old_schema) IXMLDOMSchemaCollection2_Release(old_schema);
2717 return hr;
2720 static inline BOOL is_wellformed(xmlDocPtr doc)
2722 #ifdef HAVE_XMLDOC_PROPERTIES
2723 return doc->properties & XML_DOC_WELLFORMED;
2724 #else
2725 /* Not a full check, but catches the worst violations */
2726 xmlNodePtr child;
2727 int root = 0;
2729 for (child = doc->children; child != NULL; child = child->next)
2731 switch (child->type)
2733 case XML_ELEMENT_NODE:
2734 if (++root > 1)
2735 return FALSE;
2736 break;
2737 case XML_TEXT_NODE:
2738 case XML_CDATA_SECTION_NODE:
2739 return FALSE;
2740 break;
2741 default:
2742 break;
2746 return root == 1;
2747 #endif
2750 static void LIBXML2_LOG_CALLBACK validate_error(void* ctx, char const* msg, ...)
2752 va_list ap;
2753 va_start(ap, msg);
2754 LIBXML2_CALLBACK_ERR(domdoc_validateNode, msg, ap);
2755 va_end(ap);
2758 static void LIBXML2_LOG_CALLBACK validate_warning(void* ctx, char const* msg, ...)
2760 va_list ap;
2761 va_start(ap, msg);
2762 LIBXML2_CALLBACK_WARN(domdoc_validateNode, msg, ap);
2763 va_end(ap);
2766 static HRESULT WINAPI domdoc_validateNode(
2767 IXMLDOMDocument3* iface,
2768 IXMLDOMNode* node,
2769 IXMLDOMParseError** err)
2771 domdoc* This = impl_from_IXMLDOMDocument3(iface);
2772 LONG state, err_code = 0;
2773 HRESULT hr = S_OK;
2774 int validated = 0;
2776 TRACE("(%p)->(%p, %p)\n", This, node, err);
2777 IXMLDOMDocument3_get_readyState(iface, &state);
2778 if (state != READYSTATE_COMPLETE)
2780 if (err)
2781 *err = create_parseError(err_code, NULL, NULL, NULL, 0, 0, 0);
2782 return E_PENDING;
2785 if (!node)
2787 if (err)
2788 *err = create_parseError(err_code, NULL, NULL, NULL, 0, 0, 0);
2789 return E_POINTER;
2792 if (!get_node_obj(node)->node || get_node_obj(node)->node->doc != get_doc(This))
2794 if (err)
2795 *err = create_parseError(err_code, NULL, NULL, NULL, 0, 0, 0);
2796 return E_FAIL;
2799 if (!is_wellformed(get_doc(This)))
2801 ERR("doc not well-formed\n");
2802 if (err)
2803 *err = create_parseError(E_XML_NOTWF, NULL, NULL, NULL, 0, 0, 0);
2804 return S_FALSE;
2807 /* DTD validation */
2808 if (get_doc(This)->intSubset || get_doc(This)->extSubset)
2810 xmlValidCtxtPtr vctx = xmlNewValidCtxt();
2811 vctx->error = validate_error;
2812 vctx->warning = validate_warning;
2813 ++validated;
2815 if (!((node == (IXMLDOMNode*)iface)?
2816 xmlValidateDocument(vctx, get_doc(This)) :
2817 xmlValidateElement(vctx, get_doc(This), get_node_obj(node)->node)))
2819 /* TODO: get a real error code here */
2820 TRACE("DTD validation failed\n");
2821 err_code = E_XML_INVALID;
2822 hr = S_FALSE;
2824 xmlFreeValidCtxt(vctx);
2827 /* Schema validation */
2828 if (hr == S_OK && This->properties->schemaCache != NULL)
2831 hr = SchemaCache_validate_tree(This->properties->schemaCache, get_node_obj(node)->node);
2832 if (SUCCEEDED(hr))
2834 ++validated;
2835 /* TODO: get a real error code here */
2836 if (hr == S_OK)
2838 TRACE("schema validation succeeded\n");
2840 else
2842 ERR("schema validation failed\n");
2843 err_code = E_XML_INVALID;
2846 else
2848 /* not really OK, just didn't find a schema for the ns */
2849 hr = S_OK;
2853 if (!validated)
2855 ERR("no DTD or schema found\n");
2856 err_code = E_XML_NODTD;
2857 hr = S_FALSE;
2860 if (err)
2861 *err = create_parseError(err_code, NULL, NULL, NULL, 0, 0, 0);
2863 return hr;
2866 static HRESULT WINAPI domdoc_validate(
2867 IXMLDOMDocument3* iface,
2868 IXMLDOMParseError** err)
2870 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2871 TRACE("(%p)->(%p)\n", This, err);
2872 return IXMLDOMDocument3_validateNode(iface, (IXMLDOMNode*)iface, err);
2875 static HRESULT WINAPI domdoc_setProperty(
2876 IXMLDOMDocument3* iface,
2877 BSTR p,
2878 VARIANT value)
2880 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2882 TRACE("(%p)->(%s %s)\n", This, debugstr_w(p), debugstr_variant(&value));
2884 if (lstrcmpiW(p, PropertySelectionLanguageW) == 0)
2886 VARIANT varStr;
2887 HRESULT hr;
2888 BSTR bstr;
2890 V_VT(&varStr) = VT_EMPTY;
2891 if (V_VT(&value) != VT_BSTR)
2893 if (FAILED(hr = VariantChangeType(&varStr, &value, 0, VT_BSTR)))
2894 return hr;
2895 bstr = V_BSTR(&varStr);
2897 else
2898 bstr = V_BSTR(&value);
2900 hr = S_OK;
2901 if (lstrcmpiW(bstr, PropValueXPathW) == 0)
2902 This->properties->XPath = TRUE;
2903 else if (lstrcmpiW(bstr, PropValueXSLPatternW) == 0)
2904 This->properties->XPath = FALSE;
2905 else
2906 hr = E_FAIL;
2908 VariantClear(&varStr);
2909 return hr;
2911 else if (lstrcmpiW(p, PropertySelectionNamespacesW) == 0)
2913 xmlChar *nsStr = (xmlChar*)This->properties->selectNsStr;
2914 struct list *pNsList;
2915 VARIANT varStr;
2916 HRESULT hr;
2917 BSTR bstr;
2919 V_VT(&varStr) = VT_EMPTY;
2920 if (V_VT(&value) != VT_BSTR)
2922 if (FAILED(hr = VariantChangeType(&varStr, &value, 0, VT_BSTR)))
2923 return hr;
2924 bstr = V_BSTR(&varStr);
2926 else
2927 bstr = V_BSTR(&value);
2929 hr = S_OK;
2931 pNsList = &(This->properties->selectNsList);
2932 clear_selectNsList(pNsList);
2933 heap_free(nsStr);
2934 nsStr = xmlchar_from_wchar(bstr);
2936 TRACE("property value: \"%s\"\n", debugstr_w(bstr));
2938 This->properties->selectNsStr = nsStr;
2939 This->properties->selectNsStr_len = xmlStrlen(nsStr);
2940 if (bstr && *bstr)
2942 xmlChar *pTokBegin, *pTokEnd, *pTokInner;
2943 select_ns_entry* ns_entry = NULL;
2944 xmlXPathContextPtr ctx;
2946 ctx = xmlXPathNewContext(This->node.node->doc);
2947 pTokBegin = nsStr;
2949 /* skip leading spaces */
2950 while (*pTokBegin == ' ' || *pTokBegin == '\n' ||
2951 *pTokBegin == '\t' || *pTokBegin == '\r')
2952 ++pTokBegin;
2954 for (; *pTokBegin; pTokBegin = pTokEnd)
2956 if (ns_entry)
2957 memset(ns_entry, 0, sizeof(select_ns_entry));
2958 else
2959 ns_entry = heap_alloc_zero(sizeof(select_ns_entry));
2961 while (*pTokBegin == ' ')
2962 ++pTokBegin;
2963 pTokEnd = pTokBegin;
2964 while (*pTokEnd != ' ' && *pTokEnd != 0)
2965 ++pTokEnd;
2967 /* so it failed to advance which means we've got some trailing spaces */
2968 if (pTokEnd == pTokBegin) break;
2970 if (xmlStrncmp(pTokBegin, (xmlChar const*)"xmlns", 5) != 0)
2972 hr = E_FAIL;
2973 WARN("Syntax error in xmlns string: %s\n\tat token: %s\n",
2974 debugstr_w(bstr), debugstr_an((const char*)pTokBegin, pTokEnd-pTokBegin));
2975 continue;
2978 pTokBegin += 5;
2979 if (*pTokBegin == '=')
2981 /*valid for XSLPattern?*/
2982 FIXME("Setting default xmlns not supported - skipping.\n");
2983 continue;
2985 else if (*pTokBegin == ':')
2987 ns_entry->prefix = ++pTokBegin;
2988 for (pTokInner = pTokBegin; pTokInner != pTokEnd && *pTokInner != '='; ++pTokInner)
2991 if (pTokInner == pTokEnd)
2993 hr = E_FAIL;
2994 WARN("Syntax error in xmlns string: %s\n\tat token: %s\n",
2995 debugstr_w(bstr), debugstr_an((const char*)pTokBegin, pTokEnd-pTokBegin));
2996 continue;
2999 ns_entry->prefix_end = *pTokInner;
3000 *pTokInner = 0;
3001 ++pTokInner;
3003 if (pTokEnd-pTokInner > 1 &&
3004 ((*pTokInner == '\'' && *(pTokEnd-1) == '\'') ||
3005 (*pTokInner == '"' && *(pTokEnd-1) == '"')))
3007 ns_entry->href = ++pTokInner;
3008 ns_entry->href_end = *(pTokEnd-1);
3009 *(pTokEnd-1) = 0;
3010 list_add_tail(pNsList, &ns_entry->entry);
3011 /*let libxml figure out if they're valid from here ;)*/
3012 if (xmlXPathRegisterNs(ctx, ns_entry->prefix, ns_entry->href) != 0)
3014 hr = E_FAIL;
3016 ns_entry = NULL;
3017 continue;
3019 else
3021 WARN("Syntax error in xmlns string: %s\n\tat token: %s\n",
3022 debugstr_w(bstr), debugstr_an((const char*)pTokInner, pTokEnd-pTokInner));
3023 list_add_tail(pNsList, &ns_entry->entry);
3025 ns_entry = NULL;
3026 hr = E_FAIL;
3027 continue;
3030 else
3032 hr = E_FAIL;
3033 continue;
3036 heap_free(ns_entry);
3037 xmlXPathFreeContext(ctx);
3040 VariantClear(&varStr);
3041 return hr;
3043 else if (lstrcmpiW(p, PropertyProhibitDTDW) == 0 ||
3044 lstrcmpiW(p, PropertyNewParserW) == 0 ||
3045 lstrcmpiW(p, PropertyResolveExternalsW) == 0)
3047 /* Ignore */
3048 FIXME("Ignoring property %s, value %s\n", debugstr_w(p), debugstr_variant(&value));
3049 return S_OK;
3052 FIXME("Unknown property %s\n", debugstr_w(p));
3053 return E_FAIL;
3056 static HRESULT WINAPI domdoc_getProperty(
3057 IXMLDOMDocument3* iface,
3058 BSTR p,
3059 VARIANT* var)
3061 domdoc *This = impl_from_IXMLDOMDocument3( iface );
3063 TRACE("(%p)->(%s)\n", This, debugstr_w(p));
3065 if (!var)
3066 return E_INVALIDARG;
3068 if (lstrcmpiW(p, PropertySelectionLanguageW) == 0)
3070 V_VT(var) = VT_BSTR;
3071 V_BSTR(var) = This->properties->XPath ?
3072 SysAllocString(PropValueXPathW) :
3073 SysAllocString(PropValueXSLPatternW);
3074 return V_BSTR(var) ? S_OK : E_OUTOFMEMORY;
3076 else if (lstrcmpiW(p, PropertySelectionNamespacesW) == 0)
3078 int lenA, lenW;
3079 BSTR rebuiltStr, cur;
3080 const xmlChar *nsStr;
3081 struct list *pNsList;
3082 select_ns_entry* pNsEntry;
3084 V_VT(var) = VT_BSTR;
3085 nsStr = This->properties->selectNsStr;
3086 pNsList = &This->properties->selectNsList;
3087 lenA = This->properties->selectNsStr_len;
3088 lenW = MultiByteToWideChar(CP_UTF8, 0, (LPCSTR)nsStr, lenA+1, NULL, 0);
3089 rebuiltStr = heap_alloc(lenW*sizeof(WCHAR));
3090 MultiByteToWideChar(CP_UTF8, 0, (LPCSTR)nsStr, lenA+1, rebuiltStr, lenW);
3091 cur = rebuiltStr;
3092 /* this is fine because all of the chars that end tokens are ASCII*/
3093 LIST_FOR_EACH_ENTRY(pNsEntry, pNsList, select_ns_entry, entry)
3095 while (*cur != 0) ++cur;
3096 if (pNsEntry->prefix_end)
3098 *cur = pNsEntry->prefix_end;
3099 while (*cur != 0) ++cur;
3102 if (pNsEntry->href_end)
3104 *cur = pNsEntry->href_end;
3107 V_BSTR(var) = SysAllocString(rebuiltStr);
3108 heap_free(rebuiltStr);
3109 return S_OK;
3112 FIXME("Unknown property %s\n", debugstr_w(p));
3113 return E_FAIL;
3116 static HRESULT WINAPI domdoc_importNode(
3117 IXMLDOMDocument3* iface,
3118 IXMLDOMNode* node,
3119 VARIANT_BOOL deep,
3120 IXMLDOMNode** clone)
3122 domdoc *This = impl_from_IXMLDOMDocument3( iface );
3123 FIXME("(%p)->(%p %d %p): stub\n", This, node, deep, clone);
3124 return E_NOTIMPL;
3127 static const struct IXMLDOMDocument3Vtbl XMLDOMDocument3Vtbl =
3129 domdoc_QueryInterface,
3130 domdoc_AddRef,
3131 domdoc_Release,
3132 domdoc_GetTypeInfoCount,
3133 domdoc_GetTypeInfo,
3134 domdoc_GetIDsOfNames,
3135 domdoc_Invoke,
3136 domdoc_get_nodeName,
3137 domdoc_get_nodeValue,
3138 domdoc_put_nodeValue,
3139 domdoc_get_nodeType,
3140 domdoc_get_parentNode,
3141 domdoc_get_childNodes,
3142 domdoc_get_firstChild,
3143 domdoc_get_lastChild,
3144 domdoc_get_previousSibling,
3145 domdoc_get_nextSibling,
3146 domdoc_get_attributes,
3147 domdoc_insertBefore,
3148 domdoc_replaceChild,
3149 domdoc_removeChild,
3150 domdoc_appendChild,
3151 domdoc_hasChildNodes,
3152 domdoc_get_ownerDocument,
3153 domdoc_cloneNode,
3154 domdoc_get_nodeTypeString,
3155 domdoc_get_text,
3156 domdoc_put_text,
3157 domdoc_get_specified,
3158 domdoc_get_definition,
3159 domdoc_get_nodeTypedValue,
3160 domdoc_put_nodeTypedValue,
3161 domdoc_get_dataType,
3162 domdoc_put_dataType,
3163 domdoc_get_xml,
3164 domdoc_transformNode,
3165 domdoc_selectNodes,
3166 domdoc_selectSingleNode,
3167 domdoc_get_parsed,
3168 domdoc_get_namespaceURI,
3169 domdoc_get_prefix,
3170 domdoc_get_baseName,
3171 domdoc_transformNodeToObject,
3172 domdoc_get_doctype,
3173 domdoc_get_implementation,
3174 domdoc_get_documentElement,
3175 domdoc_put_documentElement,
3176 domdoc_createElement,
3177 domdoc_createDocumentFragment,
3178 domdoc_createTextNode,
3179 domdoc_createComment,
3180 domdoc_createCDATASection,
3181 domdoc_createProcessingInstruction,
3182 domdoc_createAttribute,
3183 domdoc_createEntityReference,
3184 domdoc_getElementsByTagName,
3185 domdoc_createNode,
3186 domdoc_nodeFromID,
3187 domdoc_load,
3188 domdoc_get_readyState,
3189 domdoc_get_parseError,
3190 domdoc_get_url,
3191 domdoc_get_async,
3192 domdoc_put_async,
3193 domdoc_abort,
3194 domdoc_loadXML,
3195 domdoc_save,
3196 domdoc_get_validateOnParse,
3197 domdoc_put_validateOnParse,
3198 domdoc_get_resolveExternals,
3199 domdoc_put_resolveExternals,
3200 domdoc_get_preserveWhiteSpace,
3201 domdoc_put_preserveWhiteSpace,
3202 domdoc_put_onreadystatechange,
3203 domdoc_put_onDataAvailable,
3204 domdoc_put_onTransformNode,
3205 domdoc_get_namespaces,
3206 domdoc_get_schemas,
3207 domdoc_putref_schemas,
3208 domdoc_validate,
3209 domdoc_setProperty,
3210 domdoc_getProperty,
3211 domdoc_validateNode,
3212 domdoc_importNode
3215 /* IConnectionPointContainer */
3216 static HRESULT WINAPI ConnectionPointContainer_QueryInterface(IConnectionPointContainer *iface,
3217 REFIID riid, void **ppv)
3219 domdoc *This = impl_from_IConnectionPointContainer(iface);
3220 return IXMLDOMDocument3_QueryInterface(&This->IXMLDOMDocument3_iface, riid, ppv);
3223 static ULONG WINAPI ConnectionPointContainer_AddRef(IConnectionPointContainer *iface)
3225 domdoc *This = impl_from_IConnectionPointContainer(iface);
3226 return IXMLDOMDocument3_AddRef(&This->IXMLDOMDocument3_iface);
3229 static ULONG WINAPI ConnectionPointContainer_Release(IConnectionPointContainer *iface)
3231 domdoc *This = impl_from_IConnectionPointContainer(iface);
3232 return IXMLDOMDocument3_Release(&This->IXMLDOMDocument3_iface);
3235 static HRESULT WINAPI ConnectionPointContainer_EnumConnectionPoints(IConnectionPointContainer *iface,
3236 IEnumConnectionPoints **ppEnum)
3238 domdoc *This = impl_from_IConnectionPointContainer(iface);
3239 FIXME("(%p)->(%p): stub\n", This, ppEnum);
3240 return E_NOTIMPL;
3243 static HRESULT WINAPI ConnectionPointContainer_FindConnectionPoint(IConnectionPointContainer *iface,
3244 REFIID riid, IConnectionPoint **cp)
3246 domdoc *This = impl_from_IConnectionPointContainer(iface);
3247 ConnectionPoint *iter;
3249 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), cp);
3251 *cp = NULL;
3253 for(iter = This->cp_list; iter; iter = iter->next)
3255 if (IsEqualGUID(iter->iid, riid))
3256 *cp = &iter->IConnectionPoint_iface;
3259 if (*cp)
3261 IConnectionPoint_AddRef(*cp);
3262 return S_OK;
3265 FIXME("unsupported riid %s\n", debugstr_guid(riid));
3266 return CONNECT_E_NOCONNECTION;
3270 static const struct IConnectionPointContainerVtbl ConnectionPointContainerVtbl =
3272 ConnectionPointContainer_QueryInterface,
3273 ConnectionPointContainer_AddRef,
3274 ConnectionPointContainer_Release,
3275 ConnectionPointContainer_EnumConnectionPoints,
3276 ConnectionPointContainer_FindConnectionPoint
3279 /* IConnectionPoint */
3280 static HRESULT WINAPI ConnectionPoint_QueryInterface(IConnectionPoint *iface,
3281 REFIID riid, void **ppv)
3283 ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3285 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv );
3287 *ppv = NULL;
3289 if (IsEqualGUID(&IID_IUnknown, riid) ||
3290 IsEqualGUID(&IID_IConnectionPoint, riid))
3292 *ppv = iface;
3295 if (*ppv)
3297 IConnectionPoint_AddRef(iface);
3298 return S_OK;
3301 WARN("Unsupported interface %s\n", debugstr_guid(riid));
3302 return E_NOINTERFACE;
3305 static ULONG WINAPI ConnectionPoint_AddRef(IConnectionPoint *iface)
3307 ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3308 return IConnectionPointContainer_AddRef(This->container);
3311 static ULONG WINAPI ConnectionPoint_Release(IConnectionPoint *iface)
3313 ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3314 return IConnectionPointContainer_Release(This->container);
3317 static HRESULT WINAPI ConnectionPoint_GetConnectionInterface(IConnectionPoint *iface, IID *iid)
3319 ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3321 TRACE("(%p)->(%p)\n", This, iid);
3323 if (!iid) return E_POINTER;
3325 *iid = *This->iid;
3326 return S_OK;
3329 static HRESULT WINAPI ConnectionPoint_GetConnectionPointContainer(IConnectionPoint *iface,
3330 IConnectionPointContainer **container)
3332 ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3334 TRACE("(%p)->(%p)\n", This, container);
3336 if (!container) return E_POINTER;
3338 *container = This->container;
3339 IConnectionPointContainer_AddRef(*container);
3340 return S_OK;
3343 static HRESULT WINAPI ConnectionPoint_Advise(IConnectionPoint *iface, IUnknown *unk_sink,
3344 DWORD *cookie)
3346 ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3347 IUnknown *sink;
3348 HRESULT hr;
3349 DWORD i;
3351 TRACE("(%p)->(%p %p)\n", This, unk_sink, cookie);
3353 hr = IUnknown_QueryInterface(unk_sink, This->iid, (void**)&sink);
3354 if(FAILED(hr) && !IsEqualGUID(&IID_IPropertyNotifySink, This->iid))
3355 hr = IUnknown_QueryInterface(unk_sink, &IID_IDispatch, (void**)&sink);
3356 if(FAILED(hr))
3357 return CONNECT_E_CANNOTCONNECT;
3359 if(This->sinks)
3361 for (i = 0; i < This->sinks_size; i++)
3362 if (!This->sinks[i].unk)
3363 break;
3365 if (i == This->sinks_size)
3366 This->sinks = heap_realloc(This->sinks,(++This->sinks_size)*sizeof(*This->sinks));
3368 else
3370 This->sinks = heap_alloc(sizeof(*This->sinks));
3371 This->sinks_size = 1;
3372 i = 0;
3375 This->sinks[i].unk = sink;
3376 if (cookie)
3377 *cookie = i+1;
3379 return S_OK;
3382 static HRESULT WINAPI ConnectionPoint_Unadvise(IConnectionPoint *iface, DWORD cookie)
3384 ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3386 TRACE("(%p)->(%d)\n", This, cookie);
3388 if (cookie == 0 || cookie > This->sinks_size || !This->sinks[cookie-1].unk)
3389 return CONNECT_E_NOCONNECTION;
3391 IUnknown_Release(This->sinks[cookie-1].unk);
3392 This->sinks[cookie-1].unk = NULL;
3394 return S_OK;
3397 static HRESULT WINAPI ConnectionPoint_EnumConnections(IConnectionPoint *iface,
3398 IEnumConnections **ppEnum)
3400 ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3401 FIXME("(%p)->(%p): stub\n", This, ppEnum);
3402 return E_NOTIMPL;
3405 static const IConnectionPointVtbl ConnectionPointVtbl =
3407 ConnectionPoint_QueryInterface,
3408 ConnectionPoint_AddRef,
3409 ConnectionPoint_Release,
3410 ConnectionPoint_GetConnectionInterface,
3411 ConnectionPoint_GetConnectionPointContainer,
3412 ConnectionPoint_Advise,
3413 ConnectionPoint_Unadvise,
3414 ConnectionPoint_EnumConnections
3417 static void ConnectionPoint_Init(ConnectionPoint *cp, struct domdoc *doc, REFIID riid)
3419 cp->IConnectionPoint_iface.lpVtbl = &ConnectionPointVtbl;
3420 cp->doc = doc;
3421 cp->iid = riid;
3422 cp->sinks = NULL;
3423 cp->sinks_size = 0;
3425 cp->next = doc->cp_list;
3426 doc->cp_list = cp;
3428 cp->container = &doc->IConnectionPointContainer_iface;
3431 /* domdoc implementation of IObjectWithSite */
3432 static HRESULT WINAPI
3433 domdoc_ObjectWithSite_QueryInterface( IObjectWithSite* iface, REFIID riid, void** ppvObject )
3435 domdoc *This = impl_from_IObjectWithSite(iface);
3436 return IXMLDOMDocument3_QueryInterface(&This->IXMLDOMDocument3_iface, riid, ppvObject);
3439 static ULONG WINAPI domdoc_ObjectWithSite_AddRef( IObjectWithSite* iface )
3441 domdoc *This = impl_from_IObjectWithSite(iface);
3442 return IXMLDOMDocument3_AddRef(&This->IXMLDOMDocument3_iface);
3445 static ULONG WINAPI domdoc_ObjectWithSite_Release( IObjectWithSite* iface )
3447 domdoc *This = impl_from_IObjectWithSite(iface);
3448 return IXMLDOMDocument3_Release(&This->IXMLDOMDocument3_iface);
3451 static HRESULT WINAPI domdoc_ObjectWithSite_GetSite( IObjectWithSite *iface, REFIID iid, void **ppvSite )
3453 domdoc *This = impl_from_IObjectWithSite(iface);
3455 TRACE("(%p)->(%s %p)\n", This, debugstr_guid( iid ), ppvSite );
3457 if ( !This->site )
3458 return E_FAIL;
3460 return IUnknown_QueryInterface( This->site, iid, ppvSite );
3463 static HRESULT WINAPI domdoc_ObjectWithSite_SetSite( IObjectWithSite *iface, IUnknown *punk )
3465 domdoc *This = impl_from_IObjectWithSite(iface);
3467 TRACE("(%p)->(%p)\n", iface, punk);
3469 if(!punk)
3471 if(This->site)
3473 IUnknown_Release( This->site );
3474 This->site = NULL;
3477 return S_OK;
3480 IUnknown_AddRef( punk );
3482 if(This->site)
3483 IUnknown_Release( This->site );
3485 This->site = punk;
3487 return S_OK;
3490 static const IObjectWithSiteVtbl domdocObjectSite =
3492 domdoc_ObjectWithSite_QueryInterface,
3493 domdoc_ObjectWithSite_AddRef,
3494 domdoc_ObjectWithSite_Release,
3495 domdoc_ObjectWithSite_SetSite,
3496 domdoc_ObjectWithSite_GetSite
3499 static HRESULT WINAPI domdoc_Safety_QueryInterface(IObjectSafety *iface, REFIID riid, void **ppv)
3501 domdoc *This = impl_from_IObjectSafety(iface);
3502 return IXMLDOMDocument3_QueryInterface(&This->IXMLDOMDocument3_iface, riid, ppv);
3505 static ULONG WINAPI domdoc_Safety_AddRef(IObjectSafety *iface)
3507 domdoc *This = impl_from_IObjectSafety(iface);
3508 return IXMLDOMDocument3_AddRef(&This->IXMLDOMDocument3_iface);
3511 static ULONG WINAPI domdoc_Safety_Release(IObjectSafety *iface)
3513 domdoc *This = impl_from_IObjectSafety(iface);
3514 return IXMLDOMDocument3_Release(&This->IXMLDOMDocument3_iface);
3517 #define SAFETY_SUPPORTED_OPTIONS (INTERFACESAFE_FOR_UNTRUSTED_CALLER|INTERFACESAFE_FOR_UNTRUSTED_DATA|INTERFACE_USES_SECURITY_MANAGER)
3519 static HRESULT WINAPI domdoc_Safety_GetInterfaceSafetyOptions(IObjectSafety *iface, REFIID riid,
3520 DWORD *supported, DWORD *enabled)
3522 domdoc *This = impl_from_IObjectSafety(iface);
3524 TRACE("(%p)->(%s %p %p)\n", This, debugstr_guid(riid), supported, enabled);
3526 if(!supported || !enabled) return E_POINTER;
3528 *supported = SAFETY_SUPPORTED_OPTIONS;
3529 *enabled = This->safeopt;
3531 return S_OK;
3534 static HRESULT WINAPI domdoc_Safety_SetInterfaceSafetyOptions(IObjectSafety *iface, REFIID riid,
3535 DWORD mask, DWORD enabled)
3537 domdoc *This = impl_from_IObjectSafety(iface);
3538 TRACE("(%p)->(%s %x %x)\n", This, debugstr_guid(riid), mask, enabled);
3540 if ((mask & ~SAFETY_SUPPORTED_OPTIONS) != 0)
3541 return E_FAIL;
3543 This->safeopt = (This->safeopt & ~mask) | (mask & enabled);
3545 return S_OK;
3548 #undef SAFETY_SUPPORTED_OPTIONS
3550 static const IObjectSafetyVtbl domdocObjectSafetyVtbl = {
3551 domdoc_Safety_QueryInterface,
3552 domdoc_Safety_AddRef,
3553 domdoc_Safety_Release,
3554 domdoc_Safety_GetInterfaceSafetyOptions,
3555 domdoc_Safety_SetInterfaceSafetyOptions
3558 static const tid_t domdoc_iface_tids[] = {
3559 IXMLDOMDocument3_tid,
3563 static dispex_static_data_t domdoc_dispex = {
3564 NULL,
3565 IXMLDOMDocument3_tid,
3566 NULL,
3567 domdoc_iface_tids
3570 HRESULT get_domdoc_from_xmldoc(xmlDocPtr xmldoc, IXMLDOMDocument3 **document)
3572 domdoc *doc;
3574 doc = heap_alloc( sizeof (*doc) );
3575 if( !doc )
3576 return E_OUTOFMEMORY;
3578 doc->IXMLDOMDocument3_iface.lpVtbl = &XMLDOMDocument3Vtbl;
3579 doc->IPersistStreamInit_iface.lpVtbl = &xmldoc_IPersistStreamInit_VTable;
3580 doc->IObjectWithSite_iface.lpVtbl = &domdocObjectSite;
3581 doc->IObjectSafety_iface.lpVtbl = &domdocObjectSafetyVtbl;
3582 doc->IConnectionPointContainer_iface.lpVtbl = &ConnectionPointContainerVtbl;
3583 doc->ref = 1;
3584 doc->async = VARIANT_TRUE;
3585 doc->validating = 0;
3586 doc->resolving = 0;
3587 doc->properties = properties_from_xmlDocPtr(xmldoc);
3588 doc->error = S_OK;
3589 doc->site = NULL;
3590 doc->safeopt = 0;
3591 doc->cp_list = NULL;
3592 doc->namespaces = NULL;
3593 memset(doc->events, 0, sizeof(doc->events));
3595 /* events connection points */
3596 ConnectionPoint_Init(&doc->cp_dispatch, doc, &IID_IDispatch);
3597 ConnectionPoint_Init(&doc->cp_propnotif, doc, &IID_IPropertyNotifySink);
3598 ConnectionPoint_Init(&doc->cp_domdocevents, doc, &DIID_XMLDOMDocumentEvents);
3600 init_xmlnode(&doc->node, (xmlNodePtr)xmldoc, (IXMLDOMNode*)&doc->IXMLDOMDocument3_iface,
3601 &domdoc_dispex);
3603 *document = &doc->IXMLDOMDocument3_iface;
3605 TRACE("returning iface %p\n", *document);
3606 return S_OK;
3609 HRESULT DOMDocument_create(MSXML_VERSION version, void **ppObj)
3611 xmlDocPtr xmldoc;
3612 HRESULT hr;
3614 TRACE("(%d, %p)\n", version, ppObj);
3616 xmldoc = xmlNewDoc(NULL);
3617 if(!xmldoc)
3618 return E_OUTOFMEMORY;
3620 xmldoc_init(xmldoc, version);
3622 hr = get_domdoc_from_xmldoc(xmldoc, (IXMLDOMDocument3**)ppObj);
3623 if(FAILED(hr))
3625 free_properties(properties_from_xmlDocPtr(xmldoc));
3626 heap_free(xmldoc->_private);
3627 xmlFreeDoc(xmldoc);
3628 return hr;
3631 return hr;
3634 IUnknown* create_domdoc( xmlNodePtr document )
3636 void* pObj = NULL;
3637 HRESULT hr;
3639 TRACE("(%p)\n", document);
3641 hr = get_domdoc_from_xmldoc((xmlDocPtr)document, (IXMLDOMDocument3**)&pObj);
3642 if (FAILED(hr))
3643 return NULL;
3645 return pObj;
3648 #else
3650 HRESULT DOMDocument_create(MSXML_VERSION version, void **ppObj)
3652 MESSAGE("This program tried to use a DOMDocument object, but\n"
3653 "libxml2 support was not present at compile time.\n");
3654 return E_NOTIMPL;
3657 #endif