user32/tests: Test MDI child order changing caused by WM_MDINEXT.
[wine/multimedia.git] / dlls / msxml3 / domdoc.c
blob7eae2d44bc347f427e83a1c35d1fd99a45a565f8
1 /*
2 * DOM Document implementation
4 * Copyright 2005 Mike McCormack
5 * Copyright 2010-2011 Adam Martinson for CodeWeavers
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
22 #define COBJMACROS
23 #define NONAMELESSUNION
25 #include "config.h"
27 #include <stdarg.h>
28 #include <assert.h>
29 #ifdef HAVE_LIBXML2
30 # include <libxml/parser.h>
31 # include <libxml/xmlerror.h>
32 # include <libxml/xpathInternals.h>
33 # include <libxml/xmlsave.h>
34 # include <libxml/SAX2.h>
35 # include <libxml/parserInternals.h>
36 #endif
38 #include "windef.h"
39 #include "winbase.h"
40 #include "winuser.h"
41 #include "winnls.h"
42 #include "ole2.h"
43 #include "olectl.h"
44 #include "msxml6.h"
45 #include "wininet.h"
46 #include "winreg.h"
47 #include "shlwapi.h"
48 #include "ocidl.h"
49 #include "objsafe.h"
51 #include "wine/debug.h"
52 #include "wine/list.h"
54 #include "msxml_private.h"
56 WINE_DEFAULT_DEBUG_CHANNEL(msxml);
58 #ifdef HAVE_LIBXML2
60 /* not defined in older versions */
61 #define XML_SAVE_FORMAT 1
62 #define XML_SAVE_NO_DECL 2
63 #define XML_SAVE_NO_EMPTY 4
64 #define XML_SAVE_NO_XHTML 8
65 #define XML_SAVE_XHTML 16
66 #define XML_SAVE_AS_XML 32
67 #define XML_SAVE_AS_HTML 64
69 static const WCHAR PropertySelectionLanguageW[] = {'S','e','l','e','c','t','i','o','n','L','a','n','g','u','a','g','e',0};
70 static const WCHAR PropertySelectionNamespacesW[] = {'S','e','l','e','c','t','i','o','n','N','a','m','e','s','p','a','c','e','s',0};
71 static const WCHAR PropertyProhibitDTDW[] = {'P','r','o','h','i','b','i','t','D','T','D',0};
72 static const WCHAR PropertyNewParserW[] = {'N','e','w','P','a','r','s','e','r',0};
73 static const WCHAR PropValueXPathW[] = {'X','P','a','t','h',0};
74 static const WCHAR PropValueXSLPatternW[] = {'X','S','L','P','a','t','t','e','r','n',0};
75 static const WCHAR PropertyResolveExternalsW[] = {'R','e','s','o','l','v','e','E','x','t','e','r','n','a','l','s',0};
77 /* Anything that passes the test_get_ownerDocument()
78 * tests can go here (data shared between all instances).
79 * We need to preserve this when reloading a document,
80 * and also need access to it from the libxml backend. */
81 typedef struct {
82 MSXML_VERSION version;
83 VARIANT_BOOL preserving;
84 IXMLDOMSchemaCollection2* schemaCache;
85 struct list selectNsList;
86 xmlChar const* selectNsStr;
87 LONG selectNsStr_len;
88 BOOL XPath;
89 } domdoc_properties;
91 typedef struct ConnectionPoint ConnectionPoint;
92 typedef struct domdoc domdoc;
94 struct ConnectionPoint
96 IConnectionPoint IConnectionPoint_iface;
97 const IID *iid;
99 ConnectionPoint *next;
100 IConnectionPointContainer *container;
101 domdoc *doc;
103 union
105 IUnknown *unk;
106 IDispatch *disp;
107 IPropertyNotifySink *propnotif;
108 } *sinks;
109 DWORD sinks_size;
112 typedef enum {
113 EVENTID_READYSTATECHANGE = 0,
114 EVENTID_DATAAVAILABLE,
115 EVENTID_TRANSFORMNODE,
116 EVENTID_LAST
117 } eventid_t;
119 struct domdoc
121 xmlnode node;
122 IXMLDOMDocument3 IXMLDOMDocument3_iface;
123 IPersistStreamInit IPersistStreamInit_iface;
124 IObjectWithSite IObjectWithSite_iface;
125 IObjectSafety IObjectSafety_iface;
126 IConnectionPointContainer IConnectionPointContainer_iface;
127 LONG ref;
128 VARIANT_BOOL async;
129 VARIANT_BOOL validating;
130 VARIANT_BOOL resolving;
131 domdoc_properties* properties;
132 bsc_t *bsc;
133 HRESULT error;
135 /* IObjectWithSite*/
136 IUnknown *site;
138 /* IObjectSafety */
139 DWORD safeopt;
141 /* connection list */
142 ConnectionPoint *cp_list;
143 ConnectionPoint cp_domdocevents;
144 ConnectionPoint cp_propnotif;
145 ConnectionPoint cp_dispatch;
147 /* events */
148 IDispatch *events[EVENTID_LAST];
150 IXMLDOMSchemaCollection2 *namespaces;
153 static HRESULT set_doc_event(domdoc *doc, eventid_t eid, const VARIANT *v)
155 IDispatch *disp;
157 switch (V_VT(v))
159 case VT_UNKNOWN:
160 if (V_UNKNOWN(v))
161 IUnknown_QueryInterface(V_UNKNOWN(v), &IID_IDispatch, (void**)&disp);
162 else
163 disp = NULL;
164 break;
165 case VT_DISPATCH:
166 disp = V_DISPATCH(v);
167 if (disp) IDispatch_AddRef(disp);
168 break;
169 default:
170 return DISP_E_TYPEMISMATCH;
173 if (doc->events[eid]) IDispatch_Release(doc->events[eid]);
174 doc->events[eid] = disp;
176 return S_OK;
179 static inline ConnectionPoint *impl_from_IConnectionPoint(IConnectionPoint *iface)
181 return CONTAINING_RECORD(iface, ConnectionPoint, IConnectionPoint_iface);
185 In native windows, the whole lifetime management of XMLDOMNodes is
186 managed automatically using reference counts. Wine emulates that by
187 maintaining a reference count to the document that is increased for
188 each IXMLDOMNode pointer passed out for this document. If all these
189 pointers are gone, the document is unreachable and gets freed, that
190 is, all nodes in the tree of the document get freed.
192 You are able to create nodes that are associated to a document (in
193 fact, in msxml's XMLDOM model, all nodes are associated to a document),
194 but not in the tree of that document, for example using the createFoo
195 functions from IXMLDOMDocument. These nodes do not get cleaned up
196 by libxml, so we have to do it ourselves.
198 To catch these nodes, a list of "orphan nodes" is introduced.
199 It contains pointers to all roots of node trees that are
200 associated with the document without being part of the document
201 tree. All nodes with parent==NULL (except for the document root nodes)
202 should be in the orphan node list of their document. All orphan nodes
203 get freed together with the document itself.
206 typedef struct _xmldoc_priv {
207 LONG refs;
208 struct list orphans;
209 domdoc_properties* properties;
210 } xmldoc_priv;
212 typedef struct _orphan_entry {
213 struct list entry;
214 xmlNode * node;
215 } orphan_entry;
217 typedef struct _select_ns_entry {
218 struct list entry;
219 xmlChar const* prefix;
220 xmlChar prefix_end;
221 xmlChar const* href;
222 xmlChar href_end;
223 } select_ns_entry;
225 static inline xmldoc_priv * priv_from_xmlDocPtr(const xmlDocPtr doc)
227 return doc->_private;
230 static inline domdoc_properties * properties_from_xmlDocPtr(xmlDocPtr doc)
232 return priv_from_xmlDocPtr(doc)->properties;
235 BOOL is_xpathmode(const xmlDocPtr doc)
237 return properties_from_xmlDocPtr(doc)->XPath;
240 void set_xpathmode(xmlDocPtr doc, BOOL xpath)
242 properties_from_xmlDocPtr(doc)->XPath = xpath;
245 int registerNamespaces(xmlXPathContextPtr ctxt)
247 int n = 0;
248 const select_ns_entry* ns = NULL;
249 const struct list* pNsList = &properties_from_xmlDocPtr(ctxt->doc)->selectNsList;
251 TRACE("(%p)\n", ctxt);
253 LIST_FOR_EACH_ENTRY( ns, pNsList, select_ns_entry, entry )
255 xmlXPathRegisterNs(ctxt, ns->prefix, ns->href);
256 ++n;
259 return n;
262 static inline void clear_selectNsList(struct list* pNsList)
264 select_ns_entry *ns, *ns2;
265 LIST_FOR_EACH_ENTRY_SAFE( ns, ns2, pNsList, select_ns_entry, entry )
267 heap_free( ns );
269 list_init(pNsList);
272 static xmldoc_priv * create_priv(void)
274 xmldoc_priv *priv;
275 priv = heap_alloc( sizeof (*priv) );
277 if (priv)
279 priv->refs = 0;
280 list_init( &priv->orphans );
281 priv->properties = NULL;
284 return priv;
287 static domdoc_properties *create_properties(MSXML_VERSION version)
289 domdoc_properties *properties = heap_alloc(sizeof(domdoc_properties));
291 list_init(&properties->selectNsList);
292 properties->preserving = VARIANT_FALSE;
293 properties->schemaCache = NULL;
294 properties->selectNsStr = heap_alloc_zero(sizeof(xmlChar));
295 properties->selectNsStr_len = 0;
297 /* properties that are dependent on object versions */
298 properties->version = version;
299 properties->XPath = (version == MSXML4 || version == MSXML6);
301 return properties;
304 static domdoc_properties* copy_properties(domdoc_properties const* properties)
306 domdoc_properties* pcopy = heap_alloc(sizeof(domdoc_properties));
307 select_ns_entry const* ns = NULL;
308 select_ns_entry* new_ns = NULL;
309 int len = (properties->selectNsStr_len+1)*sizeof(xmlChar);
310 ptrdiff_t offset;
312 if (pcopy)
314 pcopy->version = properties->version;
315 pcopy->preserving = properties->preserving;
316 pcopy->schemaCache = properties->schemaCache;
317 if (pcopy->schemaCache)
318 IXMLDOMSchemaCollection2_AddRef(pcopy->schemaCache);
319 pcopy->XPath = properties->XPath;
320 pcopy->selectNsStr_len = properties->selectNsStr_len;
321 list_init( &pcopy->selectNsList );
322 pcopy->selectNsStr = heap_alloc(len);
323 memcpy((xmlChar*)pcopy->selectNsStr, properties->selectNsStr, len);
324 offset = pcopy->selectNsStr - properties->selectNsStr;
326 LIST_FOR_EACH_ENTRY( ns, (&properties->selectNsList), select_ns_entry, entry )
328 new_ns = heap_alloc(sizeof(select_ns_entry));
329 memcpy(new_ns, ns, sizeof(select_ns_entry));
330 new_ns->href += offset;
331 new_ns->prefix += offset;
332 list_add_tail(&pcopy->selectNsList, &new_ns->entry);
337 return pcopy;
340 static void free_properties(domdoc_properties* properties)
342 if (properties)
344 if (properties->schemaCache)
345 IXMLDOMSchemaCollection2_Release(properties->schemaCache);
346 clear_selectNsList(&properties->selectNsList);
347 heap_free((xmlChar*)properties->selectNsStr);
348 heap_free(properties);
352 static void release_namespaces(domdoc *This)
354 if (This->namespaces)
356 IXMLDOMSchemaCollection2_Release(This->namespaces);
357 This->namespaces = NULL;
361 /* links a "<?xml" node as a first child */
362 void xmldoc_link_xmldecl(xmlDocPtr doc, xmlNodePtr node)
364 assert(doc != NULL);
365 if (doc->standalone != -1) xmlAddPrevSibling( doc->children, node );
368 /* unlinks a first "<?xml" child if it was created */
369 xmlNodePtr xmldoc_unlink_xmldecl(xmlDocPtr doc)
371 static const xmlChar xmlA[] = "xml";
372 xmlNodePtr node, first_child;
374 assert(doc != NULL);
376 /* xml declaration node could be created automatically after parsing or added
377 to a tree later */
378 first_child = doc->children;
379 if (first_child && first_child->type == XML_PI_NODE && xmlStrEqual(first_child->name, xmlA))
381 node = first_child;
382 xmlUnlinkNode( node );
384 else
385 node = NULL;
387 return node;
390 BOOL is_preserving_whitespace(xmlNodePtr node)
392 domdoc_properties* properties = NULL;
393 /* during parsing the xmlDoc._private stuff is not there */
394 if (priv_from_xmlDocPtr(node->doc))
395 properties = properties_from_xmlDocPtr(node->doc);
396 return ((properties && properties->preserving == VARIANT_TRUE) ||
397 xmlNodeGetSpacePreserve(node) == 1);
400 static inline BOOL strn_isspace(xmlChar const* str, int len)
402 for (; str && len > 0 && *str; ++str, --len)
403 if (!isspace(*str))
404 break;
406 return len == 0;
409 static void sax_characters(void *ctx, const xmlChar *ch, int len)
411 xmlParserCtxtPtr ctxt;
412 const domdoc *This;
414 ctxt = (xmlParserCtxtPtr) ctx;
415 This = (const domdoc*) ctxt->_private;
417 if (ctxt->node)
419 xmlChar cur = *(ctxt->input->cur);
421 /* Characters are reported with multiple calls, for example each charref is reported with a separate
422 call and then parser appends it to a single text node or creates a new node if not created.
423 It's not possible to tell if it's ignorable data or not just looking at data itself cause it could be
424 space chars that separate charrefs or similar case. We only need to skip leading and trailing spaces,
425 or whole node if it has nothing but space chars, so to detect leading space node->last is checked that
426 contains text node pointer if already created, trailing spaces are detected directly looking at parser input
427 for next '<' opening bracket - similar logic is used by libxml2 itself. Basically 'cur' == '<' means the last
428 chunk of char data, in case it's not the last chunk we check for previously added node type and if it's not
429 a text node it's safe to ignore.
431 Note that during domdoc_loadXML() the xmlDocPtr->_private data is not available. */
433 if (!This->properties->preserving &&
434 !is_preserving_whitespace(ctxt->node) &&
435 strn_isspace(ch, len) &&
436 (!ctxt->node->last ||
437 ((ctxt->node->last && (cur == '<' || ctxt->node->last->type != XML_TEXT_NODE))
439 return;
442 xmlSAX2Characters(ctxt, ch, len);
445 static void LIBXML2_LOG_CALLBACK sax_error(void* ctx, char const* msg, ...)
447 va_list ap;
448 va_start(ap, msg);
449 LIBXML2_CALLBACK_ERR(doparse, msg, ap);
450 va_end(ap);
453 static void LIBXML2_LOG_CALLBACK sax_warning(void* ctx, char const* msg, ...)
455 va_list ap;
456 va_start(ap, msg);
457 LIBXML2_CALLBACK_WARN(doparse, msg, ap);
458 va_end(ap);
461 static void sax_serror(void* ctx, xmlErrorPtr err)
463 LIBXML2_CALLBACK_SERROR(doparse, err);
466 static xmlDocPtr doparse(domdoc* This, char const* ptr, int len, xmlCharEncoding encoding)
468 xmlDocPtr doc = NULL;
469 xmlParserCtxtPtr pctx;
470 static xmlSAXHandler sax_handler = {
471 xmlSAX2InternalSubset, /* internalSubset */
472 xmlSAX2IsStandalone, /* isStandalone */
473 xmlSAX2HasInternalSubset, /* hasInternalSubset */
474 xmlSAX2HasExternalSubset, /* hasExternalSubset */
475 xmlSAX2ResolveEntity, /* resolveEntity */
476 xmlSAX2GetEntity, /* getEntity */
477 xmlSAX2EntityDecl, /* entityDecl */
478 xmlSAX2NotationDecl, /* notationDecl */
479 xmlSAX2AttributeDecl, /* attributeDecl */
480 xmlSAX2ElementDecl, /* elementDecl */
481 xmlSAX2UnparsedEntityDecl, /* unparsedEntityDecl */
482 xmlSAX2SetDocumentLocator, /* setDocumentLocator */
483 xmlSAX2StartDocument, /* startDocument */
484 xmlSAX2EndDocument, /* endDocument */
485 xmlSAX2StartElement, /* startElement */
486 xmlSAX2EndElement, /* endElement */
487 xmlSAX2Reference, /* reference */
488 sax_characters, /* characters */
489 sax_characters, /* ignorableWhitespace */
490 xmlSAX2ProcessingInstruction, /* processingInstruction */
491 xmlSAX2Comment, /* comment */
492 sax_warning, /* warning */
493 sax_error, /* error */
494 sax_error, /* fatalError */
495 xmlSAX2GetParameterEntity, /* getParameterEntity */
496 xmlSAX2CDataBlock, /* cdataBlock */
497 xmlSAX2ExternalSubset, /* externalSubset */
498 0, /* initialized */
499 NULL, /* _private */
500 xmlSAX2StartElementNs, /* startElementNs */
501 xmlSAX2EndElementNs, /* endElementNs */
502 sax_serror /* serror */
505 pctx = xmlCreateMemoryParserCtxt(ptr, len);
506 if (!pctx)
508 ERR("Failed to create parser context\n");
509 return NULL;
512 if (pctx->sax) xmlFree(pctx->sax);
513 pctx->sax = &sax_handler;
514 pctx->_private = This;
515 pctx->recovery = 0;
517 if (encoding != XML_CHAR_ENCODING_NONE)
518 xmlSwitchEncoding(pctx, encoding);
520 xmlParseDocument(pctx);
522 if (pctx->wellFormed)
524 doc = pctx->myDoc;
526 else
528 xmlFreeDoc(pctx->myDoc);
529 pctx->myDoc = NULL;
531 pctx->sax = NULL;
532 xmlFreeParserCtxt(pctx);
534 /* TODO: put this in one of the SAX callbacks */
535 /* create first child as a <?xml...?> */
536 if (doc && doc->standalone != -1)
538 xmlNodePtr node;
539 char buff[30];
540 xmlChar *xmlbuff = (xmlChar*)buff;
542 node = xmlNewDocPI( doc, (xmlChar*)"xml", NULL );
544 /* version attribute can't be omitted */
545 sprintf(buff, "version=\"%s\"", doc->version ? (char*)doc->version : "1.0");
546 xmlNodeAddContent( node, xmlbuff );
548 if (doc->encoding)
550 sprintf(buff, " encoding=\"%s\"", doc->encoding);
551 xmlNodeAddContent( node, xmlbuff );
554 if (doc->standalone != -2)
556 sprintf(buff, " standalone=\"%s\"", doc->standalone == 0 ? "no" : "yes");
557 xmlNodeAddContent( node, xmlbuff );
560 xmldoc_link_xmldecl( doc, node );
563 return doc;
566 void xmldoc_init(xmlDocPtr doc, MSXML_VERSION version)
568 doc->_private = create_priv();
569 priv_from_xmlDocPtr(doc)->properties = create_properties(version);
572 LONG xmldoc_add_refs(xmlDocPtr doc, LONG refs)
574 LONG ref = InterlockedExchangeAdd(&priv_from_xmlDocPtr(doc)->refs, refs) + refs;
575 TRACE("(%p)->(%d)\n", doc, ref);
576 return ref;
579 LONG xmldoc_add_ref(xmlDocPtr doc)
581 return xmldoc_add_refs(doc, 1);
584 LONG xmldoc_release_refs(xmlDocPtr doc, LONG refs)
586 xmldoc_priv *priv = priv_from_xmlDocPtr(doc);
587 LONG ref = InterlockedExchangeAdd(&priv->refs, -refs) - refs;
588 TRACE("(%p)->(%d)\n", doc, ref);
590 if (ref < 0)
591 WARN("negative refcount, expect troubles\n");
593 if (ref == 0)
595 orphan_entry *orphan, *orphan2;
596 TRACE("freeing docptr %p\n", doc);
598 LIST_FOR_EACH_ENTRY_SAFE( orphan, orphan2, &priv->orphans, orphan_entry, entry )
600 xmlFreeNode( orphan->node );
601 heap_free( orphan );
603 free_properties(priv->properties);
604 heap_free(doc->_private);
606 xmlFreeDoc(doc);
609 return ref;
612 LONG xmldoc_release(xmlDocPtr doc)
614 return xmldoc_release_refs(doc, 1);
617 HRESULT xmldoc_add_orphan(xmlDocPtr doc, xmlNodePtr node)
619 xmldoc_priv *priv = priv_from_xmlDocPtr(doc);
620 orphan_entry *entry;
622 entry = heap_alloc( sizeof (*entry) );
623 if(!entry)
624 return E_OUTOFMEMORY;
626 entry->node = node;
627 list_add_head( &priv->orphans, &entry->entry );
628 return S_OK;
631 HRESULT xmldoc_remove_orphan(xmlDocPtr doc, xmlNodePtr node)
633 xmldoc_priv *priv = priv_from_xmlDocPtr(doc);
634 orphan_entry *entry, *entry2;
636 LIST_FOR_EACH_ENTRY_SAFE( entry, entry2, &priv->orphans, orphan_entry, entry )
638 if( entry->node == node )
640 list_remove( &entry->entry );
641 heap_free( entry );
642 return S_OK;
646 return S_FALSE;
649 static inline xmlDocPtr get_doc( domdoc *This )
651 return This->node.node->doc;
654 static HRESULT attach_xmldoc(domdoc *This, xmlDocPtr xml )
656 release_namespaces(This);
658 if(This->node.node)
660 priv_from_xmlDocPtr(get_doc(This))->properties = NULL;
661 if (xmldoc_release(get_doc(This)) != 0)
662 priv_from_xmlDocPtr(get_doc(This))->properties =
663 copy_properties(This->properties);
666 This->node.node = (xmlNodePtr) xml;
668 if(This->node.node)
670 xmldoc_add_ref(get_doc(This));
671 priv_from_xmlDocPtr(get_doc(This))->properties = This->properties;
674 return S_OK;
677 static inline domdoc *impl_from_IXMLDOMDocument3( IXMLDOMDocument3 *iface )
679 return CONTAINING_RECORD(iface, domdoc, IXMLDOMDocument3_iface);
682 static inline domdoc *impl_from_IPersistStreamInit(IPersistStreamInit *iface)
684 return CONTAINING_RECORD(iface, domdoc, IPersistStreamInit_iface);
687 static inline domdoc *impl_from_IObjectWithSite(IObjectWithSite *iface)
689 return CONTAINING_RECORD(iface, domdoc, IObjectWithSite_iface);
692 static inline domdoc *impl_from_IObjectSafety(IObjectSafety *iface)
694 return CONTAINING_RECORD(iface, domdoc, IObjectSafety_iface);
697 static inline domdoc *impl_from_IConnectionPointContainer(IConnectionPointContainer *iface)
699 return CONTAINING_RECORD(iface, domdoc, IConnectionPointContainer_iface);
702 /************************************************************************
703 * domdoc implementation of IPersistStream.
705 static HRESULT WINAPI PersistStreamInit_QueryInterface(
706 IPersistStreamInit *iface, REFIID riid, void **ppvObj)
708 domdoc* This = impl_from_IPersistStreamInit(iface);
709 return IXMLDOMDocument3_QueryInterface(&This->IXMLDOMDocument3_iface, riid, ppvObj);
712 static ULONG WINAPI PersistStreamInit_AddRef(
713 IPersistStreamInit *iface)
715 domdoc* This = impl_from_IPersistStreamInit(iface);
716 return IXMLDOMDocument3_AddRef(&This->IXMLDOMDocument3_iface);
719 static ULONG WINAPI PersistStreamInit_Release(
720 IPersistStreamInit *iface)
722 domdoc* This = impl_from_IPersistStreamInit(iface);
723 return IXMLDOMDocument3_Release(&This->IXMLDOMDocument3_iface);
726 static HRESULT WINAPI PersistStreamInit_GetClassID(
727 IPersistStreamInit *iface, CLSID *classid)
729 domdoc* This = impl_from_IPersistStreamInit(iface);
730 TRACE("(%p)->(%p)\n", This, classid);
732 if(!classid)
733 return E_POINTER;
735 *classid = *DOMDocument_version(This->properties->version);
737 return S_OK;
740 static HRESULT WINAPI PersistStreamInit_IsDirty(
741 IPersistStreamInit *iface)
743 domdoc *This = impl_from_IPersistStreamInit(iface);
744 FIXME("(%p): stub!\n", This);
745 return S_FALSE;
748 static HRESULT domdoc_load_from_stream(domdoc *doc, ISequentialStream *stream)
750 DWORD read, written, len;
751 xmlDocPtr xmldoc = NULL;
752 IStream *hstream;
753 HGLOBAL hglobal;
754 BYTE buf[4096];
755 HRESULT hr;
756 char *ptr;
758 hstream = NULL;
759 hr = CreateStreamOnHGlobal(NULL, TRUE, &hstream);
760 if (FAILED(hr))
761 return hr;
765 ISequentialStream_Read(stream, buf, sizeof(buf), &read);
766 hr = IStream_Write(hstream, buf, read, &written);
767 } while(SUCCEEDED(hr) && written != 0 && read != 0);
769 if (FAILED(hr))
771 ERR("failed to copy stream 0x%08x\n", hr);
772 IStream_Release(hstream);
773 return hr;
776 hr = GetHGlobalFromStream(hstream, &hglobal);
777 if (FAILED(hr))
778 return hr;
780 len = GlobalSize(hglobal);
781 ptr = GlobalLock(hglobal);
782 if (len)
783 xmldoc = doparse(doc, ptr, len, XML_CHAR_ENCODING_NONE);
784 GlobalUnlock(hglobal);
786 if (!xmldoc)
788 ERR("Failed to parse xml\n");
789 return E_FAIL;
792 xmldoc->_private = create_priv();
794 return attach_xmldoc(doc, xmldoc);
797 static HRESULT WINAPI PersistStreamInit_Load(IPersistStreamInit *iface, IStream *stream)
799 domdoc *This = impl_from_IPersistStreamInit(iface);
801 TRACE("(%p)->(%p)\n", This, stream);
803 if (!stream)
804 return E_INVALIDARG;
806 return domdoc_load_from_stream(This, (ISequentialStream*)stream);
809 static HRESULT WINAPI PersistStreamInit_Save(
810 IPersistStreamInit *iface, IStream *stream, BOOL clr_dirty)
812 domdoc *This = impl_from_IPersistStreamInit(iface);
813 BSTR xmlString;
814 HRESULT hr;
816 TRACE("(%p)->(%p %d)\n", This, stream, clr_dirty);
818 hr = IXMLDOMDocument3_get_xml(&This->IXMLDOMDocument3_iface, &xmlString);
819 if(hr == S_OK)
821 DWORD len = SysStringLen(xmlString) * sizeof(WCHAR);
823 hr = IStream_Write( stream, xmlString, len, NULL );
824 SysFreeString(xmlString);
827 TRACE("ret 0x%08x\n", hr);
829 return hr;
832 static HRESULT WINAPI PersistStreamInit_GetSizeMax(
833 IPersistStreamInit *iface, ULARGE_INTEGER *pcbSize)
835 domdoc *This = impl_from_IPersistStreamInit(iface);
836 TRACE("(%p)->(%p)\n", This, pcbSize);
837 return E_NOTIMPL;
840 static HRESULT WINAPI PersistStreamInit_InitNew(
841 IPersistStreamInit *iface)
843 domdoc *This = impl_from_IPersistStreamInit(iface);
844 TRACE("(%p)\n", This);
845 return S_OK;
848 static const IPersistStreamInitVtbl xmldoc_IPersistStreamInit_VTable =
850 PersistStreamInit_QueryInterface,
851 PersistStreamInit_AddRef,
852 PersistStreamInit_Release,
853 PersistStreamInit_GetClassID,
854 PersistStreamInit_IsDirty,
855 PersistStreamInit_Load,
856 PersistStreamInit_Save,
857 PersistStreamInit_GetSizeMax,
858 PersistStreamInit_InitNew
861 /* IXMLDOMDocument3 interface */
863 static const tid_t domdoc_se_tids[] = {
864 IXMLDOMNode_tid,
865 IXMLDOMDocument_tid,
866 IXMLDOMDocument2_tid,
867 IXMLDOMDocument3_tid,
868 NULL_tid
871 static HRESULT WINAPI domdoc_QueryInterface( IXMLDOMDocument3 *iface, REFIID riid, void** ppvObject )
873 domdoc *This = impl_from_IXMLDOMDocument3( iface );
875 TRACE("(%p)->(%s %p)\n", This, debugstr_guid( riid ), ppvObject );
877 *ppvObject = NULL;
879 if ( IsEqualGUID( riid, &IID_IUnknown ) ||
880 IsEqualGUID( riid, &IID_IDispatch ) ||
881 IsEqualGUID( riid, &IID_IXMLDOMNode ) ||
882 IsEqualGUID( riid, &IID_IXMLDOMDocument ) ||
883 IsEqualGUID( riid, &IID_IXMLDOMDocument2 )||
884 IsEqualGUID( riid, &IID_IXMLDOMDocument3 ))
886 *ppvObject = iface;
888 else if (IsEqualGUID(&IID_IPersistStream, riid) ||
889 IsEqualGUID(&IID_IPersistStreamInit, riid))
891 *ppvObject = &This->IPersistStreamInit_iface;
893 else if (IsEqualGUID(&IID_IObjectWithSite, riid))
895 *ppvObject = &This->IObjectWithSite_iface;
897 else if (IsEqualGUID(&IID_IObjectSafety, riid))
899 *ppvObject = &This->IObjectSafety_iface;
901 else if( IsEqualGUID( riid, &IID_ISupportErrorInfo ))
903 return node_create_supporterrorinfo(domdoc_se_tids, ppvObject);
905 else if(node_query_interface(&This->node, riid, ppvObject))
907 return *ppvObject ? S_OK : E_NOINTERFACE;
909 else if (IsEqualGUID( riid, &IID_IConnectionPointContainer ))
911 *ppvObject = &This->IConnectionPointContainer_iface;
913 else
915 TRACE("interface %s not implemented\n", debugstr_guid(riid));
916 return E_NOINTERFACE;
919 IUnknown_AddRef((IUnknown*)*ppvObject);
921 return S_OK;
924 static ULONG WINAPI domdoc_AddRef( IXMLDOMDocument3 *iface )
926 domdoc *This = impl_from_IXMLDOMDocument3( iface );
927 ULONG ref = InterlockedIncrement( &This->ref );
928 TRACE("(%p)->(%d)\n", This, ref );
929 return ref;
932 static ULONG WINAPI domdoc_Release( IXMLDOMDocument3 *iface )
934 domdoc *This = impl_from_IXMLDOMDocument3( iface );
935 LONG ref = InterlockedDecrement( &This->ref );
937 TRACE("(%p)->(%d)\n", This, ref );
939 if ( ref == 0 )
941 int eid;
943 if(This->bsc)
944 detach_bsc(This->bsc);
946 if (This->site)
947 IUnknown_Release( This->site );
948 destroy_xmlnode(&This->node);
950 for (eid = 0; eid < EVENTID_LAST; eid++)
951 if (This->events[eid]) IDispatch_Release(This->events[eid]);
953 release_namespaces(This);
954 heap_free(This);
957 return ref;
960 static HRESULT WINAPI domdoc_GetTypeInfoCount( IXMLDOMDocument3 *iface, UINT* pctinfo )
962 domdoc *This = impl_from_IXMLDOMDocument3( iface );
963 return IDispatchEx_GetTypeInfoCount(&This->node.dispex.IDispatchEx_iface, pctinfo);
966 static HRESULT WINAPI domdoc_GetTypeInfo(
967 IXMLDOMDocument3 *iface,
968 UINT iTInfo, LCID lcid, ITypeInfo** ppTInfo )
970 domdoc *This = impl_from_IXMLDOMDocument3( iface );
971 return IDispatchEx_GetTypeInfo(&This->node.dispex.IDispatchEx_iface, iTInfo, lcid, ppTInfo);
974 static HRESULT WINAPI domdoc_GetIDsOfNames(
975 IXMLDOMDocument3 *iface,
976 REFIID riid,
977 LPOLESTR* rgszNames,
978 UINT cNames,
979 LCID lcid,
980 DISPID* rgDispId)
982 domdoc *This = impl_from_IXMLDOMDocument3( iface );
983 return IDispatchEx_GetIDsOfNames(&This->node.dispex.IDispatchEx_iface,
984 riid, rgszNames, cNames, lcid, rgDispId);
987 static HRESULT WINAPI domdoc_Invoke(
988 IXMLDOMDocument3 *iface,
989 DISPID dispIdMember,
990 REFIID riid,
991 LCID lcid,
992 WORD wFlags,
993 DISPPARAMS* pDispParams,
994 VARIANT* pVarResult,
995 EXCEPINFO* pExcepInfo,
996 UINT* puArgErr)
998 domdoc *This = impl_from_IXMLDOMDocument3( iface );
999 return IDispatchEx_Invoke(&This->node.dispex.IDispatchEx_iface,
1000 dispIdMember, riid, lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
1003 static HRESULT WINAPI domdoc_get_nodeName(
1004 IXMLDOMDocument3 *iface,
1005 BSTR* name )
1007 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1009 static const WCHAR documentW[] = {'#','d','o','c','u','m','e','n','t',0};
1011 TRACE("(%p)->(%p)\n", This, name);
1013 return return_bstr(documentW, name);
1017 static HRESULT WINAPI domdoc_get_nodeValue(
1018 IXMLDOMDocument3 *iface,
1019 VARIANT* value )
1021 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1023 TRACE("(%p)->(%p)\n", This, value);
1025 if(!value)
1026 return E_INVALIDARG;
1028 V_VT(value) = VT_NULL;
1029 V_BSTR(value) = NULL; /* tests show that we should do this */
1030 return S_FALSE;
1034 static HRESULT WINAPI domdoc_put_nodeValue(
1035 IXMLDOMDocument3 *iface,
1036 VARIANT value)
1038 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1039 TRACE("(%p)->(%s)\n", This, debugstr_variant(&value));
1040 return E_FAIL;
1044 static HRESULT WINAPI domdoc_get_nodeType(
1045 IXMLDOMDocument3 *iface,
1046 DOMNodeType* type )
1048 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1050 TRACE("(%p)->(%p)\n", This, type);
1052 *type = NODE_DOCUMENT;
1053 return S_OK;
1057 static HRESULT WINAPI domdoc_get_parentNode(
1058 IXMLDOMDocument3 *iface,
1059 IXMLDOMNode** parent )
1061 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1063 TRACE("(%p)->(%p)\n", This, parent);
1065 return node_get_parent(&This->node, parent);
1069 static HRESULT WINAPI domdoc_get_childNodes(
1070 IXMLDOMDocument3 *iface,
1071 IXMLDOMNodeList** childList )
1073 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1075 TRACE("(%p)->(%p)\n", This, childList);
1077 return node_get_child_nodes(&This->node, childList);
1081 static HRESULT WINAPI domdoc_get_firstChild(
1082 IXMLDOMDocument3 *iface,
1083 IXMLDOMNode** firstChild )
1085 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1087 TRACE("(%p)->(%p)\n", This, firstChild);
1089 return node_get_first_child(&This->node, firstChild);
1093 static HRESULT WINAPI domdoc_get_lastChild(
1094 IXMLDOMDocument3 *iface,
1095 IXMLDOMNode** lastChild )
1097 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1099 TRACE("(%p)->(%p)\n", This, lastChild);
1101 return node_get_last_child(&This->node, lastChild);
1105 static HRESULT WINAPI domdoc_get_previousSibling(
1106 IXMLDOMDocument3 *iface,
1107 IXMLDOMNode** previousSibling )
1109 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1111 TRACE("(%p)->(%p)\n", This, previousSibling);
1113 return return_null_node(previousSibling);
1117 static HRESULT WINAPI domdoc_get_nextSibling(
1118 IXMLDOMDocument3 *iface,
1119 IXMLDOMNode** nextSibling )
1121 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1123 TRACE("(%p)->(%p)\n", This, nextSibling);
1125 return return_null_node(nextSibling);
1129 static HRESULT WINAPI domdoc_get_attributes(
1130 IXMLDOMDocument3 *iface,
1131 IXMLDOMNamedNodeMap** attributeMap )
1133 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1135 TRACE("(%p)->(%p)\n", This, attributeMap);
1137 return return_null_ptr((void**)attributeMap);
1141 static HRESULT WINAPI domdoc_insertBefore(
1142 IXMLDOMDocument3 *iface,
1143 IXMLDOMNode* newChild,
1144 VARIANT refChild,
1145 IXMLDOMNode** outNewChild )
1147 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1148 DOMNodeType type;
1149 HRESULT hr;
1151 TRACE("(%p)->(%p %s %p)\n", This, newChild, debugstr_variant(&refChild), outNewChild);
1153 hr = IXMLDOMNode_get_nodeType(newChild, &type);
1154 if (hr != S_OK) return hr;
1156 TRACE("new node type %d\n", type);
1157 switch (type)
1159 case NODE_ATTRIBUTE:
1160 case NODE_DOCUMENT:
1161 case NODE_CDATA_SECTION:
1162 if (outNewChild) *outNewChild = NULL;
1163 return E_FAIL;
1164 default:
1165 return node_insert_before(&This->node, newChild, &refChild, outNewChild);
1169 static HRESULT WINAPI domdoc_replaceChild(
1170 IXMLDOMDocument3 *iface,
1171 IXMLDOMNode* newChild,
1172 IXMLDOMNode* oldChild,
1173 IXMLDOMNode** outOldChild)
1175 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1177 TRACE("(%p)->(%p %p %p)\n", This, newChild, oldChild, outOldChild);
1179 return node_replace_child(&This->node, newChild, oldChild, outOldChild);
1183 static HRESULT WINAPI domdoc_removeChild(
1184 IXMLDOMDocument3 *iface,
1185 IXMLDOMNode *child,
1186 IXMLDOMNode **oldChild)
1188 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1189 TRACE("(%p)->(%p %p)\n", This, child, oldChild);
1190 return node_remove_child(&This->node, child, oldChild);
1194 static HRESULT WINAPI domdoc_appendChild(
1195 IXMLDOMDocument3 *iface,
1196 IXMLDOMNode *child,
1197 IXMLDOMNode **outChild)
1199 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1200 TRACE("(%p)->(%p %p)\n", This, child, outChild);
1201 return node_append_child(&This->node, child, outChild);
1205 static HRESULT WINAPI domdoc_hasChildNodes(
1206 IXMLDOMDocument3 *iface,
1207 VARIANT_BOOL *ret)
1209 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1210 TRACE("(%p)->(%p)\n", This, ret);
1211 return node_has_childnodes(&This->node, ret);
1215 static HRESULT WINAPI domdoc_get_ownerDocument(
1216 IXMLDOMDocument3 *iface,
1217 IXMLDOMDocument **doc)
1219 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1220 TRACE("(%p)->(%p)\n", This, doc);
1221 return node_get_owner_doc(&This->node, doc);
1225 static HRESULT WINAPI domdoc_cloneNode(
1226 IXMLDOMDocument3 *iface,
1227 VARIANT_BOOL deep,
1228 IXMLDOMNode** outNode)
1230 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1231 TRACE("(%p)->(%d %p)\n", This, deep, outNode);
1232 return node_clone( &This->node, deep, outNode );
1236 static HRESULT WINAPI domdoc_get_nodeTypeString(
1237 IXMLDOMDocument3 *iface,
1238 BSTR *p)
1240 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1241 static const WCHAR documentW[] = {'d','o','c','u','m','e','n','t',0};
1243 TRACE("(%p)->(%p)\n", This, p);
1245 return return_bstr(documentW, p);
1249 static HRESULT WINAPI domdoc_get_text(
1250 IXMLDOMDocument3 *iface,
1251 BSTR *p)
1253 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1254 TRACE("(%p)->(%p)\n", This, p);
1255 return node_get_text(&This->node, p);
1259 static HRESULT WINAPI domdoc_put_text(
1260 IXMLDOMDocument3 *iface,
1261 BSTR text )
1263 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1264 TRACE("(%p)->(%s)\n", This, debugstr_w(text));
1265 return E_FAIL;
1269 static HRESULT WINAPI domdoc_get_specified(
1270 IXMLDOMDocument3 *iface,
1271 VARIANT_BOOL* isSpecified )
1273 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1274 FIXME("(%p)->(%p) stub!\n", This, isSpecified);
1275 *isSpecified = VARIANT_TRUE;
1276 return S_OK;
1280 static HRESULT WINAPI domdoc_get_definition(
1281 IXMLDOMDocument3 *iface,
1282 IXMLDOMNode** definitionNode )
1284 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1285 FIXME("(%p)->(%p)\n", This, definitionNode);
1286 return E_NOTIMPL;
1290 static HRESULT WINAPI domdoc_get_nodeTypedValue(
1291 IXMLDOMDocument3 *iface,
1292 VARIANT* v )
1294 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1295 TRACE("(%p)->(%p)\n", This, v);
1296 return return_null_var(v);
1299 static HRESULT WINAPI domdoc_put_nodeTypedValue(
1300 IXMLDOMDocument3 *iface,
1301 VARIANT typedValue )
1303 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1304 FIXME("(%p)->(%s)\n", This, debugstr_variant(&typedValue));
1305 return E_NOTIMPL;
1309 static HRESULT WINAPI domdoc_get_dataType(
1310 IXMLDOMDocument3 *iface,
1311 VARIANT* typename )
1313 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1314 TRACE("(%p)->(%p)\n", This, typename);
1315 return return_null_var( typename );
1319 static HRESULT WINAPI domdoc_put_dataType(
1320 IXMLDOMDocument3 *iface,
1321 BSTR dataTypeName )
1323 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1325 FIXME("(%p)->(%s)\n", This, debugstr_w(dataTypeName));
1327 if(!dataTypeName)
1328 return E_INVALIDARG;
1330 return E_FAIL;
1333 static int XMLCALL domdoc_get_xml_writecallback(void *ctx, const char *data, int len)
1335 return xmlBufferAdd((xmlBufferPtr)ctx, (xmlChar*)data, len) == 0 ? len : 0;
1338 static HRESULT WINAPI domdoc_get_xml(
1339 IXMLDOMDocument3 *iface,
1340 BSTR* p)
1342 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1343 xmlSaveCtxtPtr ctxt;
1344 xmlBufferPtr buf;
1345 int options;
1346 long ret;
1348 TRACE("(%p)->(%p)\n", This, p);
1350 if(!p)
1351 return E_INVALIDARG;
1353 *p = NULL;
1355 buf = xmlBufferCreate();
1356 if(!buf)
1357 return E_OUTOFMEMORY;
1359 options = XML_SAVE_FORMAT | XML_SAVE_NO_DECL;
1360 ctxt = xmlSaveToIO(domdoc_get_xml_writecallback, NULL, buf, "UTF-8", options);
1362 if(!ctxt)
1364 xmlBufferFree(buf);
1365 return E_OUTOFMEMORY;
1368 ret = xmlSaveDoc(ctxt, get_doc(This));
1369 /* flushes on close */
1370 xmlSaveClose(ctxt);
1372 TRACE("%ld, len=%d\n", ret, xmlBufferLength(buf));
1373 if(ret != -1 && xmlBufferLength(buf) > 0)
1375 BSTR content;
1377 content = bstr_from_xmlChar(xmlBufferContent(buf));
1378 content = EnsureCorrectEOL(content);
1380 *p = content;
1382 else
1384 *p = SysAllocStringLen(NULL, 0);
1387 xmlBufferFree(buf);
1389 return *p ? S_OK : E_OUTOFMEMORY;
1393 static HRESULT WINAPI domdoc_transformNode(
1394 IXMLDOMDocument3 *iface,
1395 IXMLDOMNode *node,
1396 BSTR *p)
1398 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1399 TRACE("(%p)->(%p %p)\n", This, node, p);
1400 return node_transform_node(&This->node, node, p);
1404 static HRESULT WINAPI domdoc_selectNodes(
1405 IXMLDOMDocument3 *iface,
1406 BSTR p,
1407 IXMLDOMNodeList **outList)
1409 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1410 TRACE("(%p)->(%s %p)\n", This, debugstr_w(p), outList);
1411 return node_select_nodes(&This->node, p, outList);
1415 static HRESULT WINAPI domdoc_selectSingleNode(
1416 IXMLDOMDocument3 *iface,
1417 BSTR p,
1418 IXMLDOMNode **outNode)
1420 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1421 TRACE("(%p)->(%s %p)\n", This, debugstr_w(p), outNode);
1422 return node_select_singlenode(&This->node, p, outNode);
1426 static HRESULT WINAPI domdoc_get_parsed(
1427 IXMLDOMDocument3 *iface,
1428 VARIANT_BOOL* isParsed )
1430 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1431 FIXME("(%p)->(%p) stub!\n", This, isParsed);
1432 *isParsed = VARIANT_TRUE;
1433 return S_OK;
1436 static HRESULT WINAPI domdoc_get_namespaceURI(
1437 IXMLDOMDocument3 *iface,
1438 BSTR* namespaceURI )
1440 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1441 TRACE("(%p)->(%p)\n", This, namespaceURI);
1442 return return_null_bstr( namespaceURI );
1445 static HRESULT WINAPI domdoc_get_prefix(
1446 IXMLDOMDocument3 *iface,
1447 BSTR* prefix )
1449 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1450 TRACE("(%p)->(%p)\n", This, prefix);
1451 return return_null_bstr( prefix );
1455 static HRESULT WINAPI domdoc_get_baseName(
1456 IXMLDOMDocument3 *iface,
1457 BSTR* name )
1459 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1460 TRACE("(%p)->(%p)\n", This, name);
1461 return return_null_bstr( name );
1465 static HRESULT WINAPI domdoc_transformNodeToObject(
1466 IXMLDOMDocument3 *iface,
1467 IXMLDOMNode* stylesheet,
1468 VARIANT outputObject)
1470 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1471 FIXME("(%p)->(%p %s)\n", This, stylesheet, debugstr_variant(&outputObject));
1472 return E_NOTIMPL;
1476 static HRESULT WINAPI domdoc_get_doctype(
1477 IXMLDOMDocument3 *iface,
1478 IXMLDOMDocumentType** doctype )
1480 domdoc *This = impl_from_IXMLDOMDocument3(iface);
1481 IXMLDOMNode *node;
1482 xmlDtdPtr dtd;
1483 HRESULT hr;
1485 TRACE("(%p)->(%p)\n", This, doctype);
1487 if (!doctype) return E_INVALIDARG;
1489 *doctype = NULL;
1491 dtd = xmlGetIntSubset(get_doc(This));
1492 if (!dtd) return S_FALSE;
1494 node = create_node((xmlNodePtr)dtd);
1495 if (!node) return S_FALSE;
1497 hr = IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMDocumentType, (void**)doctype);
1498 IXMLDOMNode_Release(node);
1500 return hr;
1504 static HRESULT WINAPI domdoc_get_implementation(
1505 IXMLDOMDocument3 *iface,
1506 IXMLDOMImplementation** impl )
1508 domdoc *This = impl_from_IXMLDOMDocument3(iface);
1510 TRACE("(%p)->(%p)\n", This, impl);
1512 if(!impl)
1513 return E_INVALIDARG;
1515 *impl = (IXMLDOMImplementation*)create_doc_Implementation();
1517 return S_OK;
1520 static HRESULT WINAPI domdoc_get_documentElement(
1521 IXMLDOMDocument3 *iface,
1522 IXMLDOMElement** DOMElement )
1524 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1525 IXMLDOMNode *element_node;
1526 xmlNodePtr root;
1527 HRESULT hr;
1529 TRACE("(%p)->(%p)\n", This, DOMElement);
1531 if(!DOMElement)
1532 return E_INVALIDARG;
1534 *DOMElement = NULL;
1536 root = xmlDocGetRootElement( get_doc(This) );
1537 if ( !root )
1538 return S_FALSE;
1540 element_node = create_node( root );
1541 if(!element_node) return S_FALSE;
1543 hr = IXMLDOMNode_QueryInterface(element_node, &IID_IXMLDOMElement, (void**)DOMElement);
1544 IXMLDOMNode_Release(element_node);
1546 return hr;
1550 static HRESULT WINAPI domdoc_put_documentElement(
1551 IXMLDOMDocument3 *iface,
1552 IXMLDOMElement* DOMElement )
1554 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1555 IXMLDOMNode *elementNode;
1556 xmlNodePtr oldRoot;
1557 xmlDocPtr old_doc;
1558 xmlnode *xmlNode;
1559 int refcount = 0;
1560 HRESULT hr;
1562 TRACE("(%p)->(%p)\n", This, DOMElement);
1564 hr = IXMLDOMElement_QueryInterface( DOMElement, &IID_IXMLDOMNode, (void**)&elementNode );
1565 if(FAILED(hr))
1566 return hr;
1568 xmlNode = get_node_obj( elementNode );
1569 if(!xmlNode) return E_FAIL;
1571 if(!xmlNode->node->parent)
1572 if(xmldoc_remove_orphan(xmlNode->node->doc, xmlNode->node) != S_OK)
1573 WARN("%p is not an orphan of %p\n", xmlNode->node->doc, xmlNode->node);
1575 old_doc = xmlNode->node->doc;
1576 if (old_doc != get_doc(This))
1577 refcount = xmlnode_get_inst_cnt(xmlNode);
1579 /* old root is still orphaned by its document, update refcount from new root */
1580 if (refcount) xmldoc_add_refs(get_doc(This), refcount);
1581 oldRoot = xmlDocSetRootElement( get_doc(This), xmlNode->node);
1582 if (refcount) xmldoc_release_refs(old_doc, refcount);
1583 IXMLDOMNode_Release( elementNode );
1585 if(oldRoot)
1586 xmldoc_add_orphan(oldRoot->doc, oldRoot);
1588 return S_OK;
1592 static HRESULT WINAPI domdoc_createElement(
1593 IXMLDOMDocument3 *iface,
1594 BSTR tagname,
1595 IXMLDOMElement** element )
1597 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1598 IXMLDOMNode *node;
1599 VARIANT type;
1600 HRESULT hr;
1602 TRACE("(%p)->(%s %p)\n", This, debugstr_w(tagname), element);
1604 if (!element || !tagname) return E_INVALIDARG;
1606 V_VT(&type) = VT_I1;
1607 V_I1(&type) = NODE_ELEMENT;
1609 hr = IXMLDOMDocument3_createNode(iface, type, tagname, NULL, &node);
1610 if (hr == S_OK)
1612 IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMElement, (void**)element);
1613 IXMLDOMNode_Release(node);
1616 return hr;
1620 static HRESULT WINAPI domdoc_createDocumentFragment(
1621 IXMLDOMDocument3 *iface,
1622 IXMLDOMDocumentFragment** frag )
1624 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1625 IXMLDOMNode *node;
1626 VARIANT type;
1627 HRESULT hr;
1629 TRACE("(%p)->(%p)\n", This, frag);
1631 if (!frag) return E_INVALIDARG;
1633 *frag = NULL;
1635 V_VT(&type) = VT_I1;
1636 V_I1(&type) = NODE_DOCUMENT_FRAGMENT;
1638 hr = IXMLDOMDocument3_createNode(iface, type, NULL, NULL, &node);
1639 if (hr == S_OK)
1641 IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMDocumentFragment, (void**)frag);
1642 IXMLDOMNode_Release(node);
1645 return hr;
1649 static HRESULT WINAPI domdoc_createTextNode(
1650 IXMLDOMDocument3 *iface,
1651 BSTR data,
1652 IXMLDOMText** text )
1654 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1655 IXMLDOMNode *node;
1656 VARIANT type;
1657 HRESULT hr;
1659 TRACE("(%p)->(%s %p)\n", This, debugstr_w(data), text);
1661 if (!text) return E_INVALIDARG;
1663 *text = NULL;
1665 V_VT(&type) = VT_I1;
1666 V_I1(&type) = NODE_TEXT;
1668 hr = IXMLDOMDocument3_createNode(iface, type, NULL, NULL, &node);
1669 if (hr == S_OK)
1671 IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMText, (void**)text);
1672 IXMLDOMNode_Release(node);
1673 hr = IXMLDOMText_put_data(*text, data);
1676 return hr;
1680 static HRESULT WINAPI domdoc_createComment(
1681 IXMLDOMDocument3 *iface,
1682 BSTR data,
1683 IXMLDOMComment** comment )
1685 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1686 VARIANT type;
1687 HRESULT hr;
1688 IXMLDOMNode *node;
1690 TRACE("(%p)->(%s %p)\n", This, debugstr_w(data), comment);
1692 if (!comment) return E_INVALIDARG;
1694 *comment = NULL;
1696 V_VT(&type) = VT_I1;
1697 V_I1(&type) = NODE_COMMENT;
1699 hr = IXMLDOMDocument3_createNode(iface, type, NULL, NULL, &node);
1700 if (hr == S_OK)
1702 IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMComment, (void**)comment);
1703 IXMLDOMNode_Release(node);
1704 hr = IXMLDOMComment_put_data(*comment, data);
1707 return hr;
1711 static HRESULT WINAPI domdoc_createCDATASection(
1712 IXMLDOMDocument3 *iface,
1713 BSTR data,
1714 IXMLDOMCDATASection** cdata )
1716 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1717 IXMLDOMNode *node;
1718 VARIANT type;
1719 HRESULT hr;
1721 TRACE("(%p)->(%s %p)\n", This, debugstr_w(data), cdata);
1723 if (!cdata) return E_INVALIDARG;
1725 *cdata = NULL;
1727 V_VT(&type) = VT_I1;
1728 V_I1(&type) = NODE_CDATA_SECTION;
1730 hr = IXMLDOMDocument3_createNode(iface, type, NULL, NULL, &node);
1731 if (hr == S_OK)
1733 IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMCDATASection, (void**)cdata);
1734 IXMLDOMNode_Release(node);
1735 hr = IXMLDOMCDATASection_put_data(*cdata, data);
1738 return hr;
1742 static HRESULT WINAPI domdoc_createProcessingInstruction(
1743 IXMLDOMDocument3 *iface,
1744 BSTR target,
1745 BSTR data,
1746 IXMLDOMProcessingInstruction** pi )
1748 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1749 IXMLDOMNode *node;
1750 VARIANT type;
1751 HRESULT hr;
1753 TRACE("(%p)->(%s %s %p)\n", This, debugstr_w(target), debugstr_w(data), pi);
1755 if (!pi) return E_INVALIDARG;
1757 *pi = NULL;
1759 V_VT(&type) = VT_I1;
1760 V_I1(&type) = NODE_PROCESSING_INSTRUCTION;
1762 hr = IXMLDOMDocument3_createNode(iface, type, target, NULL, &node);
1763 if (hr == S_OK)
1765 xmlnode *node_obj;
1767 /* this is to bypass check in ::put_data() that blocks "<?xml" PIs */
1768 node_obj = get_node_obj(node);
1769 hr = node_set_content(node_obj, data);
1771 IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMProcessingInstruction, (void**)pi);
1772 IXMLDOMNode_Release(node);
1775 return hr;
1779 static HRESULT WINAPI domdoc_createAttribute(
1780 IXMLDOMDocument3 *iface,
1781 BSTR name,
1782 IXMLDOMAttribute** attribute )
1784 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1785 IXMLDOMNode *node;
1786 VARIANT type;
1787 HRESULT hr;
1789 TRACE("(%p)->(%s %p)\n", This, debugstr_w(name), attribute);
1791 if (!attribute || !name) return E_INVALIDARG;
1793 V_VT(&type) = VT_I1;
1794 V_I1(&type) = NODE_ATTRIBUTE;
1796 hr = IXMLDOMDocument3_createNode(iface, type, name, NULL, &node);
1797 if (hr == S_OK)
1799 IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMAttribute, (void**)attribute);
1800 IXMLDOMNode_Release(node);
1803 return hr;
1807 static HRESULT WINAPI domdoc_createEntityReference(
1808 IXMLDOMDocument3 *iface,
1809 BSTR name,
1810 IXMLDOMEntityReference** entityref )
1812 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1813 IXMLDOMNode *node;
1814 VARIANT type;
1815 HRESULT hr;
1817 TRACE("(%p)->(%s %p)\n", This, debugstr_w(name), entityref);
1819 if (!entityref) return E_INVALIDARG;
1821 *entityref = NULL;
1823 V_VT(&type) = VT_I1;
1824 V_I1(&type) = NODE_ENTITY_REFERENCE;
1826 hr = IXMLDOMDocument3_createNode(iface, type, name, NULL, &node);
1827 if (hr == S_OK)
1829 IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMEntityReference, (void**)entityref);
1830 IXMLDOMNode_Release(node);
1833 return hr;
1836 xmlChar* tagName_to_XPath(const BSTR tagName)
1838 xmlChar *query, *tmp;
1839 static const xmlChar mod_pre[] = "*[local-name()='";
1840 static const xmlChar mod_post[] = "']";
1841 static const xmlChar prefix[] = "descendant::";
1842 const WCHAR *tokBegin, *tokEnd;
1843 int len;
1845 query = xmlStrdup(prefix);
1847 tokBegin = tagName;
1848 while (tokBegin && *tokBegin)
1850 switch (*tokBegin)
1852 case '/':
1853 query = xmlStrcat(query, BAD_CAST "/");
1854 ++tokBegin;
1855 break;
1856 case '*':
1857 query = xmlStrcat(query, BAD_CAST "*");
1858 ++tokBegin;
1859 break;
1860 default:
1861 query = xmlStrcat(query, mod_pre);
1862 tokEnd = tokBegin;
1863 while (*tokEnd && *tokEnd != '/')
1864 ++tokEnd;
1865 len = WideCharToMultiByte(CP_UTF8, 0, tokBegin, tokEnd-tokBegin, NULL, 0, NULL, NULL);
1866 tmp = xmlMalloc(len);
1867 WideCharToMultiByte(CP_UTF8, 0, tokBegin, tokEnd-tokBegin, (char*)tmp, len, NULL, NULL);
1868 query = xmlStrncat(query, tmp, len);
1869 xmlFree(tmp);
1870 tokBegin = tokEnd;
1871 query = xmlStrcat(query, mod_post);
1875 return query;
1878 static HRESULT WINAPI domdoc_getElementsByTagName(
1879 IXMLDOMDocument3 *iface,
1880 BSTR tagName,
1881 IXMLDOMNodeList** resultList )
1883 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1884 xmlChar *query;
1885 HRESULT hr;
1886 BOOL XPath;
1888 TRACE("(%p)->(%s, %p)\n", This, debugstr_w(tagName), resultList);
1890 if (!tagName || !resultList) return E_INVALIDARG;
1892 XPath = This->properties->XPath;
1893 This->properties->XPath = TRUE;
1894 query = tagName_to_XPath(tagName);
1895 hr = create_selection((xmlNodePtr)get_doc(This), query, resultList);
1896 xmlFree(query);
1897 This->properties->XPath = XPath;
1899 return hr;
1902 static HRESULT get_node_type(VARIANT Type, DOMNodeType * type)
1904 VARIANT tmp;
1905 HRESULT hr;
1907 VariantInit(&tmp);
1908 hr = VariantChangeType(&tmp, &Type, 0, VT_I4);
1909 if(FAILED(hr))
1910 return E_INVALIDARG;
1912 *type = V_I4(&tmp);
1914 return S_OK;
1917 static HRESULT WINAPI domdoc_createNode(
1918 IXMLDOMDocument3 *iface,
1919 VARIANT Type,
1920 BSTR name,
1921 BSTR namespaceURI,
1922 IXMLDOMNode** node )
1924 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1925 DOMNodeType node_type;
1926 xmlNodePtr xmlnode;
1927 xmlChar *xml_name, *href;
1928 HRESULT hr;
1930 TRACE("(%p)->(%s %s %s %p)\n", This, debugstr_variant(&Type), debugstr_w(name), debugstr_w(namespaceURI), node);
1932 if(!node) return E_INVALIDARG;
1934 hr = get_node_type(Type, &node_type);
1935 if(FAILED(hr)) return hr;
1937 if(namespaceURI && namespaceURI[0] && node_type != NODE_ELEMENT)
1938 FIXME("nodes with namespaces currently not supported.\n");
1940 TRACE("node_type %d\n", node_type);
1942 /* exit earlier for types that need name */
1943 switch(node_type)
1945 case NODE_ELEMENT:
1946 case NODE_ATTRIBUTE:
1947 case NODE_ENTITY_REFERENCE:
1948 case NODE_PROCESSING_INSTRUCTION:
1949 if (!name || *name == 0) return E_FAIL;
1950 break;
1951 default:
1952 break;
1955 xml_name = xmlchar_from_wchar(name);
1956 /* prevent empty href to be allocated */
1957 href = namespaceURI ? xmlchar_from_wchar(namespaceURI) : NULL;
1959 switch(node_type)
1961 case NODE_ELEMENT:
1963 xmlChar *local, *prefix;
1965 local = xmlSplitQName2(xml_name, &prefix);
1967 xmlnode = xmlNewDocNode(get_doc(This), NULL, local ? local : xml_name, NULL);
1969 /* allow to create default namespace xmlns= */
1970 if (local || (href && *href))
1972 xmlNsPtr ns = xmlNewNs(xmlnode, href, prefix);
1973 xmlSetNs(xmlnode, ns);
1976 xmlFree(local);
1977 xmlFree(prefix);
1979 break;
1981 case NODE_ATTRIBUTE:
1982 xmlnode = (xmlNodePtr)xmlNewDocProp(get_doc(This), xml_name, NULL);
1983 break;
1984 case NODE_TEXT:
1985 xmlnode = (xmlNodePtr)xmlNewDocText(get_doc(This), NULL);
1986 break;
1987 case NODE_CDATA_SECTION:
1988 xmlnode = xmlNewCDataBlock(get_doc(This), NULL, 0);
1989 break;
1990 case NODE_ENTITY_REFERENCE:
1991 xmlnode = xmlNewReference(get_doc(This), xml_name);
1992 break;
1993 case NODE_PROCESSING_INSTRUCTION:
1994 #ifdef HAVE_XMLNEWDOCPI
1995 xmlnode = xmlNewDocPI(get_doc(This), xml_name, NULL);
1996 #else
1997 FIXME("xmlNewDocPI() not supported, use libxml2 2.6.15 or greater\n");
1998 xmlnode = NULL;
1999 #endif
2000 break;
2001 case NODE_COMMENT:
2002 xmlnode = xmlNewDocComment(get_doc(This), NULL);
2003 break;
2004 case NODE_DOCUMENT_FRAGMENT:
2005 xmlnode = xmlNewDocFragment(get_doc(This));
2006 break;
2007 /* unsupported types */
2008 case NODE_DOCUMENT:
2009 case NODE_DOCUMENT_TYPE:
2010 case NODE_ENTITY:
2011 case NODE_NOTATION:
2012 heap_free(xml_name);
2013 return E_INVALIDARG;
2014 default:
2015 FIXME("unhandled node type %d\n", node_type);
2016 xmlnode = NULL;
2017 break;
2020 *node = create_node(xmlnode);
2021 heap_free(xml_name);
2022 heap_free(href);
2024 if(*node)
2026 TRACE("created node (%d, %p, %p)\n", node_type, *node, xmlnode);
2027 xmldoc_add_orphan(xmlnode->doc, xmlnode);
2028 return S_OK;
2031 return E_FAIL;
2034 static HRESULT WINAPI domdoc_nodeFromID(
2035 IXMLDOMDocument3 *iface,
2036 BSTR idString,
2037 IXMLDOMNode** node )
2039 domdoc *This = impl_from_IXMLDOMDocument3(iface);
2040 FIXME("(%p)->(%s %p)\n", This, debugstr_w(idString), node);
2041 return E_NOTIMPL;
2044 static HRESULT domdoc_onDataAvailable(void *obj, char *ptr, DWORD len)
2046 domdoc *This = obj;
2047 xmlDocPtr xmldoc;
2049 xmldoc = doparse(This, ptr, len, XML_CHAR_ENCODING_NONE);
2050 if(xmldoc) {
2051 xmldoc->_private = create_priv();
2052 return attach_xmldoc(This, xmldoc);
2055 return S_OK;
2058 static HRESULT domdoc_load_moniker(domdoc *This, IMoniker *mon)
2060 bsc_t *bsc;
2061 HRESULT hr;
2063 hr = bind_url(mon, domdoc_onDataAvailable, This, &bsc);
2064 if(FAILED(hr))
2065 return hr;
2067 if(This->bsc) {
2068 hr = detach_bsc(This->bsc);
2069 if(FAILED(hr))
2070 return hr;
2073 This->bsc = bsc;
2074 return S_OK;
2077 static HRESULT WINAPI domdoc_load(
2078 IXMLDOMDocument3 *iface,
2079 VARIANT source,
2080 VARIANT_BOOL* isSuccessful )
2082 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2083 LPWSTR filename = NULL;
2084 HRESULT hr = S_FALSE;
2085 xmlDocPtr xmldoc;
2087 TRACE("(%p)->(%s)\n", This, debugstr_variant(&source));
2089 if (!isSuccessful)
2090 return E_POINTER;
2091 *isSuccessful = VARIANT_FALSE;
2093 assert( &This->node );
2095 switch( V_VT(&source) )
2097 case VT_BSTR:
2098 filename = V_BSTR(&source);
2099 break;
2100 case VT_BSTR|VT_BYREF:
2101 if (!V_BSTRREF(&source)) return E_INVALIDARG;
2102 filename = *V_BSTRREF(&source);
2103 break;
2104 case VT_ARRAY|VT_UI1:
2106 SAFEARRAY *psa = V_ARRAY(&source);
2107 char *str;
2108 LONG len;
2109 UINT dim = SafeArrayGetDim(psa);
2111 switch (dim)
2113 case 0:
2114 ERR("SAFEARRAY == NULL\n");
2115 hr = This->error = E_INVALIDARG;
2116 break;
2117 case 1:
2118 /* Only takes UTF-8 strings.
2119 * NOT NULL-terminated. */
2120 SafeArrayAccessData(psa, (void**)&str);
2121 SafeArrayGetUBound(psa, 1, &len);
2123 if ((xmldoc = doparse(This, str, ++len, XML_CHAR_ENCODING_UTF8)))
2125 hr = This->error = S_OK;
2126 *isSuccessful = VARIANT_TRUE;
2127 TRACE("parsed document %p\n", xmldoc);
2129 else
2131 This->error = E_FAIL;
2132 TRACE("failed to parse document\n");
2135 SafeArrayUnaccessData(psa);
2137 if(xmldoc)
2139 xmldoc->_private = create_priv();
2140 return attach_xmldoc(This, xmldoc);
2142 break;
2143 default:
2144 FIXME("unhandled SAFEARRAY dim: %d\n", dim);
2145 hr = This->error = E_NOTIMPL;
2148 break;
2149 case VT_UNKNOWN:
2151 ISequentialStream *stream = NULL;
2152 IXMLDOMDocument3 *newdoc = NULL;
2154 if (!V_UNKNOWN(&source)) return E_INVALIDARG;
2156 hr = IUnknown_QueryInterface(V_UNKNOWN(&source), &IID_IXMLDOMDocument3, (void**)&newdoc);
2157 if(hr == S_OK)
2159 if(newdoc)
2161 domdoc *newDoc = impl_from_IXMLDOMDocument3( newdoc );
2163 xmldoc = xmlCopyDoc(get_doc(newDoc), 1);
2164 xmldoc->_private = create_priv();
2165 hr = attach_xmldoc(This, xmldoc);
2167 if(SUCCEEDED(hr))
2168 *isSuccessful = VARIANT_TRUE;
2170 return hr;
2174 hr = IUnknown_QueryInterface(V_UNKNOWN(&source), &IID_IStream, (void**)&stream);
2175 if (FAILED(hr))
2176 hr = IUnknown_QueryInterface(V_UNKNOWN(&source), &IID_ISequentialStream, (void**)&stream);
2178 if (hr == S_OK)
2180 hr = domdoc_load_from_stream(This, stream);
2181 if (hr == S_OK)
2182 *isSuccessful = VARIANT_TRUE;
2183 ISequentialStream_Release(stream);
2184 return hr;
2187 FIXME("unsupported IUnknown type (0x%08x) (%p)\n", hr, V_UNKNOWN(&source)->lpVtbl);
2188 break;
2190 default:
2191 FIXME("VT type not supported (%d)\n", V_VT(&source));
2194 if ( filename )
2196 IMoniker *mon;
2198 hr = create_moniker_from_url( filename, &mon);
2199 if ( SUCCEEDED(hr) )
2201 hr = domdoc_load_moniker( This, mon );
2202 IMoniker_Release(mon);
2205 if ( FAILED(hr) )
2206 This->error = E_FAIL;
2207 else
2209 hr = This->error = S_OK;
2210 *isSuccessful = VARIANT_TRUE;
2214 if(!filename || FAILED(hr)) {
2215 xmldoc = xmlNewDoc(NULL);
2216 xmldoc->_private = create_priv();
2217 hr = attach_xmldoc(This, xmldoc);
2218 if(SUCCEEDED(hr))
2219 hr = S_FALSE;
2222 TRACE("ret (%d)\n", hr);
2224 return hr;
2228 static HRESULT WINAPI domdoc_get_readyState(
2229 IXMLDOMDocument3 *iface,
2230 LONG *value )
2232 domdoc *This = impl_from_IXMLDOMDocument3(iface);
2233 FIXME("stub! (%p)->(%p)\n", This, value);
2235 if (!value)
2236 return E_INVALIDARG;
2238 *value = READYSTATE_COMPLETE;
2239 return S_OK;
2243 static HRESULT WINAPI domdoc_get_parseError(
2244 IXMLDOMDocument3 *iface,
2245 IXMLDOMParseError** errorObj )
2247 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2248 static const WCHAR err[] = {'e','r','r','o','r',0};
2249 BSTR error_string = NULL;
2251 FIXME("(%p)->(%p): creating a dummy parseError\n", iface, errorObj);
2253 if(This->error)
2254 error_string = SysAllocString(err);
2256 *errorObj = create_parseError(This->error, NULL, error_string, NULL, 0, 0, 0);
2257 if(!*errorObj) return E_OUTOFMEMORY;
2258 return S_OK;
2262 static HRESULT WINAPI domdoc_get_url(
2263 IXMLDOMDocument3 *iface,
2264 BSTR* urlString )
2266 domdoc *This = impl_from_IXMLDOMDocument3(iface);
2267 FIXME("(%p)->(%p)\n", This, urlString);
2268 return E_NOTIMPL;
2272 static HRESULT WINAPI domdoc_get_async(
2273 IXMLDOMDocument3 *iface,
2274 VARIANT_BOOL* isAsync )
2276 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2278 TRACE("(%p)->(%p: %d)\n", This, isAsync, This->async);
2279 *isAsync = This->async;
2280 return S_OK;
2284 static HRESULT WINAPI domdoc_put_async(
2285 IXMLDOMDocument3 *iface,
2286 VARIANT_BOOL isAsync )
2288 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2290 TRACE("(%p)->(%d)\n", This, isAsync);
2291 This->async = isAsync;
2292 return S_OK;
2296 static HRESULT WINAPI domdoc_abort(
2297 IXMLDOMDocument3 *iface )
2299 domdoc *This = impl_from_IXMLDOMDocument3(iface);
2300 FIXME("%p\n", This);
2301 return E_NOTIMPL;
2304 /* don't rely on data to be in BSTR format, treat it as WCHAR string */
2305 static HRESULT WINAPI domdoc_loadXML(
2306 IXMLDOMDocument3 *iface,
2307 BSTR data,
2308 VARIANT_BOOL* isSuccessful )
2310 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2311 xmlDocPtr xmldoc = NULL;
2312 HRESULT hr = S_FALSE, hr2;
2314 TRACE("(%p)->(%s %p)\n", This, debugstr_w(data), isSuccessful );
2316 assert ( &This->node );
2318 if ( isSuccessful )
2320 *isSuccessful = VARIANT_FALSE;
2322 if (data)
2324 WCHAR *ptr = data;
2326 /* skip leading spaces if needed */
2327 if (This->properties->version == MSXML_DEFAULT || This->properties->version == MSXML26)
2328 while (*ptr && isspaceW(*ptr)) ptr++;
2330 xmldoc = doparse(This, (char*)ptr, strlenW(ptr)*sizeof(WCHAR), XML_CHAR_ENCODING_UTF16LE);
2331 if ( !xmldoc )
2333 This->error = E_FAIL;
2334 TRACE("failed to parse document\n");
2336 else
2338 hr = This->error = S_OK;
2339 *isSuccessful = VARIANT_TRUE;
2340 TRACE("parsed document %p\n", xmldoc);
2345 if(!xmldoc)
2346 xmldoc = xmlNewDoc(NULL);
2347 xmldoc->_private = create_priv();
2348 hr2 = attach_xmldoc(This, xmldoc);
2349 if( FAILED(hr2) )
2350 hr = hr2;
2352 return hr;
2355 static int XMLCALL domdoc_save_writecallback(void *ctx, const char *buffer, int len)
2357 DWORD written = -1;
2359 if(!WriteFile(ctx, buffer, len, &written, NULL))
2361 WARN("write error\n");
2362 return -1;
2364 else
2365 return written;
2368 static int XMLCALL domdoc_save_closecallback(void *ctx)
2370 return CloseHandle(ctx) ? 0 : -1;
2373 static int XMLCALL domdoc_stream_save_writecallback(void *ctx, const char *buffer, int len)
2375 ULONG written = 0;
2376 HRESULT hr;
2378 hr = IStream_Write((IStream*)ctx, buffer, len, &written);
2379 TRACE("0x%08x %p %d %u\n", hr, buffer, len, written);
2380 if (hr != S_OK)
2382 WARN("stream write error: 0x%08x\n", hr);
2383 return -1;
2385 else
2386 return len;
2389 static int XMLCALL domdoc_stream_save_closecallback(void *ctx)
2391 IStream_Release((IStream*)ctx);
2392 return 0;
2395 static HRESULT WINAPI domdoc_save(
2396 IXMLDOMDocument3 *iface,
2397 VARIANT destination )
2399 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2400 xmlSaveCtxtPtr ctx = NULL;
2401 xmlNodePtr xmldecl;
2402 HRESULT ret = S_OK;
2404 TRACE("(%p)->(%s)\n", This, debugstr_variant(&destination));
2406 switch (V_VT(&destination))
2408 case VT_UNKNOWN:
2410 IUnknown *pUnk = V_UNKNOWN(&destination);
2411 IXMLDOMDocument3 *document;
2412 IStream *stream;
2414 ret = IUnknown_QueryInterface(pUnk, &IID_IXMLDOMDocument3, (void**)&document);
2415 if(ret == S_OK)
2417 VARIANT_BOOL success;
2418 BSTR xml;
2420 ret = IXMLDOMDocument3_get_xml(iface, &xml);
2421 if(ret == S_OK)
2423 ret = IXMLDOMDocument3_loadXML(document, xml, &success);
2424 SysFreeString(xml);
2427 IXMLDOMDocument3_Release(document);
2428 return ret;
2431 ret = IUnknown_QueryInterface(pUnk, &IID_IStream, (void**)&stream);
2432 if(ret == S_OK)
2434 int options = get_doc(This)->standalone == -1 ? XML_SAVE_NO_DECL : 0;
2435 ctx = xmlSaveToIO(domdoc_stream_save_writecallback,
2436 domdoc_stream_save_closecallback, stream, NULL, options);
2438 if(!ctx)
2440 IStream_Release(stream);
2441 return E_FAIL;
2445 break;
2447 case VT_BSTR:
2448 case VT_BSTR | VT_BYREF:
2450 int options = get_doc(This)->standalone == -1 ? XML_SAVE_NO_DECL : 0;
2452 /* save with file path */
2453 HANDLE handle = CreateFileW( (V_VT(&destination) & VT_BYREF)? *V_BSTRREF(&destination) : V_BSTR(&destination),
2454 GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL );
2455 if( handle == INVALID_HANDLE_VALUE )
2457 WARN("failed to create file\n");
2458 return E_FAIL;
2461 /* disable top XML declaration */
2462 ctx = xmlSaveToIO(domdoc_save_writecallback, domdoc_save_closecallback,
2463 handle, NULL, options);
2464 if (!ctx)
2466 CloseHandle(handle);
2467 return E_FAIL;
2470 break;
2472 default:
2473 FIXME("Unhandled VARIANT: %s\n", debugstr_variant(&destination));
2474 return S_FALSE;
2477 xmldecl = xmldoc_unlink_xmldecl(get_doc(This));
2478 if (xmlSaveDoc(ctx, get_doc(This)) == -1) ret = S_FALSE;
2479 xmldoc_link_xmldecl(get_doc(This), xmldecl);
2481 /* will release resources through close callback */
2482 xmlSaveClose(ctx);
2484 return ret;
2487 static HRESULT WINAPI domdoc_get_validateOnParse(
2488 IXMLDOMDocument3 *iface,
2489 VARIANT_BOOL* isValidating )
2491 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2492 TRACE("(%p)->(%p: %d)\n", This, isValidating, This->validating);
2493 *isValidating = This->validating;
2494 return S_OK;
2498 static HRESULT WINAPI domdoc_put_validateOnParse(
2499 IXMLDOMDocument3 *iface,
2500 VARIANT_BOOL isValidating )
2502 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2503 TRACE("(%p)->(%d)\n", This, isValidating);
2504 This->validating = isValidating;
2505 return S_OK;
2509 static HRESULT WINAPI domdoc_get_resolveExternals(
2510 IXMLDOMDocument3 *iface,
2511 VARIANT_BOOL* isResolving )
2513 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2514 TRACE("(%p)->(%p: %d)\n", This, isResolving, This->resolving);
2515 *isResolving = This->resolving;
2516 return S_OK;
2520 static HRESULT WINAPI domdoc_put_resolveExternals(
2521 IXMLDOMDocument3 *iface,
2522 VARIANT_BOOL isResolving )
2524 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2525 TRACE("(%p)->(%d)\n", This, isResolving);
2526 This->resolving = isResolving;
2527 return S_OK;
2531 static HRESULT WINAPI domdoc_get_preserveWhiteSpace(
2532 IXMLDOMDocument3 *iface,
2533 VARIANT_BOOL* isPreserving )
2535 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2536 TRACE("(%p)->(%p: %d)\n", This, isPreserving, This->properties->preserving);
2537 *isPreserving = This->properties->preserving;
2538 return S_OK;
2542 static HRESULT WINAPI domdoc_put_preserveWhiteSpace(
2543 IXMLDOMDocument3 *iface,
2544 VARIANT_BOOL isPreserving )
2546 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2547 TRACE("(%p)->(%d)\n", This, isPreserving);
2548 This->properties->preserving = isPreserving;
2549 return S_OK;
2553 static HRESULT WINAPI domdoc_put_onreadystatechange(
2554 IXMLDOMDocument3 *iface,
2555 VARIANT event )
2557 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2559 TRACE("(%p)->(%s)\n", This, debugstr_variant(&event));
2560 return set_doc_event(This, EVENTID_READYSTATECHANGE, &event);
2564 static HRESULT WINAPI domdoc_put_onDataAvailable(IXMLDOMDocument3 *iface, VARIANT sink)
2566 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2567 FIXME("(%p)->(%s): stub\n", This, debugstr_variant(&sink));
2568 return E_NOTIMPL;
2571 static HRESULT WINAPI domdoc_put_onTransformNode(IXMLDOMDocument3 *iface, VARIANT sink )
2573 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2574 FIXME("(%p)->(%s): stub\n", This, debugstr_variant(&sink));
2575 return E_NOTIMPL;
2578 static HRESULT WINAPI domdoc_get_namespaces(
2579 IXMLDOMDocument3* iface,
2580 IXMLDOMSchemaCollection** collection )
2582 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2583 HRESULT hr;
2585 FIXME("(%p)->(%p): semi-stub\n", This, collection);
2587 if (!collection) return E_POINTER;
2589 if (!This->namespaces)
2591 hr = SchemaCache_create(This->properties->version, NULL, (void**)&This->namespaces);
2592 if (hr != S_OK) return hr;
2594 hr = cache_from_doc_ns(This->namespaces, &This->node);
2595 if (hr != S_OK)
2596 release_namespaces(This);
2599 if (This->namespaces)
2600 return IXMLDOMSchemaCollection2_QueryInterface(This->namespaces,
2601 &IID_IXMLDOMSchemaCollection, (void**)collection);
2603 return hr;
2606 static HRESULT WINAPI domdoc_get_schemas(
2607 IXMLDOMDocument3* iface,
2608 VARIANT* schema )
2610 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2611 IXMLDOMSchemaCollection2* cur_schema = This->properties->schemaCache;
2612 HRESULT hr = S_FALSE;
2614 TRACE("(%p)->(%p)\n", This, schema);
2616 V_VT(schema) = VT_NULL;
2617 /* just to reset pointer part, cause that's what application is expected to use */
2618 V_DISPATCH(schema) = NULL;
2620 if(cur_schema)
2622 hr = IXMLDOMSchemaCollection2_QueryInterface(cur_schema, &IID_IDispatch, (void**)&V_DISPATCH(schema));
2623 if(SUCCEEDED(hr))
2624 V_VT(schema) = VT_DISPATCH;
2626 return hr;
2629 static HRESULT WINAPI domdoc_putref_schemas(
2630 IXMLDOMDocument3* iface,
2631 VARIANT schema)
2633 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2634 HRESULT hr = E_FAIL;
2635 IXMLDOMSchemaCollection2* new_schema = NULL;
2637 FIXME("(%p)->(%s): semi-stub\n", This, debugstr_variant(&schema));
2638 switch(V_VT(&schema))
2640 case VT_UNKNOWN:
2641 if (V_UNKNOWN(&schema))
2643 hr = IUnknown_QueryInterface(V_UNKNOWN(&schema), &IID_IXMLDOMSchemaCollection, (void**)&new_schema);
2644 break;
2646 /* fallthrough */
2647 case VT_DISPATCH:
2648 if (V_DISPATCH(&schema))
2650 hr = IDispatch_QueryInterface(V_DISPATCH(&schema), &IID_IXMLDOMSchemaCollection, (void**)&new_schema);
2651 break;
2653 /* fallthrough */
2654 case VT_NULL:
2655 case VT_EMPTY:
2656 hr = S_OK;
2657 break;
2659 default:
2660 WARN("Can't get schema from vt %x\n", V_VT(&schema));
2663 if(SUCCEEDED(hr))
2665 IXMLDOMSchemaCollection2* old_schema = InterlockedExchangePointer((void**)&This->properties->schemaCache, new_schema);
2666 if(old_schema) IXMLDOMSchemaCollection2_Release(old_schema);
2669 return hr;
2672 static inline BOOL is_wellformed(xmlDocPtr doc)
2674 #ifdef HAVE_XMLDOC_PROPERTIES
2675 return doc->properties & XML_DOC_WELLFORMED;
2676 #else
2677 /* Not a full check, but catches the worst violations */
2678 xmlNodePtr child;
2679 int root = 0;
2681 for (child = doc->children; child != NULL; child = child->next)
2683 switch (child->type)
2685 case XML_ELEMENT_NODE:
2686 if (++root > 1)
2687 return FALSE;
2688 break;
2689 case XML_TEXT_NODE:
2690 case XML_CDATA_SECTION_NODE:
2691 return FALSE;
2692 break;
2693 default:
2694 break;
2698 return root == 1;
2699 #endif
2702 static void LIBXML2_LOG_CALLBACK validate_error(void* ctx, char const* msg, ...)
2704 va_list ap;
2705 va_start(ap, msg);
2706 LIBXML2_CALLBACK_ERR(domdoc_validateNode, msg, ap);
2707 va_end(ap);
2710 static void LIBXML2_LOG_CALLBACK validate_warning(void* ctx, char const* msg, ...)
2712 va_list ap;
2713 va_start(ap, msg);
2714 LIBXML2_CALLBACK_WARN(domdoc_validateNode, msg, ap);
2715 va_end(ap);
2718 static HRESULT WINAPI domdoc_validateNode(
2719 IXMLDOMDocument3* iface,
2720 IXMLDOMNode* node,
2721 IXMLDOMParseError** err)
2723 domdoc* This = impl_from_IXMLDOMDocument3(iface);
2724 LONG state, err_code = 0;
2725 HRESULT hr = S_OK;
2726 int validated = 0;
2728 TRACE("(%p)->(%p, %p)\n", This, node, err);
2729 IXMLDOMDocument3_get_readyState(iface, &state);
2730 if (state != READYSTATE_COMPLETE)
2732 if (err)
2733 *err = create_parseError(err_code, NULL, NULL, NULL, 0, 0, 0);
2734 return E_PENDING;
2737 if (!node)
2739 if (err)
2740 *err = create_parseError(err_code, NULL, NULL, NULL, 0, 0, 0);
2741 return E_POINTER;
2744 if (!get_node_obj(node)->node || get_node_obj(node)->node->doc != get_doc(This))
2746 if (err)
2747 *err = create_parseError(err_code, NULL, NULL, NULL, 0, 0, 0);
2748 return E_FAIL;
2751 if (!is_wellformed(get_doc(This)))
2753 ERR("doc not well-formed\n");
2754 if (err)
2755 *err = create_parseError(E_XML_NOTWF, NULL, NULL, NULL, 0, 0, 0);
2756 return S_FALSE;
2759 /* DTD validation */
2760 if (get_doc(This)->intSubset || get_doc(This)->extSubset)
2762 xmlValidCtxtPtr vctx = xmlNewValidCtxt();
2763 vctx->error = validate_error;
2764 vctx->warning = validate_warning;
2765 ++validated;
2767 if (!((node == (IXMLDOMNode*)iface)?
2768 xmlValidateDocument(vctx, get_doc(This)) :
2769 xmlValidateElement(vctx, get_doc(This), get_node_obj(node)->node)))
2771 /* TODO: get a real error code here */
2772 TRACE("DTD validation failed\n");
2773 err_code = E_XML_INVALID;
2774 hr = S_FALSE;
2776 xmlFreeValidCtxt(vctx);
2779 /* Schema validation */
2780 if (hr == S_OK && This->properties->schemaCache != NULL)
2783 hr = SchemaCache_validate_tree(This->properties->schemaCache, get_node_obj(node)->node);
2784 if (SUCCEEDED(hr))
2786 ++validated;
2787 /* TODO: get a real error code here */
2788 if (hr == S_OK)
2790 TRACE("schema validation succeeded\n");
2792 else
2794 ERR("schema validation failed\n");
2795 err_code = E_XML_INVALID;
2798 else
2800 /* not really OK, just didn't find a schema for the ns */
2801 hr = S_OK;
2805 if (!validated)
2807 ERR("no DTD or schema found\n");
2808 err_code = E_XML_NODTD;
2809 hr = S_FALSE;
2812 if (err)
2813 *err = create_parseError(err_code, NULL, NULL, NULL, 0, 0, 0);
2815 return hr;
2818 static HRESULT WINAPI domdoc_validate(
2819 IXMLDOMDocument3* iface,
2820 IXMLDOMParseError** err)
2822 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2823 TRACE("(%p)->(%p)\n", This, err);
2824 return IXMLDOMDocument3_validateNode(iface, (IXMLDOMNode*)iface, err);
2827 static HRESULT WINAPI domdoc_setProperty(
2828 IXMLDOMDocument3* iface,
2829 BSTR p,
2830 VARIANT value)
2832 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2834 TRACE("(%p)->(%s %s)\n", This, debugstr_w(p), debugstr_variant(&value));
2836 if (lstrcmpiW(p, PropertySelectionLanguageW) == 0)
2838 VARIANT varStr;
2839 HRESULT hr;
2840 BSTR bstr;
2842 V_VT(&varStr) = VT_EMPTY;
2843 if (V_VT(&value) != VT_BSTR)
2845 if (FAILED(hr = VariantChangeType(&varStr, &value, 0, VT_BSTR)))
2846 return hr;
2847 bstr = V_BSTR(&varStr);
2849 else
2850 bstr = V_BSTR(&value);
2852 hr = S_OK;
2853 if (lstrcmpiW(bstr, PropValueXPathW) == 0)
2854 This->properties->XPath = TRUE;
2855 else if (lstrcmpiW(bstr, PropValueXSLPatternW) == 0)
2856 This->properties->XPath = FALSE;
2857 else
2858 hr = E_FAIL;
2860 VariantClear(&varStr);
2861 return hr;
2863 else if (lstrcmpiW(p, PropertySelectionNamespacesW) == 0)
2865 xmlChar *nsStr = (xmlChar*)This->properties->selectNsStr;
2866 struct list *pNsList;
2867 VARIANT varStr;
2868 HRESULT hr;
2869 BSTR bstr;
2871 V_VT(&varStr) = VT_EMPTY;
2872 if (V_VT(&value) != VT_BSTR)
2874 if (FAILED(hr = VariantChangeType(&varStr, &value, 0, VT_BSTR)))
2875 return hr;
2876 bstr = V_BSTR(&varStr);
2878 else
2879 bstr = V_BSTR(&value);
2881 hr = S_OK;
2883 pNsList = &(This->properties->selectNsList);
2884 clear_selectNsList(pNsList);
2885 heap_free(nsStr);
2886 nsStr = xmlchar_from_wchar(bstr);
2888 TRACE("property value: \"%s\"\n", debugstr_w(bstr));
2890 This->properties->selectNsStr = nsStr;
2891 This->properties->selectNsStr_len = xmlStrlen(nsStr);
2892 if (bstr && *bstr)
2894 xmlChar *pTokBegin, *pTokEnd, *pTokInner;
2895 select_ns_entry* ns_entry = NULL;
2896 xmlXPathContextPtr ctx;
2898 ctx = xmlXPathNewContext(This->node.node->doc);
2899 pTokBegin = nsStr;
2901 /* skip leading spaces */
2902 while (*pTokBegin == ' ' || *pTokBegin == '\n' ||
2903 *pTokBegin == '\t' || *pTokBegin == '\r')
2904 ++pTokBegin;
2906 for (; *pTokBegin; pTokBegin = pTokEnd)
2908 if (ns_entry)
2909 memset(ns_entry, 0, sizeof(select_ns_entry));
2910 else
2911 ns_entry = heap_alloc_zero(sizeof(select_ns_entry));
2913 while (*pTokBegin == ' ')
2914 ++pTokBegin;
2915 pTokEnd = pTokBegin;
2916 while (*pTokEnd != ' ' && *pTokEnd != 0)
2917 ++pTokEnd;
2919 /* so it failed to advance which means we've got some trailing spaces */
2920 if (pTokEnd == pTokBegin) break;
2922 if (xmlStrncmp(pTokBegin, (xmlChar const*)"xmlns", 5) != 0)
2924 hr = E_FAIL;
2925 WARN("Syntax error in xmlns string: %s\n\tat token: %s\n",
2926 debugstr_w(bstr), debugstr_an((const char*)pTokBegin, pTokEnd-pTokBegin));
2927 continue;
2930 pTokBegin += 5;
2931 if (*pTokBegin == '=')
2933 /*valid for XSLPattern?*/
2934 FIXME("Setting default xmlns not supported - skipping.\n");
2935 continue;
2937 else if (*pTokBegin == ':')
2939 ns_entry->prefix = ++pTokBegin;
2940 for (pTokInner = pTokBegin; pTokInner != pTokEnd && *pTokInner != '='; ++pTokInner)
2943 if (pTokInner == pTokEnd)
2945 hr = E_FAIL;
2946 WARN("Syntax error in xmlns string: %s\n\tat token: %s\n",
2947 debugstr_w(bstr), debugstr_an((const char*)pTokBegin, pTokEnd-pTokBegin));
2948 continue;
2951 ns_entry->prefix_end = *pTokInner;
2952 *pTokInner = 0;
2953 ++pTokInner;
2955 if (pTokEnd-pTokInner > 1 &&
2956 ((*pTokInner == '\'' && *(pTokEnd-1) == '\'') ||
2957 (*pTokInner == '"' && *(pTokEnd-1) == '"')))
2959 ns_entry->href = ++pTokInner;
2960 ns_entry->href_end = *(pTokEnd-1);
2961 *(pTokEnd-1) = 0;
2962 list_add_tail(pNsList, &ns_entry->entry);
2963 /*let libxml figure out if they're valid from here ;)*/
2964 if (xmlXPathRegisterNs(ctx, ns_entry->prefix, ns_entry->href) != 0)
2966 hr = E_FAIL;
2968 ns_entry = NULL;
2969 continue;
2971 else
2973 WARN("Syntax error in xmlns string: %s\n\tat token: %s\n",
2974 debugstr_w(bstr), debugstr_an((const char*)pTokInner, pTokEnd-pTokInner));
2975 list_add_tail(pNsList, &ns_entry->entry);
2977 ns_entry = NULL;
2978 hr = E_FAIL;
2979 continue;
2982 else
2984 hr = E_FAIL;
2985 continue;
2988 heap_free(ns_entry);
2989 xmlXPathFreeContext(ctx);
2992 VariantClear(&varStr);
2993 return hr;
2995 else if (lstrcmpiW(p, PropertyProhibitDTDW) == 0 ||
2996 lstrcmpiW(p, PropertyNewParserW) == 0 ||
2997 lstrcmpiW(p, PropertyResolveExternalsW) == 0)
2999 /* Ignore */
3000 FIXME("Ignoring property %s, value %s\n", debugstr_w(p), debugstr_variant(&value));
3001 return S_OK;
3004 FIXME("Unknown property %s\n", debugstr_w(p));
3005 return E_FAIL;
3008 static HRESULT WINAPI domdoc_getProperty(
3009 IXMLDOMDocument3* iface,
3010 BSTR p,
3011 VARIANT* var)
3013 domdoc *This = impl_from_IXMLDOMDocument3( iface );
3015 TRACE("(%p)->(%s)\n", This, debugstr_w(p));
3017 if (!var)
3018 return E_INVALIDARG;
3020 if (lstrcmpiW(p, PropertySelectionLanguageW) == 0)
3022 V_VT(var) = VT_BSTR;
3023 V_BSTR(var) = This->properties->XPath ?
3024 SysAllocString(PropValueXPathW) :
3025 SysAllocString(PropValueXSLPatternW);
3026 return V_BSTR(var) ? S_OK : E_OUTOFMEMORY;
3028 else if (lstrcmpiW(p, PropertySelectionNamespacesW) == 0)
3030 int lenA, lenW;
3031 BSTR rebuiltStr, cur;
3032 const xmlChar *nsStr;
3033 struct list *pNsList;
3034 select_ns_entry* pNsEntry;
3036 V_VT(var) = VT_BSTR;
3037 nsStr = This->properties->selectNsStr;
3038 pNsList = &This->properties->selectNsList;
3039 lenA = This->properties->selectNsStr_len;
3040 lenW = MultiByteToWideChar(CP_UTF8, 0, (LPCSTR)nsStr, lenA+1, NULL, 0);
3041 rebuiltStr = heap_alloc(lenW*sizeof(WCHAR));
3042 MultiByteToWideChar(CP_UTF8, 0, (LPCSTR)nsStr, lenA+1, rebuiltStr, lenW);
3043 cur = rebuiltStr;
3044 /* this is fine because all of the chars that end tokens are ASCII*/
3045 LIST_FOR_EACH_ENTRY(pNsEntry, pNsList, select_ns_entry, entry)
3047 while (*cur != 0) ++cur;
3048 if (pNsEntry->prefix_end)
3050 *cur = pNsEntry->prefix_end;
3051 while (*cur != 0) ++cur;
3054 if (pNsEntry->href_end)
3056 *cur = pNsEntry->href_end;
3059 V_BSTR(var) = SysAllocString(rebuiltStr);
3060 heap_free(rebuiltStr);
3061 return S_OK;
3064 FIXME("Unknown property %s\n", debugstr_w(p));
3065 return E_FAIL;
3068 static HRESULT WINAPI domdoc_importNode(
3069 IXMLDOMDocument3* iface,
3070 IXMLDOMNode* node,
3071 VARIANT_BOOL deep,
3072 IXMLDOMNode** clone)
3074 domdoc *This = impl_from_IXMLDOMDocument3( iface );
3075 FIXME("(%p)->(%p %d %p): stub\n", This, node, deep, clone);
3076 return E_NOTIMPL;
3079 static const struct IXMLDOMDocument3Vtbl XMLDOMDocument3Vtbl =
3081 domdoc_QueryInterface,
3082 domdoc_AddRef,
3083 domdoc_Release,
3084 domdoc_GetTypeInfoCount,
3085 domdoc_GetTypeInfo,
3086 domdoc_GetIDsOfNames,
3087 domdoc_Invoke,
3088 domdoc_get_nodeName,
3089 domdoc_get_nodeValue,
3090 domdoc_put_nodeValue,
3091 domdoc_get_nodeType,
3092 domdoc_get_parentNode,
3093 domdoc_get_childNodes,
3094 domdoc_get_firstChild,
3095 domdoc_get_lastChild,
3096 domdoc_get_previousSibling,
3097 domdoc_get_nextSibling,
3098 domdoc_get_attributes,
3099 domdoc_insertBefore,
3100 domdoc_replaceChild,
3101 domdoc_removeChild,
3102 domdoc_appendChild,
3103 domdoc_hasChildNodes,
3104 domdoc_get_ownerDocument,
3105 domdoc_cloneNode,
3106 domdoc_get_nodeTypeString,
3107 domdoc_get_text,
3108 domdoc_put_text,
3109 domdoc_get_specified,
3110 domdoc_get_definition,
3111 domdoc_get_nodeTypedValue,
3112 domdoc_put_nodeTypedValue,
3113 domdoc_get_dataType,
3114 domdoc_put_dataType,
3115 domdoc_get_xml,
3116 domdoc_transformNode,
3117 domdoc_selectNodes,
3118 domdoc_selectSingleNode,
3119 domdoc_get_parsed,
3120 domdoc_get_namespaceURI,
3121 domdoc_get_prefix,
3122 domdoc_get_baseName,
3123 domdoc_transformNodeToObject,
3124 domdoc_get_doctype,
3125 domdoc_get_implementation,
3126 domdoc_get_documentElement,
3127 domdoc_put_documentElement,
3128 domdoc_createElement,
3129 domdoc_createDocumentFragment,
3130 domdoc_createTextNode,
3131 domdoc_createComment,
3132 domdoc_createCDATASection,
3133 domdoc_createProcessingInstruction,
3134 domdoc_createAttribute,
3135 domdoc_createEntityReference,
3136 domdoc_getElementsByTagName,
3137 domdoc_createNode,
3138 domdoc_nodeFromID,
3139 domdoc_load,
3140 domdoc_get_readyState,
3141 domdoc_get_parseError,
3142 domdoc_get_url,
3143 domdoc_get_async,
3144 domdoc_put_async,
3145 domdoc_abort,
3146 domdoc_loadXML,
3147 domdoc_save,
3148 domdoc_get_validateOnParse,
3149 domdoc_put_validateOnParse,
3150 domdoc_get_resolveExternals,
3151 domdoc_put_resolveExternals,
3152 domdoc_get_preserveWhiteSpace,
3153 domdoc_put_preserveWhiteSpace,
3154 domdoc_put_onreadystatechange,
3155 domdoc_put_onDataAvailable,
3156 domdoc_put_onTransformNode,
3157 domdoc_get_namespaces,
3158 domdoc_get_schemas,
3159 domdoc_putref_schemas,
3160 domdoc_validate,
3161 domdoc_setProperty,
3162 domdoc_getProperty,
3163 domdoc_validateNode,
3164 domdoc_importNode
3167 /* IConnectionPointContainer */
3168 static HRESULT WINAPI ConnectionPointContainer_QueryInterface(IConnectionPointContainer *iface,
3169 REFIID riid, void **ppv)
3171 domdoc *This = impl_from_IConnectionPointContainer(iface);
3172 return IXMLDOMDocument3_QueryInterface(&This->IXMLDOMDocument3_iface, riid, ppv);
3175 static ULONG WINAPI ConnectionPointContainer_AddRef(IConnectionPointContainer *iface)
3177 domdoc *This = impl_from_IConnectionPointContainer(iface);
3178 return IXMLDOMDocument3_AddRef(&This->IXMLDOMDocument3_iface);
3181 static ULONG WINAPI ConnectionPointContainer_Release(IConnectionPointContainer *iface)
3183 domdoc *This = impl_from_IConnectionPointContainer(iface);
3184 return IXMLDOMDocument3_Release(&This->IXMLDOMDocument3_iface);
3187 static HRESULT WINAPI ConnectionPointContainer_EnumConnectionPoints(IConnectionPointContainer *iface,
3188 IEnumConnectionPoints **ppEnum)
3190 domdoc *This = impl_from_IConnectionPointContainer(iface);
3191 FIXME("(%p)->(%p): stub\n", This, ppEnum);
3192 return E_NOTIMPL;
3195 static HRESULT WINAPI ConnectionPointContainer_FindConnectionPoint(IConnectionPointContainer *iface,
3196 REFIID riid, IConnectionPoint **cp)
3198 domdoc *This = impl_from_IConnectionPointContainer(iface);
3199 ConnectionPoint *iter;
3201 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), cp);
3203 *cp = NULL;
3205 for(iter = This->cp_list; iter; iter = iter->next)
3207 if (IsEqualGUID(iter->iid, riid))
3208 *cp = &iter->IConnectionPoint_iface;
3211 if (*cp)
3213 IConnectionPoint_AddRef(*cp);
3214 return S_OK;
3217 FIXME("unsupported riid %s\n", debugstr_guid(riid));
3218 return CONNECT_E_NOCONNECTION;
3222 static const struct IConnectionPointContainerVtbl ConnectionPointContainerVtbl =
3224 ConnectionPointContainer_QueryInterface,
3225 ConnectionPointContainer_AddRef,
3226 ConnectionPointContainer_Release,
3227 ConnectionPointContainer_EnumConnectionPoints,
3228 ConnectionPointContainer_FindConnectionPoint
3231 /* IConnectionPoint */
3232 static HRESULT WINAPI ConnectionPoint_QueryInterface(IConnectionPoint *iface,
3233 REFIID riid, void **ppv)
3235 ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3237 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv );
3239 *ppv = NULL;
3241 if (IsEqualGUID(&IID_IUnknown, riid) ||
3242 IsEqualGUID(&IID_IConnectionPoint, riid))
3244 *ppv = iface;
3247 if (*ppv)
3249 IConnectionPoint_AddRef(iface);
3250 return S_OK;
3253 WARN("Unsupported interface %s\n", debugstr_guid(riid));
3254 return E_NOINTERFACE;
3257 static ULONG WINAPI ConnectionPoint_AddRef(IConnectionPoint *iface)
3259 ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3260 return IConnectionPointContainer_AddRef(This->container);
3263 static ULONG WINAPI ConnectionPoint_Release(IConnectionPoint *iface)
3265 ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3266 return IConnectionPointContainer_Release(This->container);
3269 static HRESULT WINAPI ConnectionPoint_GetConnectionInterface(IConnectionPoint *iface, IID *iid)
3271 ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3273 TRACE("(%p)->(%p)\n", This, iid);
3275 if (!iid) return E_POINTER;
3277 *iid = *This->iid;
3278 return S_OK;
3281 static HRESULT WINAPI ConnectionPoint_GetConnectionPointContainer(IConnectionPoint *iface,
3282 IConnectionPointContainer **container)
3284 ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3286 TRACE("(%p)->(%p)\n", This, container);
3288 if (!container) return E_POINTER;
3290 *container = This->container;
3291 IConnectionPointContainer_AddRef(*container);
3292 return S_OK;
3295 static HRESULT WINAPI ConnectionPoint_Advise(IConnectionPoint *iface, IUnknown *unk_sink,
3296 DWORD *cookie)
3298 ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3299 IUnknown *sink;
3300 HRESULT hr;
3301 DWORD i;
3303 TRACE("(%p)->(%p %p)\n", This, unk_sink, cookie);
3305 hr = IUnknown_QueryInterface(unk_sink, This->iid, (void**)&sink);
3306 if(FAILED(hr) && !IsEqualGUID(&IID_IPropertyNotifySink, This->iid))
3307 hr = IUnknown_QueryInterface(unk_sink, &IID_IDispatch, (void**)&sink);
3308 if(FAILED(hr))
3309 return CONNECT_E_CANNOTCONNECT;
3311 if(This->sinks)
3313 for (i = 0; i < This->sinks_size; i++)
3314 if (!This->sinks[i].unk)
3315 break;
3317 if (i == This->sinks_size)
3318 This->sinks = heap_realloc(This->sinks,(++This->sinks_size)*sizeof(*This->sinks));
3320 else
3322 This->sinks = heap_alloc(sizeof(*This->sinks));
3323 This->sinks_size = 1;
3324 i = 0;
3327 This->sinks[i].unk = sink;
3328 if (cookie)
3329 *cookie = i+1;
3331 return S_OK;
3334 static HRESULT WINAPI ConnectionPoint_Unadvise(IConnectionPoint *iface, DWORD cookie)
3336 ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3338 TRACE("(%p)->(%d)\n", This, cookie);
3340 if (cookie == 0 || cookie > This->sinks_size || !This->sinks[cookie-1].unk)
3341 return CONNECT_E_NOCONNECTION;
3343 IUnknown_Release(This->sinks[cookie-1].unk);
3344 This->sinks[cookie-1].unk = NULL;
3346 return S_OK;
3349 static HRESULT WINAPI ConnectionPoint_EnumConnections(IConnectionPoint *iface,
3350 IEnumConnections **ppEnum)
3352 ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3353 FIXME("(%p)->(%p): stub\n", This, ppEnum);
3354 return E_NOTIMPL;
3357 static const IConnectionPointVtbl ConnectionPointVtbl =
3359 ConnectionPoint_QueryInterface,
3360 ConnectionPoint_AddRef,
3361 ConnectionPoint_Release,
3362 ConnectionPoint_GetConnectionInterface,
3363 ConnectionPoint_GetConnectionPointContainer,
3364 ConnectionPoint_Advise,
3365 ConnectionPoint_Unadvise,
3366 ConnectionPoint_EnumConnections
3369 static void ConnectionPoint_Init(ConnectionPoint *cp, struct domdoc *doc, REFIID riid)
3371 cp->IConnectionPoint_iface.lpVtbl = &ConnectionPointVtbl;
3372 cp->doc = doc;
3373 cp->iid = riid;
3374 cp->sinks = NULL;
3375 cp->sinks_size = 0;
3377 cp->next = doc->cp_list;
3378 doc->cp_list = cp;
3380 cp->container = &doc->IConnectionPointContainer_iface;
3383 /* domdoc implementation of IObjectWithSite */
3384 static HRESULT WINAPI
3385 domdoc_ObjectWithSite_QueryInterface( IObjectWithSite* iface, REFIID riid, void** ppvObject )
3387 domdoc *This = impl_from_IObjectWithSite(iface);
3388 return IXMLDOMDocument3_QueryInterface(&This->IXMLDOMDocument3_iface, riid, ppvObject);
3391 static ULONG WINAPI domdoc_ObjectWithSite_AddRef( IObjectWithSite* iface )
3393 domdoc *This = impl_from_IObjectWithSite(iface);
3394 return IXMLDOMDocument3_AddRef(&This->IXMLDOMDocument3_iface);
3397 static ULONG WINAPI domdoc_ObjectWithSite_Release( IObjectWithSite* iface )
3399 domdoc *This = impl_from_IObjectWithSite(iface);
3400 return IXMLDOMDocument3_Release(&This->IXMLDOMDocument3_iface);
3403 static HRESULT WINAPI domdoc_ObjectWithSite_GetSite( IObjectWithSite *iface, REFIID iid, void **ppvSite )
3405 domdoc *This = impl_from_IObjectWithSite(iface);
3407 TRACE("(%p)->(%s %p)\n", This, debugstr_guid( iid ), ppvSite );
3409 if ( !This->site )
3410 return E_FAIL;
3412 return IUnknown_QueryInterface( This->site, iid, ppvSite );
3415 static HRESULT WINAPI domdoc_ObjectWithSite_SetSite( IObjectWithSite *iface, IUnknown *punk )
3417 domdoc *This = impl_from_IObjectWithSite(iface);
3419 TRACE("(%p)->(%p)\n", iface, punk);
3421 if(!punk)
3423 if(This->site)
3425 IUnknown_Release( This->site );
3426 This->site = NULL;
3429 return S_OK;
3432 IUnknown_AddRef( punk );
3434 if(This->site)
3435 IUnknown_Release( This->site );
3437 This->site = punk;
3439 return S_OK;
3442 static const IObjectWithSiteVtbl domdocObjectSite =
3444 domdoc_ObjectWithSite_QueryInterface,
3445 domdoc_ObjectWithSite_AddRef,
3446 domdoc_ObjectWithSite_Release,
3447 domdoc_ObjectWithSite_SetSite,
3448 domdoc_ObjectWithSite_GetSite
3451 static HRESULT WINAPI domdoc_Safety_QueryInterface(IObjectSafety *iface, REFIID riid, void **ppv)
3453 domdoc *This = impl_from_IObjectSafety(iface);
3454 return IXMLDOMDocument3_QueryInterface(&This->IXMLDOMDocument3_iface, riid, ppv);
3457 static ULONG WINAPI domdoc_Safety_AddRef(IObjectSafety *iface)
3459 domdoc *This = impl_from_IObjectSafety(iface);
3460 return IXMLDOMDocument3_AddRef(&This->IXMLDOMDocument3_iface);
3463 static ULONG WINAPI domdoc_Safety_Release(IObjectSafety *iface)
3465 domdoc *This = impl_from_IObjectSafety(iface);
3466 return IXMLDOMDocument3_Release(&This->IXMLDOMDocument3_iface);
3469 #define SAFETY_SUPPORTED_OPTIONS (INTERFACESAFE_FOR_UNTRUSTED_CALLER|INTERFACESAFE_FOR_UNTRUSTED_DATA|INTERFACE_USES_SECURITY_MANAGER)
3471 static HRESULT WINAPI domdoc_Safety_GetInterfaceSafetyOptions(IObjectSafety *iface, REFIID riid,
3472 DWORD *supported, DWORD *enabled)
3474 domdoc *This = impl_from_IObjectSafety(iface);
3476 TRACE("(%p)->(%s %p %p)\n", This, debugstr_guid(riid), supported, enabled);
3478 if(!supported || !enabled) return E_POINTER;
3480 *supported = SAFETY_SUPPORTED_OPTIONS;
3481 *enabled = This->safeopt;
3483 return S_OK;
3486 static HRESULT WINAPI domdoc_Safety_SetInterfaceSafetyOptions(IObjectSafety *iface, REFIID riid,
3487 DWORD mask, DWORD enabled)
3489 domdoc *This = impl_from_IObjectSafety(iface);
3490 TRACE("(%p)->(%s %x %x)\n", This, debugstr_guid(riid), mask, enabled);
3492 if ((mask & ~SAFETY_SUPPORTED_OPTIONS) != 0)
3493 return E_FAIL;
3495 This->safeopt = (This->safeopt & ~mask) | (mask & enabled);
3497 return S_OK;
3500 #undef SAFETY_SUPPORTED_OPTIONS
3502 static const IObjectSafetyVtbl domdocObjectSafetyVtbl = {
3503 domdoc_Safety_QueryInterface,
3504 domdoc_Safety_AddRef,
3505 domdoc_Safety_Release,
3506 domdoc_Safety_GetInterfaceSafetyOptions,
3507 domdoc_Safety_SetInterfaceSafetyOptions
3510 static const tid_t domdoc_iface_tids[] = {
3511 IXMLDOMDocument3_tid,
3515 static dispex_static_data_t domdoc_dispex = {
3516 NULL,
3517 IXMLDOMDocument3_tid,
3518 NULL,
3519 domdoc_iface_tids
3522 HRESULT get_domdoc_from_xmldoc(xmlDocPtr xmldoc, IXMLDOMDocument3 **document)
3524 domdoc *doc;
3526 doc = heap_alloc( sizeof (*doc) );
3527 if( !doc )
3528 return E_OUTOFMEMORY;
3530 doc->IXMLDOMDocument3_iface.lpVtbl = &XMLDOMDocument3Vtbl;
3531 doc->IPersistStreamInit_iface.lpVtbl = &xmldoc_IPersistStreamInit_VTable;
3532 doc->IObjectWithSite_iface.lpVtbl = &domdocObjectSite;
3533 doc->IObjectSafety_iface.lpVtbl = &domdocObjectSafetyVtbl;
3534 doc->IConnectionPointContainer_iface.lpVtbl = &ConnectionPointContainerVtbl;
3535 doc->ref = 1;
3536 doc->async = VARIANT_TRUE;
3537 doc->validating = 0;
3538 doc->resolving = 0;
3539 doc->properties = properties_from_xmlDocPtr(xmldoc);
3540 doc->error = S_OK;
3541 doc->site = NULL;
3542 doc->safeopt = 0;
3543 doc->bsc = NULL;
3544 doc->cp_list = NULL;
3545 doc->namespaces = NULL;
3546 memset(doc->events, 0, sizeof(doc->events));
3548 /* events connection points */
3549 ConnectionPoint_Init(&doc->cp_dispatch, doc, &IID_IDispatch);
3550 ConnectionPoint_Init(&doc->cp_propnotif, doc, &IID_IPropertyNotifySink);
3551 ConnectionPoint_Init(&doc->cp_domdocevents, doc, &DIID_XMLDOMDocumentEvents);
3553 init_xmlnode(&doc->node, (xmlNodePtr)xmldoc, (IXMLDOMNode*)&doc->IXMLDOMDocument3_iface,
3554 &domdoc_dispex);
3556 *document = &doc->IXMLDOMDocument3_iface;
3558 TRACE("returning iface %p\n", *document);
3559 return S_OK;
3562 HRESULT DOMDocument_create(MSXML_VERSION version, IUnknown *pUnkOuter, void **ppObj)
3564 xmlDocPtr xmldoc;
3565 HRESULT hr;
3567 TRACE("(%d, %p, %p)\n", version, pUnkOuter, ppObj);
3569 xmldoc = xmlNewDoc(NULL);
3570 if(!xmldoc)
3571 return E_OUTOFMEMORY;
3573 xmldoc_init(xmldoc, version);
3575 hr = get_domdoc_from_xmldoc(xmldoc, (IXMLDOMDocument3**)ppObj);
3576 if(FAILED(hr))
3578 free_properties(properties_from_xmlDocPtr(xmldoc));
3579 heap_free(xmldoc->_private);
3580 xmlFreeDoc(xmldoc);
3581 return hr;
3584 return hr;
3587 IUnknown* create_domdoc( xmlNodePtr document )
3589 void* pObj = NULL;
3590 HRESULT hr;
3592 TRACE("(%p)\n", document);
3594 hr = get_domdoc_from_xmldoc((xmlDocPtr)document, (IXMLDOMDocument3**)&pObj);
3595 if (FAILED(hr))
3596 return NULL;
3598 return pObj;
3601 #else
3603 HRESULT DOMDocument_create(MSXML_VERSION version, IUnknown *pUnkOuter, void **ppObj)
3605 MESSAGE("This program tried to use a DOMDocument object, but\n"
3606 "libxml2 support was not present at compile time.\n");
3607 return E_NOTIMPL;
3610 #endif