msdasql: Support IRowsetInfo in IRowset interface.
[wine.git] / dlls / msxml3 / domdoc.c
blob4013f106cc67c76734c3266ce78ed5f49f905140
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 <stdarg.h>
25 #include <assert.h>
26 #include <libxml/parser.h>
27 #include <libxml/xmlerror.h>
28 #include <libxml/xpathInternals.h>
29 # include <libxml/xmlsave.h>
30 #include <libxml/SAX2.h>
31 #include <libxml/parserInternals.h>
33 #include "windef.h"
34 #include "winbase.h"
35 #include "winuser.h"
36 #include "winnls.h"
37 #include "ole2.h"
38 #include "olectl.h"
39 #include "msxml6.h"
40 #include "wininet.h"
41 #include "winreg.h"
42 #include "shlwapi.h"
43 #include "ocidl.h"
44 #include "objsafe.h"
46 #include "wine/debug.h"
48 #include "msxml_private.h"
50 WINE_DEFAULT_DEBUG_CHANNEL(msxml);
52 /* not defined in older versions */
53 #define XML_SAVE_FORMAT 1
54 #define XML_SAVE_NO_DECL 2
55 #define XML_SAVE_NO_EMPTY 4
56 #define XML_SAVE_NO_XHTML 8
57 #define XML_SAVE_XHTML 16
58 #define XML_SAVE_AS_XML 32
59 #define XML_SAVE_AS_HTML 64
61 static const WCHAR PropertySelectionLanguageW[] = {'S','e','l','e','c','t','i','o','n','L','a','n','g','u','a','g','e',0};
62 static const WCHAR PropertySelectionNamespacesW[] = {'S','e','l','e','c','t','i','o','n','N','a','m','e','s','p','a','c','e','s',0};
63 static const WCHAR PropertyProhibitDTDW[] = {'P','r','o','h','i','b','i','t','D','T','D',0};
64 static const WCHAR PropertyNewParserW[] = {'N','e','w','P','a','r','s','e','r',0};
65 static const WCHAR PropValueXPathW[] = {'X','P','a','t','h',0};
66 static const WCHAR PropValueXSLPatternW[] = {'X','S','L','P','a','t','t','e','r','n',0};
67 static const WCHAR PropertyResolveExternalsW[] = {'R','e','s','o','l','v','e','E','x','t','e','r','n','a','l','s',0};
68 static const WCHAR PropertyAllowXsltScriptW[] = {'A','l','l','o','w','X','s','l','t','S','c','r','i','p','t',0};
69 static const WCHAR PropertyAllowDocumentFunctionW[] = {'A','l','l','o','w','D','o','c','u','m','e','n','t','F','u','n','c','t','i','o','n',0};
70 static const WCHAR PropertyNormalizeAttributeValuesW[] = {'N','o','r','m','a','l','i','z','e','A','t','t','r','i','b','u','t','e','V','a','l','u','e','s',0};
72 /* Anything that passes the test_get_ownerDocument()
73 * tests can go here (data shared between all instances).
74 * We need to preserve this when reloading a document,
75 * and also need access to it from the libxml backend. */
76 typedef struct {
77 LONG refs;
78 MSXML_VERSION version;
79 VARIANT_BOOL preserving;
80 IXMLDOMSchemaCollection2* schemaCache;
81 struct list selectNsList;
82 xmlChar const* selectNsStr;
83 LONG selectNsStr_len;
84 BOOL XPath;
85 IUri *uri;
86 } domdoc_properties;
88 typedef struct ConnectionPoint ConnectionPoint;
89 typedef struct domdoc domdoc;
91 struct ConnectionPoint
93 IConnectionPoint IConnectionPoint_iface;
94 const IID *iid;
96 ConnectionPoint *next;
97 IConnectionPointContainer *container;
98 domdoc *doc;
100 union
102 IUnknown *unk;
103 IDispatch *disp;
104 IPropertyNotifySink *propnotif;
105 } *sinks;
106 DWORD sinks_size;
109 typedef enum {
110 EVENTID_READYSTATECHANGE = 0,
111 EVENTID_DATAAVAILABLE,
112 EVENTID_TRANSFORMNODE,
113 EVENTID_LAST
114 } eventid_t;
116 struct domdoc
118 xmlnode node;
119 IXMLDOMDocument3 IXMLDOMDocument3_iface;
120 IPersistStreamInit IPersistStreamInit_iface;
121 IObjectWithSite IObjectWithSite_iface;
122 IObjectSafety IObjectSafety_iface;
123 IConnectionPointContainer IConnectionPointContainer_iface;
124 LONG ref;
125 VARIANT_BOOL async;
126 VARIANT_BOOL validating;
127 VARIANT_BOOL resolving;
128 domdoc_properties* properties;
129 HRESULT error;
131 /* IObjectWithSite */
132 IUnknown *site;
133 IUri *base_uri;
135 /* IObjectSafety */
136 DWORD safeopt;
138 /* connection list */
139 ConnectionPoint *cp_list;
140 ConnectionPoint cp_domdocevents;
141 ConnectionPoint cp_propnotif;
142 ConnectionPoint cp_dispatch;
144 /* events */
145 IDispatch *events[EVENTID_LAST];
147 IXMLDOMSchemaCollection2 *namespaces;
150 static HRESULT set_doc_event(domdoc *doc, eventid_t eid, const VARIANT *v)
152 IDispatch *disp;
154 switch (V_VT(v))
156 case VT_UNKNOWN:
157 if (V_UNKNOWN(v))
158 IUnknown_QueryInterface(V_UNKNOWN(v), &IID_IDispatch, (void**)&disp);
159 else
160 disp = NULL;
161 break;
162 case VT_DISPATCH:
163 disp = V_DISPATCH(v);
164 if (disp) IDispatch_AddRef(disp);
165 break;
166 default:
167 return DISP_E_TYPEMISMATCH;
170 if (doc->events[eid]) IDispatch_Release(doc->events[eid]);
171 doc->events[eid] = disp;
173 return S_OK;
176 static inline ConnectionPoint *impl_from_IConnectionPoint(IConnectionPoint *iface)
178 return CONTAINING_RECORD(iface, ConnectionPoint, IConnectionPoint_iface);
182 In native windows, the whole lifetime management of XMLDOMNodes is
183 managed automatically using reference counts. Wine emulates that by
184 maintaining a reference count to the document that is increased for
185 each IXMLDOMNode pointer passed out for this document. If all these
186 pointers are gone, the document is unreachable and gets freed, that
187 is, all nodes in the tree of the document get freed.
189 You are able to create nodes that are associated to a document (in
190 fact, in msxml's XMLDOM model, all nodes are associated to a document),
191 but not in the tree of that document, for example using the createFoo
192 functions from IXMLDOMDocument. These nodes do not get cleaned up
193 by libxml, so we have to do it ourselves.
195 To catch these nodes, a list of "orphan nodes" is introduced.
196 It contains pointers to all roots of node trees that are
197 associated with the document without being part of the document
198 tree. All nodes with parent==NULL (except for the document root nodes)
199 should be in the orphan node list of their document. All orphan nodes
200 get freed together with the document itself.
203 typedef struct _xmldoc_priv {
204 LONG refs;
205 struct list orphans;
206 domdoc_properties* properties;
207 } xmldoc_priv;
209 typedef struct _orphan_entry {
210 struct list entry;
211 xmlNode * node;
212 } orphan_entry;
214 typedef struct _select_ns_entry {
215 struct list entry;
216 xmlChar const* prefix;
217 xmlChar prefix_end;
218 xmlChar const* href;
219 xmlChar href_end;
220 } select_ns_entry;
222 static inline xmldoc_priv * priv_from_xmlDocPtr(const xmlDocPtr doc)
224 return doc->_private;
227 static inline domdoc_properties * properties_from_xmlDocPtr(xmlDocPtr doc)
229 return priv_from_xmlDocPtr(doc)->properties;
232 BOOL is_xpathmode(const xmlDocPtr doc)
234 return properties_from_xmlDocPtr(doc)->XPath;
237 void set_xpathmode(xmlDocPtr doc, BOOL xpath)
239 properties_from_xmlDocPtr(doc)->XPath = xpath;
242 int registerNamespaces(xmlXPathContextPtr ctxt)
244 int n = 0;
245 const select_ns_entry* ns = NULL;
246 const struct list* pNsList = &properties_from_xmlDocPtr(ctxt->doc)->selectNsList;
248 TRACE("(%p)\n", ctxt);
250 LIST_FOR_EACH_ENTRY( ns, pNsList, select_ns_entry, entry )
252 xmlXPathRegisterNs(ctxt, ns->prefix, ns->href);
253 ++n;
256 return n;
259 static inline void clear_selectNsList(struct list* pNsList)
261 select_ns_entry *ns, *ns2;
262 LIST_FOR_EACH_ENTRY_SAFE( ns, ns2, pNsList, select_ns_entry, entry )
264 heap_free( ns );
266 list_init(pNsList);
269 static xmldoc_priv * create_priv(void)
271 xmldoc_priv *priv;
272 priv = heap_alloc( sizeof (*priv) );
274 if (priv)
276 priv->refs = 0;
277 list_init( &priv->orphans );
278 priv->properties = NULL;
281 return priv;
284 static domdoc_properties *create_properties(MSXML_VERSION version)
286 domdoc_properties *properties = heap_alloc(sizeof(domdoc_properties));
288 properties->refs = 1;
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 uri */
300 properties->uri = 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->refs = 1;
316 pcopy->version = properties->version;
317 pcopy->preserving = properties->preserving;
318 pcopy->schemaCache = properties->schemaCache;
319 if (pcopy->schemaCache)
320 IXMLDOMSchemaCollection2_AddRef(pcopy->schemaCache);
321 pcopy->XPath = properties->XPath;
322 pcopy->selectNsStr_len = properties->selectNsStr_len;
323 list_init( &pcopy->selectNsList );
324 pcopy->selectNsStr = heap_alloc(len);
325 memcpy((xmlChar*)pcopy->selectNsStr, properties->selectNsStr, len);
326 offset = pcopy->selectNsStr - properties->selectNsStr;
328 LIST_FOR_EACH_ENTRY( ns, (&properties->selectNsList), select_ns_entry, entry )
330 new_ns = heap_alloc(sizeof(select_ns_entry));
331 memcpy(new_ns, ns, sizeof(select_ns_entry));
332 new_ns->href += offset;
333 new_ns->prefix += offset;
334 list_add_tail(&pcopy->selectNsList, &new_ns->entry);
337 pcopy->uri = properties->uri;
338 if (pcopy->uri)
339 IUri_AddRef(pcopy->uri);
342 return pcopy;
345 static domdoc_properties * properties_add_ref(domdoc_properties *properties)
347 LONG ref;
349 if (!properties) return NULL;
351 ref = InterlockedIncrement(&properties->refs);
352 TRACE("%p, %d.\n", properties, ref);
353 return properties;
356 static void properties_release(domdoc_properties *properties)
358 LONG ref;
360 if (!properties) return;
362 ref = InterlockedDecrement(&properties->refs);
364 TRACE("%p, %d.\n", properties, ref);
366 if (ref < 0)
367 WARN("negative refcount, expect troubles\n");
369 if (ref == 0)
371 if (properties->schemaCache)
372 IXMLDOMSchemaCollection2_Release(properties->schemaCache);
373 clear_selectNsList(&properties->selectNsList);
374 heap_free((xmlChar*)properties->selectNsStr);
375 if (properties->uri)
376 IUri_Release(properties->uri);
377 heap_free(properties);
381 static void release_namespaces(domdoc *This)
383 if (This->namespaces)
385 IXMLDOMSchemaCollection2_Release(This->namespaces);
386 This->namespaces = NULL;
390 /* links a "<?xml" node as a first child */
391 void xmldoc_link_xmldecl(xmlDocPtr doc, xmlNodePtr node)
393 assert(doc != NULL);
394 if (doc->standalone != -1) xmlAddPrevSibling( doc->children, node );
397 /* unlinks a first "<?xml" child if it was created */
398 xmlNodePtr xmldoc_unlink_xmldecl(xmlDocPtr doc)
400 static const xmlChar xmlA[] = "xml";
401 xmlNodePtr node, first_child;
403 assert(doc != NULL);
405 /* xml declaration node could be created automatically after parsing or added
406 to a tree later */
407 first_child = doc->children;
408 if (first_child && first_child->type == XML_PI_NODE && xmlStrEqual(first_child->name, xmlA))
410 node = first_child;
411 xmlUnlinkNode( node );
413 else
414 node = NULL;
416 return node;
419 MSXML_VERSION xmldoc_version(xmlDocPtr doc)
421 return properties_from_xmlDocPtr(doc)->version;
424 BOOL is_preserving_whitespace(xmlNodePtr node)
426 domdoc_properties* properties = NULL;
427 /* during parsing the xmlDoc._private stuff is not there */
428 if (priv_from_xmlDocPtr(node->doc))
429 properties = properties_from_xmlDocPtr(node->doc);
430 return ((properties && properties->preserving == VARIANT_TRUE) ||
431 xmlNodeGetSpacePreserve(node) == 1);
434 static inline BOOL strn_isspace(xmlChar const* str, int len)
436 for (; str && len > 0 && *str; ++str, --len)
437 if (!isspace(*str))
438 break;
440 return len == 0;
443 static void sax_characters(void *ctx, const xmlChar *ch, int len)
445 xmlParserCtxtPtr ctxt;
446 const domdoc *This;
448 ctxt = (xmlParserCtxtPtr) ctx;
449 This = (const domdoc*) ctxt->_private;
451 if (ctxt->node)
453 xmlChar cur = *(ctxt->input->cur);
455 /* Characters are reported with multiple calls, for example each charref is reported with a separate
456 call and then parser appends it to a single text node or creates a new node if not created.
457 It's not possible to tell if it's ignorable data or not just looking at data itself cause it could be
458 space chars that separate charrefs or similar case. We only need to skip leading and trailing spaces,
459 or whole node if it has nothing but space chars, so to detect leading space node->last is checked that
460 contains text node pointer if already created, trailing spaces are detected directly looking at parser input
461 for next '<' opening bracket - similar logic is used by libxml2 itself. Basically 'cur' == '<' means the last
462 chunk of char data, in case it's not the last chunk we check for previously added node type and if it's not
463 a text node it's safe to ignore.
465 Note that during domdoc_loadXML() the xmlDocPtr->_private data is not available. */
467 if (!This->properties->preserving &&
468 !is_preserving_whitespace(ctxt->node) &&
469 strn_isspace(ch, len) &&
470 (!ctxt->node->last ||
471 ((ctxt->node->last && (cur == '<' || ctxt->node->last->type != XML_TEXT_NODE))
474 /* Keep information about ignorable whitespace text node in previous or parent node */
475 if (ctxt->node->last)
476 *(DWORD*)&ctxt->node->last->_private |= NODE_PRIV_TRAILING_IGNORABLE_WS;
477 else if (ctxt->node->type != XML_DOCUMENT_NODE)
478 *(DWORD*)&ctxt->node->_private |= NODE_PRIV_CHILD_IGNORABLE_WS;
479 return;
483 xmlSAX2Characters(ctxt, ch, len);
486 static void LIBXML2_LOG_CALLBACK sax_error(void* ctx, char const* msg, ...)
488 va_list ap;
489 va_start(ap, msg);
490 LIBXML2_CALLBACK_ERR(doparse, msg, ap);
491 va_end(ap);
494 static void LIBXML2_LOG_CALLBACK sax_warning(void* ctx, char const* msg, ...)
496 va_list ap;
497 va_start(ap, msg);
498 LIBXML2_CALLBACK_WARN(doparse, msg, ap);
499 va_end(ap);
502 static void sax_serror(void* ctx, xmlErrorPtr err)
504 LIBXML2_CALLBACK_SERROR(doparse, err);
507 static xmlDocPtr doparse(domdoc* This, char const* ptr, int len, xmlCharEncoding encoding)
509 xmlDocPtr doc = NULL;
510 xmlParserCtxtPtr pctx;
511 static xmlSAXHandler sax_handler = {
512 xmlSAX2InternalSubset, /* internalSubset */
513 xmlSAX2IsStandalone, /* isStandalone */
514 xmlSAX2HasInternalSubset, /* hasInternalSubset */
515 xmlSAX2HasExternalSubset, /* hasExternalSubset */
516 xmlSAX2ResolveEntity, /* resolveEntity */
517 xmlSAX2GetEntity, /* getEntity */
518 xmlSAX2EntityDecl, /* entityDecl */
519 xmlSAX2NotationDecl, /* notationDecl */
520 xmlSAX2AttributeDecl, /* attributeDecl */
521 xmlSAX2ElementDecl, /* elementDecl */
522 xmlSAX2UnparsedEntityDecl, /* unparsedEntityDecl */
523 xmlSAX2SetDocumentLocator, /* setDocumentLocator */
524 xmlSAX2StartDocument, /* startDocument */
525 xmlSAX2EndDocument, /* endDocument */
526 xmlSAX2StartElement, /* startElement */
527 xmlSAX2EndElement, /* endElement */
528 xmlSAX2Reference, /* reference */
529 sax_characters, /* characters */
530 sax_characters, /* ignorableWhitespace */
531 xmlSAX2ProcessingInstruction, /* processingInstruction */
532 xmlSAX2Comment, /* comment */
533 sax_warning, /* warning */
534 sax_error, /* error */
535 sax_error, /* fatalError */
536 xmlSAX2GetParameterEntity, /* getParameterEntity */
537 xmlSAX2CDataBlock, /* cdataBlock */
538 xmlSAX2ExternalSubset, /* externalSubset */
539 0, /* initialized */
540 NULL, /* _private */
541 xmlSAX2StartElementNs, /* startElementNs */
542 xmlSAX2EndElementNs, /* endElementNs */
543 sax_serror /* serror */
546 pctx = xmlCreateMemoryParserCtxt(ptr, len);
547 if (!pctx)
549 ERR("Failed to create parser context\n");
550 return NULL;
553 if (pctx->sax) xmlFree(pctx->sax);
554 pctx->sax = &sax_handler;
555 pctx->_private = This;
556 pctx->recovery = 0;
558 if (encoding != XML_CHAR_ENCODING_NONE)
559 xmlSwitchEncoding(pctx, encoding);
561 xmlParseDocument(pctx);
563 if (pctx->wellFormed)
565 doc = pctx->myDoc;
567 else
569 xmlFreeDoc(pctx->myDoc);
570 pctx->myDoc = NULL;
572 pctx->sax = NULL;
573 xmlFreeParserCtxt(pctx);
575 /* TODO: put this in one of the SAX callbacks */
576 /* create first child as a <?xml...?> */
577 if (doc && doc->standalone != -1)
579 xmlNodePtr node;
580 char buff[30];
581 xmlChar *xmlbuff = (xmlChar*)buff;
583 node = xmlNewDocPI( doc, (xmlChar*)"xml", NULL );
585 /* version attribute can't be omitted */
586 sprintf(buff, "version=\"%s\"", doc->version ? (char*)doc->version : "1.0");
587 xmlNodeAddContent( node, xmlbuff );
589 if (doc->encoding)
591 sprintf(buff, " encoding=\"%s\"", doc->encoding);
592 xmlNodeAddContent( node, xmlbuff );
595 if (doc->standalone != -2)
597 sprintf(buff, " standalone=\"%s\"", doc->standalone == 0 ? "no" : "yes");
598 xmlNodeAddContent( node, xmlbuff );
601 xmldoc_link_xmldecl( doc, node );
604 return doc;
607 void xmldoc_init(xmlDocPtr doc, MSXML_VERSION version)
609 doc->_private = create_priv();
610 priv_from_xmlDocPtr(doc)->properties = create_properties(version);
613 LONG xmldoc_add_refs(xmlDocPtr doc, LONG refs)
615 LONG ref = InterlockedExchangeAdd(&priv_from_xmlDocPtr(doc)->refs, refs) + refs;
616 TRACE("(%p)->(%d)\n", doc, ref);
617 return ref;
620 LONG xmldoc_add_ref(xmlDocPtr doc)
622 return xmldoc_add_refs(doc, 1);
625 LONG xmldoc_release_refs(xmlDocPtr doc, LONG refs)
627 xmldoc_priv *priv = priv_from_xmlDocPtr(doc);
628 LONG ref = InterlockedExchangeAdd(&priv->refs, -refs) - refs;
629 TRACE("(%p)->(%d)\n", doc, ref);
631 if (ref < 0)
632 WARN("negative refcount, expect troubles\n");
634 if (ref == 0)
636 orphan_entry *orphan, *orphan2;
637 TRACE("freeing docptr %p\n", doc);
639 LIST_FOR_EACH_ENTRY_SAFE( orphan, orphan2, &priv->orphans, orphan_entry, entry )
641 xmlFreeNode( orphan->node );
642 heap_free( orphan );
644 properties_release(priv->properties);
645 heap_free(doc->_private);
647 xmlFreeDoc(doc);
650 return ref;
653 LONG xmldoc_release(xmlDocPtr doc)
655 return xmldoc_release_refs(doc, 1);
658 HRESULT xmldoc_add_orphan(xmlDocPtr doc, xmlNodePtr node)
660 xmldoc_priv *priv = priv_from_xmlDocPtr(doc);
661 orphan_entry *entry;
663 entry = heap_alloc( sizeof (*entry) );
664 if(!entry)
665 return E_OUTOFMEMORY;
667 entry->node = node;
668 list_add_head( &priv->orphans, &entry->entry );
669 return S_OK;
672 HRESULT xmldoc_remove_orphan(xmlDocPtr doc, xmlNodePtr node)
674 xmldoc_priv *priv = priv_from_xmlDocPtr(doc);
675 orphan_entry *entry, *entry2;
677 LIST_FOR_EACH_ENTRY_SAFE( entry, entry2, &priv->orphans, orphan_entry, entry )
679 if( entry->node == node )
681 list_remove( &entry->entry );
682 heap_free( entry );
683 return S_OK;
687 return S_FALSE;
690 static inline xmlDocPtr get_doc( domdoc *This )
692 return This->node.node->doc;
695 static HRESULT attach_xmldoc(domdoc *This, xmlDocPtr xml )
697 release_namespaces(This);
699 if(This->node.node)
701 properties_release(properties_from_xmlDocPtr(get_doc(This)));
702 priv_from_xmlDocPtr(get_doc(This))->properties = NULL;
703 if (xmldoc_release(get_doc(This)) != 0)
705 /* The xmlDocPtr object can no longer use the properties of this
706 * domdoc object. So give it its own copy.
708 priv_from_xmlDocPtr(get_doc(This))->properties =
709 copy_properties(This->properties);
713 This->node.node = (xmlNodePtr) xml;
715 if(This->node.node)
717 xmldoc_add_ref(get_doc(This));
718 /* Only attach new xmlDocPtr objects, i.e. ones for which properties
719 * is still NULL.
721 priv_from_xmlDocPtr(get_doc(This))->properties = properties_add_ref(This->properties);
724 return S_OK;
727 static inline domdoc *impl_from_IXMLDOMDocument3( IXMLDOMDocument3 *iface )
729 return CONTAINING_RECORD(iface, domdoc, IXMLDOMDocument3_iface);
732 static inline domdoc *impl_from_IPersistStreamInit(IPersistStreamInit *iface)
734 return CONTAINING_RECORD(iface, domdoc, IPersistStreamInit_iface);
737 static inline domdoc *impl_from_IObjectWithSite(IObjectWithSite *iface)
739 return CONTAINING_RECORD(iface, domdoc, IObjectWithSite_iface);
742 static inline domdoc *impl_from_IObjectSafety(IObjectSafety *iface)
744 return CONTAINING_RECORD(iface, domdoc, IObjectSafety_iface);
747 static inline domdoc *impl_from_IConnectionPointContainer(IConnectionPointContainer *iface)
749 return CONTAINING_RECORD(iface, domdoc, IConnectionPointContainer_iface);
752 /************************************************************************
753 * domdoc implementation of IPersistStream.
755 static HRESULT WINAPI PersistStreamInit_QueryInterface(
756 IPersistStreamInit *iface, REFIID riid, void **ppvObj)
758 domdoc* This = impl_from_IPersistStreamInit(iface);
759 return IXMLDOMDocument3_QueryInterface(&This->IXMLDOMDocument3_iface, riid, ppvObj);
762 static ULONG WINAPI PersistStreamInit_AddRef(
763 IPersistStreamInit *iface)
765 domdoc* This = impl_from_IPersistStreamInit(iface);
766 return IXMLDOMDocument3_AddRef(&This->IXMLDOMDocument3_iface);
769 static ULONG WINAPI PersistStreamInit_Release(
770 IPersistStreamInit *iface)
772 domdoc* This = impl_from_IPersistStreamInit(iface);
773 return IXMLDOMDocument3_Release(&This->IXMLDOMDocument3_iface);
776 static HRESULT WINAPI PersistStreamInit_GetClassID(
777 IPersistStreamInit *iface, CLSID *classid)
779 domdoc* This = impl_from_IPersistStreamInit(iface);
780 TRACE("(%p)->(%p)\n", This, classid);
782 if(!classid)
783 return E_POINTER;
785 *classid = *DOMDocument_version(This->properties->version);
787 return S_OK;
790 static HRESULT WINAPI PersistStreamInit_IsDirty(
791 IPersistStreamInit *iface)
793 domdoc *This = impl_from_IPersistStreamInit(iface);
794 FIXME("(%p): stub!\n", This);
795 return S_FALSE;
798 static HRESULT domdoc_load_from_stream(domdoc *doc, ISequentialStream *stream)
800 DWORD read, written, len;
801 xmlDocPtr xmldoc = NULL;
802 IStream *hstream;
803 HGLOBAL hglobal;
804 BYTE buf[4096];
805 HRESULT hr;
806 char *ptr;
808 hstream = NULL;
809 hr = CreateStreamOnHGlobal(NULL, TRUE, &hstream);
810 if (FAILED(hr))
811 return hr;
815 ISequentialStream_Read(stream, buf, sizeof(buf), &read);
816 hr = IStream_Write(hstream, buf, read, &written);
817 } while(SUCCEEDED(hr) && written != 0 && read != 0);
819 if (FAILED(hr))
821 ERR("failed to copy stream 0x%08x\n", hr);
822 IStream_Release(hstream);
823 return hr;
826 hr = GetHGlobalFromStream(hstream, &hglobal);
827 if (FAILED(hr))
829 IStream_Release(hstream);
830 return hr;
833 len = GlobalSize(hglobal);
834 ptr = GlobalLock(hglobal);
835 if (len)
836 xmldoc = doparse(doc, ptr, len, XML_CHAR_ENCODING_NONE);
837 GlobalUnlock(hglobal);
838 IStream_Release(hstream);
840 if (!xmldoc)
842 ERR("Failed to parse xml\n");
843 return E_FAIL;
846 xmldoc->_private = create_priv();
848 return attach_xmldoc(doc, xmldoc);
851 static HRESULT WINAPI PersistStreamInit_Load(IPersistStreamInit *iface, IStream *stream)
853 domdoc *This = impl_from_IPersistStreamInit(iface);
855 TRACE("(%p)->(%p)\n", This, stream);
857 if (!stream)
858 return E_INVALIDARG;
860 return This->error = domdoc_load_from_stream(This, (ISequentialStream*)stream);
863 static HRESULT WINAPI PersistStreamInit_Save(
864 IPersistStreamInit *iface, IStream *stream, BOOL clr_dirty)
866 domdoc *This = impl_from_IPersistStreamInit(iface);
867 BSTR xmlString;
868 HRESULT hr;
870 TRACE("(%p)->(%p %d)\n", This, stream, clr_dirty);
872 hr = IXMLDOMDocument3_get_xml(&This->IXMLDOMDocument3_iface, &xmlString);
873 if(hr == S_OK)
875 DWORD len = SysStringLen(xmlString) * sizeof(WCHAR);
877 hr = IStream_Write( stream, xmlString, len, NULL );
878 SysFreeString(xmlString);
881 TRACE("ret 0x%08x\n", hr);
883 return hr;
886 static HRESULT WINAPI PersistStreamInit_GetSizeMax(
887 IPersistStreamInit *iface, ULARGE_INTEGER *pcbSize)
889 domdoc *This = impl_from_IPersistStreamInit(iface);
890 TRACE("(%p)->(%p)\n", This, pcbSize);
891 return E_NOTIMPL;
894 static HRESULT WINAPI PersistStreamInit_InitNew(
895 IPersistStreamInit *iface)
897 domdoc *This = impl_from_IPersistStreamInit(iface);
898 TRACE("(%p)\n", This);
899 return S_OK;
902 static const IPersistStreamInitVtbl xmldoc_IPersistStreamInit_VTable =
904 PersistStreamInit_QueryInterface,
905 PersistStreamInit_AddRef,
906 PersistStreamInit_Release,
907 PersistStreamInit_GetClassID,
908 PersistStreamInit_IsDirty,
909 PersistStreamInit_Load,
910 PersistStreamInit_Save,
911 PersistStreamInit_GetSizeMax,
912 PersistStreamInit_InitNew
915 /* IXMLDOMDocument3 interface */
917 static const tid_t domdoc_se_tids[] = {
918 IXMLDOMNode_tid,
919 IXMLDOMDocument_tid,
920 IXMLDOMDocument2_tid,
921 IXMLDOMDocument3_tid,
922 NULL_tid
925 static HRESULT WINAPI domdoc_QueryInterface( IXMLDOMDocument3 *iface, REFIID riid, void** ppvObject )
927 domdoc *This = impl_from_IXMLDOMDocument3( iface );
929 TRACE("(%p)->(%s %p)\n", This, debugstr_guid( riid ), ppvObject );
931 *ppvObject = NULL;
933 if ( IsEqualGUID( riid, &IID_IUnknown ) ||
934 IsEqualGUID( riid, &IID_IDispatch ) ||
935 IsEqualGUID( riid, &IID_IXMLDOMNode ) ||
936 IsEqualGUID( riid, &IID_IXMLDOMDocument ) ||
937 IsEqualGUID( riid, &IID_IXMLDOMDocument2 )||
938 IsEqualGUID( riid, &IID_IXMLDOMDocument3 ))
940 *ppvObject = iface;
942 else if (IsEqualGUID(&IID_IPersistStream, riid) ||
943 IsEqualGUID(&IID_IPersistStreamInit, riid))
945 *ppvObject = &This->IPersistStreamInit_iface;
947 else if (IsEqualGUID(&IID_IObjectWithSite, riid))
949 *ppvObject = &This->IObjectWithSite_iface;
951 else if (IsEqualGUID(&IID_IObjectSafety, riid))
953 *ppvObject = &This->IObjectSafety_iface;
955 else if( IsEqualGUID( riid, &IID_ISupportErrorInfo ))
957 return node_create_supporterrorinfo(domdoc_se_tids, ppvObject);
959 else if(node_query_interface(&This->node, riid, ppvObject))
961 return *ppvObject ? S_OK : E_NOINTERFACE;
963 else if (IsEqualGUID( riid, &IID_IConnectionPointContainer ))
965 *ppvObject = &This->IConnectionPointContainer_iface;
967 else
969 TRACE("interface %s not implemented\n", debugstr_guid(riid));
970 return E_NOINTERFACE;
973 IUnknown_AddRef((IUnknown*)*ppvObject);
975 return S_OK;
978 static ULONG WINAPI domdoc_AddRef( IXMLDOMDocument3 *iface )
980 domdoc *This = impl_from_IXMLDOMDocument3( iface );
981 ULONG ref = InterlockedIncrement( &This->ref );
982 TRACE("(%p)->(%d)\n", This, ref );
983 return ref;
986 static ULONG WINAPI domdoc_Release( IXMLDOMDocument3 *iface )
988 domdoc *This = impl_from_IXMLDOMDocument3( iface );
989 LONG ref = InterlockedDecrement( &This->ref );
991 TRACE("(%p)->(%d)\n", This, ref );
993 if ( ref == 0 )
995 int eid;
997 if (This->site)
998 IUnknown_Release( This->site );
999 if (This->base_uri)
1000 IUri_Release( This->base_uri );
1001 destroy_xmlnode(&This->node);
1003 for (eid = 0; eid < EVENTID_LAST; eid++)
1004 if (This->events[eid]) IDispatch_Release(This->events[eid]);
1006 properties_release(This->properties);
1007 release_namespaces(This);
1008 heap_free(This);
1011 return ref;
1014 static HRESULT WINAPI domdoc_GetTypeInfoCount( IXMLDOMDocument3 *iface, UINT* pctinfo )
1016 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1017 return IDispatchEx_GetTypeInfoCount(&This->node.dispex.IDispatchEx_iface, pctinfo);
1020 static HRESULT WINAPI domdoc_GetTypeInfo(
1021 IXMLDOMDocument3 *iface,
1022 UINT iTInfo, LCID lcid, ITypeInfo** ppTInfo )
1024 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1025 return IDispatchEx_GetTypeInfo(&This->node.dispex.IDispatchEx_iface, iTInfo, lcid, ppTInfo);
1028 static HRESULT WINAPI domdoc_GetIDsOfNames(
1029 IXMLDOMDocument3 *iface,
1030 REFIID riid,
1031 LPOLESTR* rgszNames,
1032 UINT cNames,
1033 LCID lcid,
1034 DISPID* rgDispId)
1036 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1037 return IDispatchEx_GetIDsOfNames(&This->node.dispex.IDispatchEx_iface,
1038 riid, rgszNames, cNames, lcid, rgDispId);
1041 static HRESULT WINAPI domdoc_Invoke(
1042 IXMLDOMDocument3 *iface,
1043 DISPID dispIdMember,
1044 REFIID riid,
1045 LCID lcid,
1046 WORD wFlags,
1047 DISPPARAMS* pDispParams,
1048 VARIANT* pVarResult,
1049 EXCEPINFO* pExcepInfo,
1050 UINT* puArgErr)
1052 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1053 return IDispatchEx_Invoke(&This->node.dispex.IDispatchEx_iface,
1054 dispIdMember, riid, lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
1057 static HRESULT WINAPI domdoc_get_nodeName(
1058 IXMLDOMDocument3 *iface,
1059 BSTR* name )
1061 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1063 static const WCHAR documentW[] = {'#','d','o','c','u','m','e','n','t',0};
1065 TRACE("(%p)->(%p)\n", This, name);
1067 return return_bstr(documentW, name);
1071 static HRESULT WINAPI domdoc_get_nodeValue(
1072 IXMLDOMDocument3 *iface,
1073 VARIANT* value )
1075 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1077 TRACE("(%p)->(%p)\n", This, value);
1079 if(!value)
1080 return E_INVALIDARG;
1082 V_VT(value) = VT_NULL;
1083 V_BSTR(value) = NULL; /* tests show that we should do this */
1084 return S_FALSE;
1088 static HRESULT WINAPI domdoc_put_nodeValue(
1089 IXMLDOMDocument3 *iface,
1090 VARIANT value)
1092 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1093 TRACE("(%p)->(%s)\n", This, debugstr_variant(&value));
1094 return E_FAIL;
1098 static HRESULT WINAPI domdoc_get_nodeType(
1099 IXMLDOMDocument3 *iface,
1100 DOMNodeType* type )
1102 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1104 TRACE("(%p)->(%p)\n", This, type);
1106 *type = NODE_DOCUMENT;
1107 return S_OK;
1111 static HRESULT WINAPI domdoc_get_parentNode(
1112 IXMLDOMDocument3 *iface,
1113 IXMLDOMNode** parent )
1115 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1117 TRACE("(%p)->(%p)\n", This, parent);
1119 return node_get_parent(&This->node, parent);
1123 static HRESULT WINAPI domdoc_get_childNodes(
1124 IXMLDOMDocument3 *iface,
1125 IXMLDOMNodeList** childList )
1127 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1129 TRACE("(%p)->(%p)\n", This, childList);
1131 return node_get_child_nodes(&This->node, childList);
1135 static HRESULT WINAPI domdoc_get_firstChild(
1136 IXMLDOMDocument3 *iface,
1137 IXMLDOMNode** firstChild )
1139 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1141 TRACE("(%p)->(%p)\n", This, firstChild);
1143 return node_get_first_child(&This->node, firstChild);
1147 static HRESULT WINAPI domdoc_get_lastChild(
1148 IXMLDOMDocument3 *iface,
1149 IXMLDOMNode** lastChild )
1151 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1153 TRACE("(%p)->(%p)\n", This, lastChild);
1155 return node_get_last_child(&This->node, lastChild);
1159 static HRESULT WINAPI domdoc_get_previousSibling(
1160 IXMLDOMDocument3 *iface,
1161 IXMLDOMNode** previousSibling )
1163 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1165 TRACE("(%p)->(%p)\n", This, previousSibling);
1167 return return_null_node(previousSibling);
1171 static HRESULT WINAPI domdoc_get_nextSibling(
1172 IXMLDOMDocument3 *iface,
1173 IXMLDOMNode** nextSibling )
1175 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1177 TRACE("(%p)->(%p)\n", This, nextSibling);
1179 return return_null_node(nextSibling);
1183 static HRESULT WINAPI domdoc_get_attributes(
1184 IXMLDOMDocument3 *iface,
1185 IXMLDOMNamedNodeMap** attributeMap )
1187 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1189 TRACE("(%p)->(%p)\n", This, attributeMap);
1191 return return_null_ptr((void**)attributeMap);
1195 static HRESULT WINAPI domdoc_insertBefore(
1196 IXMLDOMDocument3 *iface,
1197 IXMLDOMNode* newChild,
1198 VARIANT refChild,
1199 IXMLDOMNode** outNewChild )
1201 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1202 DOMNodeType type;
1203 HRESULT hr;
1205 TRACE("(%p)->(%p %s %p)\n", This, newChild, debugstr_variant(&refChild), outNewChild);
1207 if (!newChild) return E_INVALIDARG;
1209 hr = IXMLDOMNode_get_nodeType(newChild, &type);
1210 if (hr != S_OK) return hr;
1212 TRACE("new node type %d\n", type);
1213 switch (type)
1215 case NODE_ATTRIBUTE:
1216 case NODE_DOCUMENT:
1217 case NODE_CDATA_SECTION:
1218 if (outNewChild) *outNewChild = NULL;
1219 return E_FAIL;
1220 default:
1221 return node_insert_before(&This->node, newChild, &refChild, outNewChild);
1225 static HRESULT WINAPI domdoc_replaceChild(
1226 IXMLDOMDocument3 *iface,
1227 IXMLDOMNode* newChild,
1228 IXMLDOMNode* oldChild,
1229 IXMLDOMNode** outOldChild)
1231 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1233 TRACE("(%p)->(%p %p %p)\n", This, newChild, oldChild, outOldChild);
1235 return node_replace_child(&This->node, newChild, oldChild, outOldChild);
1239 static HRESULT WINAPI domdoc_removeChild(
1240 IXMLDOMDocument3 *iface,
1241 IXMLDOMNode *child,
1242 IXMLDOMNode **oldChild)
1244 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1245 TRACE("(%p)->(%p %p)\n", This, child, oldChild);
1246 return node_remove_child(&This->node, child, oldChild);
1250 static HRESULT WINAPI domdoc_appendChild(
1251 IXMLDOMDocument3 *iface,
1252 IXMLDOMNode *child,
1253 IXMLDOMNode **outChild)
1255 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1256 TRACE("(%p)->(%p %p)\n", This, child, outChild);
1257 return node_append_child(&This->node, child, outChild);
1261 static HRESULT WINAPI domdoc_hasChildNodes(
1262 IXMLDOMDocument3 *iface,
1263 VARIANT_BOOL *ret)
1265 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1266 TRACE("(%p)->(%p)\n", This, ret);
1267 return node_has_childnodes(&This->node, ret);
1271 static HRESULT WINAPI domdoc_get_ownerDocument(
1272 IXMLDOMDocument3 *iface,
1273 IXMLDOMDocument **doc)
1275 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1276 TRACE("(%p)->(%p)\n", This, doc);
1277 return node_get_owner_doc(&This->node, doc);
1281 static HRESULT WINAPI domdoc_cloneNode(
1282 IXMLDOMDocument3 *iface,
1283 VARIANT_BOOL deep,
1284 IXMLDOMNode** outNode)
1286 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1287 xmlNodePtr clone;
1289 TRACE("(%p)->(%d %p)\n", This, deep, outNode);
1291 if (!outNode)
1292 return E_INVALIDARG;
1294 *outNode = NULL;
1296 clone = xmlCopyNode((xmlNodePtr)get_doc(This), deep ? 1 : 2);
1297 if (!clone)
1298 return E_FAIL;
1300 clone->doc->_private = create_priv();
1301 xmldoc_add_orphan(clone->doc, clone);
1302 xmldoc_add_ref(clone->doc);
1304 priv_from_xmlDocPtr(clone->doc)->properties = copy_properties(This->properties);
1305 if (!(*outNode = (IXMLDOMNode*)create_domdoc(clone)))
1307 xmldoc_release(clone->doc);
1308 return E_FAIL;
1311 return S_OK;
1315 static HRESULT WINAPI domdoc_get_nodeTypeString(
1316 IXMLDOMDocument3 *iface,
1317 BSTR *p)
1319 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1320 static const WCHAR documentW[] = {'d','o','c','u','m','e','n','t',0};
1322 TRACE("(%p)->(%p)\n", This, p);
1324 return return_bstr(documentW, p);
1328 static HRESULT WINAPI domdoc_get_text(
1329 IXMLDOMDocument3 *iface,
1330 BSTR *p)
1332 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1333 TRACE("(%p)->(%p)\n", This, p);
1334 return node_get_text(&This->node, p);
1338 static HRESULT WINAPI domdoc_put_text(
1339 IXMLDOMDocument3 *iface,
1340 BSTR text )
1342 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1343 TRACE("(%p)->(%s)\n", This, debugstr_w(text));
1344 return E_FAIL;
1348 static HRESULT WINAPI domdoc_get_specified(
1349 IXMLDOMDocument3 *iface,
1350 VARIANT_BOOL* isSpecified )
1352 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1353 FIXME("(%p)->(%p) stub!\n", This, isSpecified);
1354 *isSpecified = VARIANT_TRUE;
1355 return S_OK;
1359 static HRESULT WINAPI domdoc_get_definition(
1360 IXMLDOMDocument3 *iface,
1361 IXMLDOMNode** definitionNode )
1363 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1364 FIXME("(%p)->(%p)\n", This, definitionNode);
1365 return E_NOTIMPL;
1369 static HRESULT WINAPI domdoc_get_nodeTypedValue(
1370 IXMLDOMDocument3 *iface,
1371 VARIANT* v )
1373 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1374 TRACE("(%p)->(%p)\n", This, v);
1375 return return_null_var(v);
1378 static HRESULT WINAPI domdoc_put_nodeTypedValue(
1379 IXMLDOMDocument3 *iface,
1380 VARIANT typedValue )
1382 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1383 FIXME("(%p)->(%s)\n", This, debugstr_variant(&typedValue));
1384 return E_NOTIMPL;
1388 static HRESULT WINAPI domdoc_get_dataType(
1389 IXMLDOMDocument3 *iface,
1390 VARIANT* typename )
1392 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1393 TRACE("(%p)->(%p)\n", This, typename);
1394 return return_null_var( typename );
1398 static HRESULT WINAPI domdoc_put_dataType(
1399 IXMLDOMDocument3 *iface,
1400 BSTR dataTypeName )
1402 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1404 FIXME("(%p)->(%s)\n", This, debugstr_w(dataTypeName));
1406 if(!dataTypeName)
1407 return E_INVALIDARG;
1409 return E_FAIL;
1412 static int XMLCALL domdoc_get_xml_writecallback(void *ctx, const char *data, int len)
1414 return xmlBufferAdd((xmlBufferPtr)ctx, (xmlChar*)data, len) == 0 ? len : 0;
1417 static HRESULT WINAPI domdoc_get_xml(
1418 IXMLDOMDocument3 *iface,
1419 BSTR* p)
1421 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1422 xmlSaveCtxtPtr ctxt;
1423 xmlBufferPtr buf;
1424 int options;
1425 long ret;
1427 TRACE("(%p)->(%p)\n", This, p);
1429 if(!p)
1430 return E_INVALIDARG;
1432 *p = NULL;
1434 buf = xmlBufferCreate();
1435 if(!buf)
1436 return E_OUTOFMEMORY;
1438 options = XML_SAVE_FORMAT | XML_SAVE_NO_DECL;
1439 ctxt = xmlSaveToIO(domdoc_get_xml_writecallback, NULL, buf, "UTF-8", options);
1441 if(!ctxt)
1443 xmlBufferFree(buf);
1444 return E_OUTOFMEMORY;
1447 ret = xmlSaveDoc(ctxt, get_doc(This));
1448 /* flushes on close */
1449 xmlSaveClose(ctxt);
1451 TRACE("%ld, len=%d\n", ret, xmlBufferLength(buf));
1452 if(ret != -1 && xmlBufferLength(buf) > 0)
1454 BSTR content;
1456 content = bstr_from_xmlChar(xmlBufferContent(buf));
1457 content = EnsureCorrectEOL(content);
1459 *p = content;
1461 else
1463 *p = SysAllocStringLen(NULL, 0);
1466 xmlBufferFree(buf);
1468 return *p ? S_OK : E_OUTOFMEMORY;
1472 static HRESULT WINAPI domdoc_transformNode(
1473 IXMLDOMDocument3 *iface,
1474 IXMLDOMNode *node,
1475 BSTR *p)
1477 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1478 TRACE("(%p)->(%p %p)\n", This, node, p);
1479 return node_transform_node(&This->node, node, p);
1483 static HRESULT WINAPI domdoc_selectNodes(
1484 IXMLDOMDocument3 *iface,
1485 BSTR p,
1486 IXMLDOMNodeList **outList)
1488 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1489 TRACE("(%p)->(%s %p)\n", This, debugstr_w(p), outList);
1490 return node_select_nodes(&This->node, p, outList);
1494 static HRESULT WINAPI domdoc_selectSingleNode(
1495 IXMLDOMDocument3 *iface,
1496 BSTR p,
1497 IXMLDOMNode **outNode)
1499 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1500 TRACE("(%p)->(%s %p)\n", This, debugstr_w(p), outNode);
1501 return node_select_singlenode(&This->node, p, outNode);
1505 static HRESULT WINAPI domdoc_get_parsed(
1506 IXMLDOMDocument3 *iface,
1507 VARIANT_BOOL* isParsed )
1509 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1510 FIXME("(%p)->(%p) stub!\n", This, isParsed);
1511 *isParsed = VARIANT_TRUE;
1512 return S_OK;
1515 static HRESULT WINAPI domdoc_get_namespaceURI(
1516 IXMLDOMDocument3 *iface,
1517 BSTR* namespaceURI )
1519 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1520 TRACE("(%p)->(%p)\n", This, namespaceURI);
1521 return return_null_bstr( namespaceURI );
1524 static HRESULT WINAPI domdoc_get_prefix(
1525 IXMLDOMDocument3 *iface,
1526 BSTR* prefix )
1528 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1529 TRACE("(%p)->(%p)\n", This, prefix);
1530 return return_null_bstr( prefix );
1534 static HRESULT WINAPI domdoc_get_baseName(
1535 IXMLDOMDocument3 *iface,
1536 BSTR* name )
1538 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1539 TRACE("(%p)->(%p)\n", This, name);
1540 return return_null_bstr( name );
1544 static HRESULT WINAPI domdoc_transformNodeToObject(
1545 IXMLDOMDocument3 *iface,
1546 IXMLDOMNode* stylesheet,
1547 VARIANT output)
1549 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1551 TRACE("(%p)->(%p %s)\n", This, stylesheet, debugstr_variant(&output));
1553 switch (V_VT(&output))
1555 case VT_UNKNOWN:
1556 case VT_DISPATCH:
1558 ISequentialStream *stream;
1559 IXMLDOMDocument *doc;
1560 HRESULT hr;
1561 BSTR str;
1563 if (!V_UNKNOWN(&output))
1564 return E_INVALIDARG;
1566 /* FIXME: we're not supposed to query for document interface, should use IStream
1567 which we don't support currently. */
1568 if (IUnknown_QueryInterface(V_UNKNOWN(&output), &IID_IXMLDOMDocument, (void **)&doc) == S_OK)
1570 VARIANT_BOOL b;
1572 if (FAILED(hr = node_transform_node(&This->node, stylesheet, &str)))
1573 return hr;
1575 hr = IXMLDOMDocument_loadXML(doc, str, &b);
1576 SysFreeString(str);
1577 return hr;
1579 else if (IUnknown_QueryInterface(V_UNKNOWN(&output), &IID_ISequentialStream, (void**)&stream) == S_OK)
1581 hr = node_transform_node_params(&This->node, stylesheet, NULL, stream, NULL);
1582 ISequentialStream_Release(stream);
1583 return hr;
1585 else
1587 FIXME("Unsupported destination type.\n");
1588 return E_INVALIDARG;
1591 default:
1592 FIXME("Output type %d not handled.\n", V_VT(&output));
1593 return E_NOTIMPL;
1596 return E_NOTIMPL;
1600 static HRESULT WINAPI domdoc_get_doctype(
1601 IXMLDOMDocument3 *iface,
1602 IXMLDOMDocumentType** doctype )
1604 domdoc *This = impl_from_IXMLDOMDocument3(iface);
1605 IXMLDOMNode *node;
1606 xmlDtdPtr dtd;
1607 HRESULT hr;
1609 TRACE("(%p)->(%p)\n", This, doctype);
1611 if (!doctype) return E_INVALIDARG;
1613 *doctype = NULL;
1615 dtd = xmlGetIntSubset(get_doc(This));
1616 if (!dtd) return S_FALSE;
1618 node = create_node((xmlNodePtr)dtd);
1619 if (!node) return S_FALSE;
1621 hr = IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMDocumentType, (void**)doctype);
1622 IXMLDOMNode_Release(node);
1624 return hr;
1628 static HRESULT WINAPI domdoc_get_implementation(
1629 IXMLDOMDocument3 *iface,
1630 IXMLDOMImplementation** impl )
1632 domdoc *This = impl_from_IXMLDOMDocument3(iface);
1634 TRACE("(%p)->(%p)\n", This, impl);
1636 if(!impl)
1637 return E_INVALIDARG;
1639 return create_dom_implementation(impl);
1642 static HRESULT WINAPI domdoc_get_documentElement(
1643 IXMLDOMDocument3 *iface,
1644 IXMLDOMElement** DOMElement )
1646 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1647 IXMLDOMNode *element_node;
1648 xmlNodePtr root;
1649 HRESULT hr;
1651 TRACE("(%p)->(%p)\n", This, DOMElement);
1653 if(!DOMElement)
1654 return E_INVALIDARG;
1656 *DOMElement = NULL;
1658 root = xmlDocGetRootElement( get_doc(This) );
1659 if ( !root )
1660 return S_FALSE;
1662 element_node = create_node( root );
1663 if(!element_node) return S_FALSE;
1665 hr = IXMLDOMNode_QueryInterface(element_node, &IID_IXMLDOMElement, (void**)DOMElement);
1666 IXMLDOMNode_Release(element_node);
1668 return hr;
1672 static HRESULT WINAPI domdoc_put_documentElement(
1673 IXMLDOMDocument3 *iface,
1674 IXMLDOMElement* DOMElement )
1676 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1677 IXMLDOMNode *elementNode;
1678 xmlNodePtr oldRoot;
1679 xmlDocPtr old_doc;
1680 xmlnode *xmlNode;
1681 int refcount = 0;
1682 HRESULT hr;
1684 TRACE("(%p)->(%p)\n", This, DOMElement);
1686 hr = IXMLDOMElement_QueryInterface( DOMElement, &IID_IXMLDOMNode, (void**)&elementNode );
1687 if(FAILED(hr))
1688 return hr;
1690 xmlNode = get_node_obj( elementNode );
1691 if(!xmlNode) return E_FAIL;
1693 if(!xmlNode->node->parent)
1694 if(xmldoc_remove_orphan(xmlNode->node->doc, xmlNode->node) != S_OK)
1695 WARN("%p is not an orphan of %p\n", xmlNode->node->doc, xmlNode->node);
1697 old_doc = xmlNode->node->doc;
1698 if (old_doc != get_doc(This))
1699 refcount = xmlnode_get_inst_cnt(xmlNode);
1701 /* old root is still orphaned by its document, update refcount from new root */
1702 if (refcount) xmldoc_add_refs(get_doc(This), refcount);
1703 oldRoot = xmlDocSetRootElement( get_doc(This), xmlNode->node);
1704 if (refcount) xmldoc_release_refs(old_doc, refcount);
1705 IXMLDOMNode_Release( elementNode );
1707 if(oldRoot)
1708 xmldoc_add_orphan(oldRoot->doc, oldRoot);
1710 return S_OK;
1714 static HRESULT WINAPI domdoc_createElement(
1715 IXMLDOMDocument3 *iface,
1716 BSTR tagname,
1717 IXMLDOMElement** element )
1719 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1720 IXMLDOMNode *node;
1721 VARIANT type;
1722 HRESULT hr;
1724 TRACE("(%p)->(%s %p)\n", This, debugstr_w(tagname), element);
1726 if (!element || !tagname) return E_INVALIDARG;
1728 V_VT(&type) = VT_I1;
1729 V_I1(&type) = NODE_ELEMENT;
1731 hr = IXMLDOMDocument3_createNode(iface, type, tagname, NULL, &node);
1732 if (hr == S_OK)
1734 IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMElement, (void**)element);
1735 IXMLDOMNode_Release(node);
1738 return hr;
1742 static HRESULT WINAPI domdoc_createDocumentFragment(
1743 IXMLDOMDocument3 *iface,
1744 IXMLDOMDocumentFragment** frag )
1746 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1747 IXMLDOMNode *node;
1748 VARIANT type;
1749 HRESULT hr;
1751 TRACE("(%p)->(%p)\n", This, frag);
1753 if (!frag) return E_INVALIDARG;
1755 *frag = NULL;
1757 V_VT(&type) = VT_I1;
1758 V_I1(&type) = NODE_DOCUMENT_FRAGMENT;
1760 hr = IXMLDOMDocument3_createNode(iface, type, NULL, NULL, &node);
1761 if (hr == S_OK)
1763 IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMDocumentFragment, (void**)frag);
1764 IXMLDOMNode_Release(node);
1767 return hr;
1771 static HRESULT WINAPI domdoc_createTextNode(
1772 IXMLDOMDocument3 *iface,
1773 BSTR data,
1774 IXMLDOMText** text )
1776 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1777 IXMLDOMNode *node;
1778 VARIANT type;
1779 HRESULT hr;
1781 TRACE("(%p)->(%s %p)\n", This, debugstr_w(data), text);
1783 if (!text) return E_INVALIDARG;
1785 *text = NULL;
1787 V_VT(&type) = VT_I1;
1788 V_I1(&type) = NODE_TEXT;
1790 hr = IXMLDOMDocument3_createNode(iface, type, NULL, NULL, &node);
1791 if (hr == S_OK)
1793 IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMText, (void**)text);
1794 IXMLDOMNode_Release(node);
1795 hr = IXMLDOMText_put_data(*text, data);
1798 return hr;
1802 static HRESULT WINAPI domdoc_createComment(
1803 IXMLDOMDocument3 *iface,
1804 BSTR data,
1805 IXMLDOMComment** comment )
1807 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1808 VARIANT type;
1809 HRESULT hr;
1810 IXMLDOMNode *node;
1812 TRACE("(%p)->(%s %p)\n", This, debugstr_w(data), comment);
1814 if (!comment) return E_INVALIDARG;
1816 *comment = NULL;
1818 V_VT(&type) = VT_I1;
1819 V_I1(&type) = NODE_COMMENT;
1821 hr = IXMLDOMDocument3_createNode(iface, type, NULL, NULL, &node);
1822 if (hr == S_OK)
1824 IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMComment, (void**)comment);
1825 IXMLDOMNode_Release(node);
1826 hr = IXMLDOMComment_put_data(*comment, data);
1829 return hr;
1833 static HRESULT WINAPI domdoc_createCDATASection(
1834 IXMLDOMDocument3 *iface,
1835 BSTR data,
1836 IXMLDOMCDATASection** cdata )
1838 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1839 IXMLDOMNode *node;
1840 VARIANT type;
1841 HRESULT hr;
1843 TRACE("(%p)->(%s %p)\n", This, debugstr_w(data), cdata);
1845 if (!cdata) return E_INVALIDARG;
1847 *cdata = NULL;
1849 V_VT(&type) = VT_I1;
1850 V_I1(&type) = NODE_CDATA_SECTION;
1852 hr = IXMLDOMDocument3_createNode(iface, type, NULL, NULL, &node);
1853 if (hr == S_OK)
1855 IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMCDATASection, (void**)cdata);
1856 IXMLDOMNode_Release(node);
1857 hr = IXMLDOMCDATASection_put_data(*cdata, data);
1860 return hr;
1864 static HRESULT WINAPI domdoc_createProcessingInstruction(
1865 IXMLDOMDocument3 *iface,
1866 BSTR target,
1867 BSTR data,
1868 IXMLDOMProcessingInstruction** pi )
1870 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1871 IXMLDOMNode *node;
1872 VARIANT type;
1873 HRESULT hr;
1875 TRACE("(%p)->(%s %s %p)\n", This, debugstr_w(target), debugstr_w(data), pi);
1877 if (!pi) return E_INVALIDARG;
1879 *pi = NULL;
1881 V_VT(&type) = VT_I1;
1882 V_I1(&type) = NODE_PROCESSING_INSTRUCTION;
1884 hr = IXMLDOMDocument3_createNode(iface, type, target, NULL, &node);
1885 if (hr == S_OK)
1887 /* this is to bypass check in ::put_data() that blocks "<?xml" PIs */
1888 hr = dom_pi_put_xml_decl(node, data);
1889 if (SUCCEEDED(hr))
1890 hr = IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMProcessingInstruction, (void**)pi);
1891 IXMLDOMNode_Release(node);
1894 return hr;
1898 static HRESULT WINAPI domdoc_createAttribute(
1899 IXMLDOMDocument3 *iface,
1900 BSTR name,
1901 IXMLDOMAttribute** attribute )
1903 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1904 IXMLDOMNode *node;
1905 VARIANT type;
1906 HRESULT hr;
1908 TRACE("(%p)->(%s %p)\n", This, debugstr_w(name), attribute);
1910 if (!attribute || !name) return E_INVALIDARG;
1912 V_VT(&type) = VT_I1;
1913 V_I1(&type) = NODE_ATTRIBUTE;
1915 hr = IXMLDOMDocument3_createNode(iface, type, name, NULL, &node);
1916 if (hr == S_OK)
1918 IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMAttribute, (void**)attribute);
1919 IXMLDOMNode_Release(node);
1922 return hr;
1926 static HRESULT WINAPI domdoc_createEntityReference(
1927 IXMLDOMDocument3 *iface,
1928 BSTR name,
1929 IXMLDOMEntityReference** entityref )
1931 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1932 IXMLDOMNode *node;
1933 VARIANT type;
1934 HRESULT hr;
1936 TRACE("(%p)->(%s %p)\n", This, debugstr_w(name), entityref);
1938 if (!entityref) return E_INVALIDARG;
1940 *entityref = NULL;
1942 V_VT(&type) = VT_I1;
1943 V_I1(&type) = NODE_ENTITY_REFERENCE;
1945 hr = IXMLDOMDocument3_createNode(iface, type, name, NULL, &node);
1946 if (hr == S_OK)
1948 IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMEntityReference, (void**)entityref);
1949 IXMLDOMNode_Release(node);
1952 return hr;
1955 xmlChar* tagName_to_XPath(const BSTR tagName)
1957 xmlChar *query, *tmp;
1958 static const xmlChar everything[] = "/descendant::node()";
1959 static const xmlChar mod_pre[] = "*[local-name()='";
1960 static const xmlChar mod_post[] = "']";
1961 static const xmlChar prefix[] = "descendant::";
1962 const WCHAR *tokBegin, *tokEnd;
1963 int len;
1965 /* Special case - empty tagname - means select all nodes,
1966 except document itself. */
1967 if (!*tagName)
1968 return xmlStrdup(everything);
1970 query = xmlStrdup(prefix);
1972 tokBegin = tagName;
1973 while (tokBegin && *tokBegin)
1975 switch (*tokBegin)
1977 case '/':
1978 query = xmlStrcat(query, BAD_CAST "/");
1979 ++tokBegin;
1980 break;
1981 case '*':
1982 query = xmlStrcat(query, BAD_CAST "*");
1983 ++tokBegin;
1984 break;
1985 default:
1986 query = xmlStrcat(query, mod_pre);
1987 tokEnd = tokBegin;
1988 while (*tokEnd && *tokEnd != '/')
1989 ++tokEnd;
1990 len = WideCharToMultiByte(CP_UTF8, 0, tokBegin, tokEnd-tokBegin, NULL, 0, NULL, NULL);
1991 tmp = xmlMalloc(len);
1992 WideCharToMultiByte(CP_UTF8, 0, tokBegin, tokEnd-tokBegin, (char*)tmp, len, NULL, NULL);
1993 query = xmlStrncat(query, tmp, len);
1994 xmlFree(tmp);
1995 tokBegin = tokEnd;
1996 query = xmlStrcat(query, mod_post);
2000 return query;
2003 static HRESULT WINAPI domdoc_getElementsByTagName(
2004 IXMLDOMDocument3 *iface,
2005 BSTR tagName,
2006 IXMLDOMNodeList** resultList )
2008 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2009 xmlChar *query;
2010 HRESULT hr;
2011 BOOL XPath;
2013 TRACE("(%p)->(%s, %p)\n", This, debugstr_w(tagName), resultList);
2015 if (!tagName || !resultList) return E_INVALIDARG;
2017 XPath = This->properties->XPath;
2018 This->properties->XPath = TRUE;
2019 query = tagName_to_XPath(tagName);
2020 hr = create_selection((xmlNodePtr)get_doc(This), query, resultList);
2021 xmlFree(query);
2022 This->properties->XPath = XPath;
2024 return hr;
2027 static HRESULT get_node_type(VARIANT Type, DOMNodeType * type)
2029 VARIANT tmp;
2030 HRESULT hr;
2032 VariantInit(&tmp);
2033 hr = VariantChangeType(&tmp, &Type, 0, VT_I4);
2034 if(FAILED(hr))
2035 return E_INVALIDARG;
2037 *type = V_I4(&tmp);
2039 return S_OK;
2042 static HRESULT WINAPI domdoc_createNode(
2043 IXMLDOMDocument3 *iface,
2044 VARIANT Type,
2045 BSTR name,
2046 BSTR namespaceURI,
2047 IXMLDOMNode** node )
2049 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2050 DOMNodeType node_type;
2051 xmlNodePtr xmlnode;
2052 xmlChar *xml_name, *href;
2053 HRESULT hr;
2055 TRACE("(%p)->(%s %s %s %p)\n", This, debugstr_variant(&Type), debugstr_w(name), debugstr_w(namespaceURI), node);
2057 if(!node) return E_INVALIDARG;
2059 hr = get_node_type(Type, &node_type);
2060 if(FAILED(hr)) return hr;
2062 TRACE("node_type %d\n", node_type);
2064 /* exit earlier for types that need name */
2065 switch(node_type)
2067 case NODE_ELEMENT:
2068 case NODE_ATTRIBUTE:
2069 case NODE_ENTITY_REFERENCE:
2070 case NODE_PROCESSING_INSTRUCTION:
2071 if (!name || *name == 0) return E_FAIL;
2072 break;
2073 default:
2074 break;
2077 xml_name = xmlchar_from_wchar(name);
2078 /* prevent empty href from being allocated */
2079 href = namespaceURI ? xmlchar_from_wchar(namespaceURI) : NULL;
2081 switch(node_type)
2083 case NODE_ELEMENT:
2085 xmlChar *local, *prefix;
2087 local = xmlSplitQName2(xml_name, &prefix);
2089 xmlnode = xmlNewDocNode(get_doc(This), NULL, local ? local : xml_name, NULL);
2091 /* allow creating the default namespace xmlns= */
2092 if (local || (href && *href))
2094 xmlNsPtr ns = xmlNewNs(xmlnode, href, prefix);
2095 xmlSetNs(xmlnode, ns);
2098 xmlFree(local);
2099 xmlFree(prefix);
2101 break;
2103 case NODE_ATTRIBUTE:
2105 xmlChar *local, *prefix;
2107 local = xmlSplitQName2(xml_name, &prefix);
2109 xmlnode = (xmlNodePtr)xmlNewDocProp(get_doc(This), local ? local : xml_name, NULL);
2111 if (local || (href && *href))
2113 /* we need a floating namespace here, it can't be created linked to attribute from
2114 a start */
2115 xmlNsPtr ns = xmlNewNs(NULL, href, prefix);
2116 xmlSetNs(xmlnode, ns);
2119 xmlFree(local);
2120 xmlFree(prefix);
2122 break;
2124 case NODE_TEXT:
2125 xmlnode = (xmlNodePtr)xmlNewDocText(get_doc(This), NULL);
2126 break;
2127 case NODE_CDATA_SECTION:
2128 xmlnode = xmlNewCDataBlock(get_doc(This), NULL, 0);
2129 break;
2130 case NODE_ENTITY_REFERENCE:
2131 xmlnode = xmlNewReference(get_doc(This), xml_name);
2132 break;
2133 case NODE_PROCESSING_INSTRUCTION:
2134 xmlnode = xmlNewDocPI(get_doc(This), xml_name, NULL);
2135 break;
2136 case NODE_COMMENT:
2137 xmlnode = xmlNewDocComment(get_doc(This), NULL);
2138 break;
2139 case NODE_DOCUMENT_FRAGMENT:
2140 xmlnode = xmlNewDocFragment(get_doc(This));
2141 break;
2142 /* unsupported types */
2143 case NODE_DOCUMENT:
2144 case NODE_DOCUMENT_TYPE:
2145 case NODE_ENTITY:
2146 case NODE_NOTATION:
2147 heap_free(xml_name);
2148 return E_INVALIDARG;
2149 default:
2150 FIXME("unhandled node type %d\n", node_type);
2151 xmlnode = NULL;
2152 break;
2155 *node = create_node(xmlnode);
2156 heap_free(xml_name);
2157 heap_free(href);
2159 if(*node)
2161 TRACE("created node (%d, %p, %p)\n", node_type, *node, xmlnode);
2162 xmldoc_add_orphan(xmlnode->doc, xmlnode);
2163 return S_OK;
2166 return E_FAIL;
2169 static HRESULT WINAPI domdoc_nodeFromID(
2170 IXMLDOMDocument3 *iface,
2171 BSTR idString,
2172 IXMLDOMNode** node )
2174 domdoc *This = impl_from_IXMLDOMDocument3(iface);
2175 FIXME("(%p)->(%s %p)\n", This, debugstr_w(idString), node);
2176 return E_NOTIMPL;
2179 static HRESULT domdoc_onDataAvailable(void *obj, char *ptr, DWORD len)
2181 domdoc *This = obj;
2182 xmlDocPtr xmldoc;
2184 xmldoc = doparse(This, ptr, len, XML_CHAR_ENCODING_NONE);
2185 if(xmldoc) {
2186 xmldoc->_private = create_priv();
2187 return attach_xmldoc(This, xmldoc);
2190 return E_FAIL;
2193 static HRESULT domdoc_load_moniker(domdoc *This, IMoniker *mon)
2195 bsc_t *bsc;
2196 HRESULT hr;
2198 hr = bind_url(mon, domdoc_onDataAvailable, This, &bsc);
2199 if(FAILED(hr))
2200 return hr;
2202 return detach_bsc(bsc);
2205 static HRESULT WINAPI domdoc_load(
2206 IXMLDOMDocument3 *iface,
2207 VARIANT source,
2208 VARIANT_BOOL* isSuccessful )
2210 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2211 LPWSTR filename = NULL;
2212 HRESULT hr = S_FALSE;
2213 xmlDocPtr xmldoc;
2215 TRACE("(%p)->(%s)\n", This, debugstr_variant(&source));
2217 if (!isSuccessful)
2218 return E_POINTER;
2219 *isSuccessful = VARIANT_FALSE;
2221 assert( &This->node );
2223 switch( V_VT(&source) )
2225 case VT_BSTR:
2226 filename = V_BSTR(&source);
2227 break;
2228 case VT_BSTR|VT_BYREF:
2229 if (!V_BSTRREF(&source)) return E_INVALIDARG;
2230 filename = *V_BSTRREF(&source);
2231 break;
2232 case VT_ARRAY|VT_UI1:
2234 SAFEARRAY *psa = V_ARRAY(&source);
2235 char *str;
2236 LONG len;
2237 UINT dim = SafeArrayGetDim(psa);
2239 switch (dim)
2241 case 0:
2242 ERR("SAFEARRAY == NULL\n");
2243 hr = This->error = E_INVALIDARG;
2244 break;
2245 case 1:
2246 /* Only takes UTF-8 strings.
2247 * NOT NULL-terminated. */
2248 hr = SafeArrayAccessData(psa, (void**)&str);
2249 if (FAILED(hr))
2251 This->error = hr;
2252 WARN("failed to access array data, 0x%08x\n", hr);
2253 break;
2255 SafeArrayGetUBound(psa, 1, &len);
2257 if ((xmldoc = doparse(This, str, ++len, XML_CHAR_ENCODING_UTF8)))
2259 hr = This->error = S_OK;
2260 *isSuccessful = VARIANT_TRUE;
2261 TRACE("parsed document %p\n", xmldoc);
2263 else
2265 This->error = E_FAIL;
2266 TRACE("failed to parse document\n");
2269 SafeArrayUnaccessData(psa);
2271 if(xmldoc)
2273 xmldoc->_private = create_priv();
2274 return attach_xmldoc(This, xmldoc);
2276 break;
2277 default:
2278 FIXME("unhandled SAFEARRAY dim: %d\n", dim);
2279 hr = This->error = E_NOTIMPL;
2282 break;
2283 case VT_UNKNOWN:
2285 ISequentialStream *stream = NULL;
2286 IXMLDOMDocument3 *newdoc = NULL;
2288 if (!V_UNKNOWN(&source)) return E_INVALIDARG;
2290 hr = IUnknown_QueryInterface(V_UNKNOWN(&source), &IID_IXMLDOMDocument3, (void**)&newdoc);
2291 if(hr == S_OK)
2293 if(newdoc)
2295 domdoc *newDoc = impl_from_IXMLDOMDocument3( newdoc );
2297 xmldoc = xmlCopyDoc(get_doc(newDoc), 1);
2298 xmldoc->_private = create_priv();
2299 hr = attach_xmldoc(This, xmldoc);
2301 if(SUCCEEDED(hr))
2302 *isSuccessful = VARIANT_TRUE;
2304 return hr;
2308 hr = IUnknown_QueryInterface(V_UNKNOWN(&source), &IID_IStream, (void**)&stream);
2309 if (FAILED(hr))
2310 hr = IUnknown_QueryInterface(V_UNKNOWN(&source), &IID_ISequentialStream, (void**)&stream);
2312 if (hr == S_OK)
2314 hr = This->error = domdoc_load_from_stream(This, stream);
2315 if (hr == S_OK)
2316 *isSuccessful = VARIANT_TRUE;
2317 ISequentialStream_Release(stream);
2318 return hr;
2321 FIXME("unsupported IUnknown type (0x%08x) (%p)\n", hr, V_UNKNOWN(&source)->lpVtbl);
2322 break;
2324 default:
2325 FIXME("VT type not supported (%d)\n", V_VT(&source));
2328 if ( filename )
2330 IUri *uri = NULL;
2331 IMoniker *mon;
2333 if (This->properties->uri)
2335 IUri_Release(This->properties->uri);
2336 This->properties->uri = NULL;
2339 hr = create_uri(This->base_uri, filename, &uri);
2340 if (SUCCEEDED(hr))
2341 hr = CreateURLMonikerEx2(NULL, uri, &mon, 0);
2342 if ( SUCCEEDED(hr) )
2344 hr = domdoc_load_moniker( This, mon );
2345 IMoniker_Release(mon);
2348 if (SUCCEEDED(hr))
2350 get_doc(This)->name = (char *)xmlchar_from_wcharn(filename, -1, TRUE);
2351 This->properties->uri = uri;
2352 hr = This->error = S_OK;
2353 *isSuccessful = VARIANT_TRUE;
2355 else
2357 if (uri)
2358 IUri_Release(uri);
2359 This->error = E_FAIL;
2363 if(!filename || FAILED(hr)) {
2364 xmldoc = xmlNewDoc(NULL);
2365 xmldoc->_private = create_priv();
2366 hr = attach_xmldoc(This, xmldoc);
2367 if(SUCCEEDED(hr))
2368 hr = S_FALSE;
2371 TRACE("ret (%d)\n", hr);
2373 return hr;
2377 static HRESULT WINAPI domdoc_get_readyState(
2378 IXMLDOMDocument3 *iface,
2379 LONG *value )
2381 domdoc *This = impl_from_IXMLDOMDocument3(iface);
2382 FIXME("stub! (%p)->(%p)\n", This, value);
2384 if (!value)
2385 return E_INVALIDARG;
2387 *value = READYSTATE_COMPLETE;
2388 return S_OK;
2392 static HRESULT WINAPI domdoc_get_parseError(
2393 IXMLDOMDocument3 *iface,
2394 IXMLDOMParseError** errorObj )
2396 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2397 static const WCHAR err[] = {'e','r','r','o','r',0};
2398 BSTR error_string = NULL;
2400 FIXME("(%p)->(%p): creating a dummy parseError\n", iface, errorObj);
2402 if(This->error)
2403 error_string = SysAllocString(err);
2405 *errorObj = create_parseError(This->error, NULL, error_string, NULL, 0, 0, 0);
2406 if(!*errorObj) return E_OUTOFMEMORY;
2407 return S_OK;
2411 static HRESULT WINAPI domdoc_get_url(
2412 IXMLDOMDocument3 *iface,
2413 BSTR* url )
2415 domdoc *This = impl_from_IXMLDOMDocument3(iface);
2417 TRACE("(%p)->(%p)\n", This, url);
2419 if (!url)
2420 return E_INVALIDARG;
2422 if (!This->properties->uri)
2423 return return_null_bstr(url);
2425 return IUri_GetPropertyBSTR(This->properties->uri, Uri_PROPERTY_DISPLAY_URI, url, 0);
2429 static HRESULT WINAPI domdoc_get_async(
2430 IXMLDOMDocument3 *iface,
2431 VARIANT_BOOL* isAsync )
2433 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2435 TRACE("(%p)->(%p: %d)\n", This, isAsync, This->async);
2436 *isAsync = This->async;
2437 return S_OK;
2441 static HRESULT WINAPI domdoc_put_async(
2442 IXMLDOMDocument3 *iface,
2443 VARIANT_BOOL isAsync )
2445 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2447 TRACE("(%p)->(%d)\n", This, isAsync);
2448 This->async = isAsync;
2449 return S_OK;
2453 static HRESULT WINAPI domdoc_abort(
2454 IXMLDOMDocument3 *iface )
2456 domdoc *This = impl_from_IXMLDOMDocument3(iface);
2457 FIXME("%p\n", This);
2458 return E_NOTIMPL;
2461 /* don't rely on data to be in BSTR format, treat it as WCHAR string */
2462 static HRESULT WINAPI domdoc_loadXML(
2463 IXMLDOMDocument3 *iface,
2464 BSTR data,
2465 VARIANT_BOOL* isSuccessful )
2467 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2468 xmlDocPtr xmldoc = NULL;
2469 HRESULT hr = S_FALSE, hr2;
2471 TRACE("(%p)->(%s %p)\n", This, debugstr_w(data), isSuccessful );
2473 assert ( &This->node );
2475 if ( isSuccessful )
2477 *isSuccessful = VARIANT_FALSE;
2479 if (data)
2481 WCHAR *ptr = data;
2483 /* skip leading spaces if needed */
2484 if (This->properties->version == MSXML_DEFAULT || This->properties->version == MSXML26)
2485 while (*ptr && iswspace(*ptr)) ptr++;
2487 xmldoc = doparse(This, (char*)ptr, lstrlenW(ptr)*sizeof(WCHAR), XML_CHAR_ENCODING_UTF16LE);
2488 if ( !xmldoc )
2490 This->error = E_FAIL;
2491 TRACE("failed to parse document\n");
2493 else
2495 hr = This->error = S_OK;
2496 *isSuccessful = VARIANT_TRUE;
2497 TRACE("parsed document %p\n", xmldoc);
2502 if(!xmldoc)
2503 xmldoc = xmlNewDoc(NULL);
2504 xmldoc->_private = create_priv();
2505 hr2 = attach_xmldoc(This, xmldoc);
2506 if( FAILED(hr2) )
2507 hr = hr2;
2509 return hr;
2512 static int XMLCALL domdoc_save_writecallback(void *ctx, const char *buffer, int len)
2514 DWORD written = -1;
2516 if(!WriteFile(ctx, buffer, len, &written, NULL))
2518 WARN("write error\n");
2519 return -1;
2521 else
2522 return written;
2525 static int XMLCALL domdoc_save_closecallback(void *ctx)
2527 return CloseHandle(ctx) ? 0 : -1;
2530 static int XMLCALL domdoc_stream_save_writecallback(void *ctx, const char *buffer, int len)
2532 ULONG written = 0;
2533 HRESULT hr;
2535 hr = IStream_Write((IStream*)ctx, buffer, len, &written);
2536 TRACE("0x%08x %p %d %u\n", hr, buffer, len, written);
2537 if (hr != S_OK)
2539 WARN("stream write error: 0x%08x\n", hr);
2540 return -1;
2542 else
2543 return len;
2546 static int XMLCALL domdoc_stream_save_closecallback(void *ctx)
2548 IStream_Release((IStream*)ctx);
2549 return 0;
2552 static char *xmldoc_encoding(IXMLDOMDocument3 *doc)
2554 HRESULT hr;
2555 IXMLDOMNode *node;
2556 char *encoding = NULL;
2558 hr = IXMLDOMDocument3_get_firstChild(doc, &node);
2559 if (hr == S_OK)
2561 DOMNodeType type;
2563 hr = IXMLDOMNode_get_nodeType(node, &type);
2564 if (hr == S_OK && type == NODE_PROCESSING_INSTRUCTION)
2566 IXMLDOMProcessingInstruction *pi;
2567 IXMLDOMNode *item;
2568 IXMLDOMNamedNodeMap *node_map;
2570 hr = IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMProcessingInstruction, (void **)&pi);
2571 if (hr == S_OK)
2573 hr = IXMLDOMNode_get_attributes(node, &node_map);
2574 if (hr == S_OK)
2576 static const WCHAR encodingW[] = {'e','n','c','o','d','i','n','g',0};
2577 BSTR bstr;
2579 bstr = SysAllocString(encodingW);
2580 hr = IXMLDOMNamedNodeMap_getNamedItem(node_map, bstr, &item);
2581 SysFreeString(bstr);
2582 if (hr == S_OK)
2584 VARIANT var;
2586 hr = IXMLDOMNode_get_nodeValue(item, &var);
2587 if (hr == S_OK)
2589 if (V_VT(&var) == VT_BSTR)
2590 encoding = (char *)xmlchar_from_wchar(V_BSTR(&var));
2592 VariantClear(&var);
2596 IXMLDOMNamedNodeMap_Release(node_map);
2599 IXMLDOMProcessingInstruction_Release(pi);
2603 IXMLDOMNode_Release(node);
2606 return encoding;
2609 static HRESULT WINAPI domdoc_save(
2610 IXMLDOMDocument3 *iface,
2611 VARIANT destination )
2613 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2614 xmlSaveCtxtPtr ctx = NULL;
2615 HRESULT ret = S_OK;
2617 TRACE("(%p)->(%s)\n", This, debugstr_variant(&destination));
2619 switch (V_VT(&destination))
2621 case VT_UNKNOWN:
2623 IUnknown *pUnk = V_UNKNOWN(&destination);
2624 IXMLDOMDocument3 *document;
2625 IStream *stream;
2627 ret = IUnknown_QueryInterface(pUnk, &IID_IXMLDOMDocument3, (void**)&document);
2628 if(ret == S_OK)
2630 VARIANT_BOOL success;
2631 BSTR xml;
2633 ret = IXMLDOMDocument3_get_xml(iface, &xml);
2634 if(ret == S_OK)
2636 ret = IXMLDOMDocument3_loadXML(document, xml, &success);
2637 SysFreeString(xml);
2640 IXMLDOMDocument3_Release(document);
2641 return ret;
2644 ret = IUnknown_QueryInterface(pUnk, &IID_IStream, (void**)&stream);
2645 if(ret == S_OK)
2647 char *encoding = xmldoc_encoding(iface);
2649 TRACE("using encoding %s\n", encoding ? debugstr_a(encoding) : "default");
2650 ctx = xmlSaveToIO(domdoc_stream_save_writecallback,
2651 domdoc_stream_save_closecallback, stream, encoding, XML_SAVE_NO_DECL);
2652 heap_free(encoding);
2654 if(!ctx)
2656 IStream_Release(stream);
2657 return E_FAIL;
2661 break;
2663 case VT_BSTR:
2664 case VT_BSTR | VT_BYREF:
2666 char *encoding;
2667 /* save with file path */
2668 HANDLE handle = CreateFileW( (V_VT(&destination) & VT_BYREF)? *V_BSTRREF(&destination) : V_BSTR(&destination),
2669 GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL );
2670 if( handle == INVALID_HANDLE_VALUE )
2672 WARN("failed to create file\n");
2673 return E_FAIL;
2676 encoding = xmldoc_encoding(iface);
2677 TRACE("using encoding %s\n", encoding ? debugstr_a(encoding) : "default");
2678 ctx = xmlSaveToIO(domdoc_save_writecallback, domdoc_save_closecallback,
2679 handle, encoding, XML_SAVE_NO_DECL);
2680 heap_free(encoding);
2682 if (!ctx)
2684 CloseHandle(handle);
2685 return E_FAIL;
2688 break;
2690 default:
2691 FIXME("Unhandled VARIANT: %s\n", debugstr_variant(&destination));
2692 return S_FALSE;
2695 if (xmlSaveDoc(ctx, get_doc(This)) == -1) ret = S_FALSE;
2697 /* will release resources through close callback */
2698 xmlSaveClose(ctx);
2700 return ret;
2703 static HRESULT WINAPI domdoc_get_validateOnParse(
2704 IXMLDOMDocument3 *iface,
2705 VARIANT_BOOL* isValidating )
2707 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2708 TRACE("(%p)->(%p: %d)\n", This, isValidating, This->validating);
2709 *isValidating = This->validating;
2710 return S_OK;
2714 static HRESULT WINAPI domdoc_put_validateOnParse(
2715 IXMLDOMDocument3 *iface,
2716 VARIANT_BOOL isValidating )
2718 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2719 TRACE("(%p)->(%d)\n", This, isValidating);
2720 This->validating = isValidating;
2721 return S_OK;
2725 static HRESULT WINAPI domdoc_get_resolveExternals(
2726 IXMLDOMDocument3 *iface,
2727 VARIANT_BOOL* isResolving )
2729 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2730 TRACE("(%p)->(%p: %d)\n", This, isResolving, This->resolving);
2731 *isResolving = This->resolving;
2732 return S_OK;
2736 static HRESULT WINAPI domdoc_put_resolveExternals(
2737 IXMLDOMDocument3 *iface,
2738 VARIANT_BOOL isResolving )
2740 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2741 TRACE("(%p)->(%d)\n", This, isResolving);
2742 This->resolving = isResolving;
2743 return S_OK;
2747 static HRESULT WINAPI domdoc_get_preserveWhiteSpace(
2748 IXMLDOMDocument3 *iface,
2749 VARIANT_BOOL* isPreserving )
2751 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2752 TRACE("(%p)->(%p: %d)\n", This, isPreserving, This->properties->preserving);
2753 *isPreserving = This->properties->preserving;
2754 return S_OK;
2758 static HRESULT WINAPI domdoc_put_preserveWhiteSpace(
2759 IXMLDOMDocument3 *iface,
2760 VARIANT_BOOL isPreserving )
2762 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2763 TRACE("(%p)->(%d)\n", This, isPreserving);
2764 This->properties->preserving = isPreserving;
2765 return S_OK;
2769 static HRESULT WINAPI domdoc_put_onreadystatechange(
2770 IXMLDOMDocument3 *iface,
2771 VARIANT event )
2773 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2775 TRACE("(%p)->(%s)\n", This, debugstr_variant(&event));
2776 return set_doc_event(This, EVENTID_READYSTATECHANGE, &event);
2780 static HRESULT WINAPI domdoc_put_onDataAvailable(IXMLDOMDocument3 *iface, VARIANT sink)
2782 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2783 FIXME("(%p)->(%s): stub\n", This, debugstr_variant(&sink));
2784 return E_NOTIMPL;
2787 static HRESULT WINAPI domdoc_put_onTransformNode(IXMLDOMDocument3 *iface, VARIANT sink )
2789 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2790 FIXME("(%p)->(%s): stub\n", This, debugstr_variant(&sink));
2791 return E_NOTIMPL;
2794 static HRESULT WINAPI domdoc_get_namespaces(
2795 IXMLDOMDocument3* iface,
2796 IXMLDOMSchemaCollection** collection )
2798 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2799 HRESULT hr;
2801 FIXME("(%p)->(%p): semi-stub\n", This, collection);
2803 if (!collection) return E_POINTER;
2805 if (!This->namespaces)
2807 hr = SchemaCache_create(This->properties->version, (void**)&This->namespaces);
2808 if (hr != S_OK) return hr;
2810 hr = cache_from_doc_ns(This->namespaces, &This->node);
2811 if (hr != S_OK)
2812 release_namespaces(This);
2815 if (This->namespaces)
2816 return IXMLDOMSchemaCollection2_QueryInterface(This->namespaces,
2817 &IID_IXMLDOMSchemaCollection, (void**)collection);
2819 return hr;
2822 static HRESULT WINAPI domdoc_get_schemas(
2823 IXMLDOMDocument3* iface,
2824 VARIANT* schema )
2826 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2827 IXMLDOMSchemaCollection2* cur_schema = This->properties->schemaCache;
2828 HRESULT hr = S_FALSE;
2830 TRACE("(%p)->(%p)\n", This, schema);
2832 V_VT(schema) = VT_NULL;
2833 /* just to reset pointer part, cause that's what application is expected to use */
2834 V_DISPATCH(schema) = NULL;
2836 if(cur_schema)
2838 hr = IXMLDOMSchemaCollection2_QueryInterface(cur_schema, &IID_IDispatch, (void**)&V_DISPATCH(schema));
2839 if(SUCCEEDED(hr))
2840 V_VT(schema) = VT_DISPATCH;
2842 return hr;
2845 static HRESULT WINAPI domdoc_putref_schemas(
2846 IXMLDOMDocument3* iface,
2847 VARIANT schema)
2849 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2850 HRESULT hr = E_FAIL;
2851 IXMLDOMSchemaCollection2* new_schema = NULL;
2853 FIXME("(%p)->(%s): semi-stub\n", This, debugstr_variant(&schema));
2854 switch(V_VT(&schema))
2856 case VT_UNKNOWN:
2857 if (V_UNKNOWN(&schema))
2859 hr = IUnknown_QueryInterface(V_UNKNOWN(&schema), &IID_IXMLDOMSchemaCollection, (void**)&new_schema);
2860 break;
2862 /* fallthrough */
2863 case VT_DISPATCH:
2864 if (V_DISPATCH(&schema))
2866 hr = IDispatch_QueryInterface(V_DISPATCH(&schema), &IID_IXMLDOMSchemaCollection, (void**)&new_schema);
2867 break;
2869 /* fallthrough */
2870 case VT_NULL:
2871 case VT_EMPTY:
2872 hr = S_OK;
2873 break;
2875 default:
2876 WARN("Can't get schema from vt %x\n", V_VT(&schema));
2879 if(SUCCEEDED(hr))
2881 IXMLDOMSchemaCollection2* old_schema = InterlockedExchangePointer((void**)&This->properties->schemaCache, new_schema);
2882 if(old_schema) IXMLDOMSchemaCollection2_Release(old_schema);
2885 return hr;
2888 static inline BOOL is_wellformed(xmlDocPtr doc)
2890 return doc->properties & XML_DOC_WELLFORMED;
2893 static void LIBXML2_LOG_CALLBACK validate_error(void* ctx, char const* msg, ...)
2895 va_list ap;
2896 va_start(ap, msg);
2897 LIBXML2_CALLBACK_ERR(domdoc_validateNode, msg, ap);
2898 va_end(ap);
2901 static void LIBXML2_LOG_CALLBACK validate_warning(void* ctx, char const* msg, ...)
2903 va_list ap;
2904 va_start(ap, msg);
2905 LIBXML2_CALLBACK_WARN(domdoc_validateNode, msg, ap);
2906 va_end(ap);
2909 static HRESULT WINAPI domdoc_validateNode(
2910 IXMLDOMDocument3* iface,
2911 IXMLDOMNode* node,
2912 IXMLDOMParseError** err)
2914 domdoc* This = impl_from_IXMLDOMDocument3(iface);
2915 LONG state, err_code = 0;
2916 HRESULT hr = S_OK;
2917 int validated = 0;
2919 TRACE("(%p)->(%p, %p)\n", This, node, err);
2920 IXMLDOMDocument3_get_readyState(iface, &state);
2921 if (state != READYSTATE_COMPLETE)
2923 if (err)
2924 *err = create_parseError(err_code, NULL, NULL, NULL, 0, 0, 0);
2925 return E_PENDING;
2928 if (!node)
2930 if (err)
2931 *err = create_parseError(err_code, NULL, NULL, NULL, 0, 0, 0);
2932 return E_POINTER;
2935 if (!get_node_obj(node)->node || get_node_obj(node)->node->doc != get_doc(This))
2937 if (err)
2938 *err = create_parseError(err_code, NULL, NULL, NULL, 0, 0, 0);
2939 return E_FAIL;
2942 if (!is_wellformed(get_doc(This)))
2944 ERR("doc not well-formed\n");
2945 if (err)
2946 *err = create_parseError(E_XML_NOTWF, NULL, NULL, NULL, 0, 0, 0);
2947 return S_FALSE;
2950 /* DTD validation */
2951 if (get_doc(This)->intSubset || get_doc(This)->extSubset)
2953 xmlValidCtxtPtr vctx = xmlNewValidCtxt();
2954 vctx->error = validate_error;
2955 vctx->warning = validate_warning;
2956 ++validated;
2958 if (!((node == (IXMLDOMNode*)iface)?
2959 xmlValidateDocument(vctx, get_doc(This)) :
2960 xmlValidateElement(vctx, get_doc(This), get_node_obj(node)->node)))
2962 /* TODO: get a real error code here */
2963 TRACE("DTD validation failed\n");
2964 err_code = E_XML_INVALID;
2965 hr = S_FALSE;
2967 xmlFreeValidCtxt(vctx);
2970 /* Schema validation */
2971 if (hr == S_OK && This->properties->schemaCache != NULL)
2974 hr = SchemaCache_validate_tree(This->properties->schemaCache, get_node_obj(node)->node);
2975 if (SUCCEEDED(hr))
2977 ++validated;
2978 /* TODO: get a real error code here */
2979 if (hr == S_OK)
2981 TRACE("schema validation succeeded\n");
2983 else
2985 ERR("schema validation failed\n");
2986 err_code = E_XML_INVALID;
2989 else
2991 /* not really OK, just didn't find a schema for the ns */
2992 hr = S_OK;
2996 if (!validated)
2998 ERR("no DTD or schema found\n");
2999 err_code = E_XML_NODTD;
3000 hr = S_FALSE;
3003 if (err)
3004 *err = create_parseError(err_code, NULL, NULL, NULL, 0, 0, 0);
3006 return hr;
3009 static HRESULT WINAPI domdoc_validate(
3010 IXMLDOMDocument3* iface,
3011 IXMLDOMParseError** err)
3013 domdoc *This = impl_from_IXMLDOMDocument3( iface );
3014 TRACE("(%p)->(%p)\n", This, err);
3015 return IXMLDOMDocument3_validateNode(iface, (IXMLDOMNode*)iface, err);
3018 static HRESULT WINAPI domdoc_setProperty(
3019 IXMLDOMDocument3* iface,
3020 BSTR p,
3021 VARIANT value)
3023 domdoc *This = impl_from_IXMLDOMDocument3( iface );
3025 TRACE("(%p)->(%s %s)\n", This, debugstr_w(p), debugstr_variant(&value));
3027 if (lstrcmpiW(p, PropertySelectionLanguageW) == 0)
3029 VARIANT varStr;
3030 HRESULT hr;
3031 BSTR bstr;
3033 V_VT(&varStr) = VT_EMPTY;
3034 if (V_VT(&value) != VT_BSTR)
3036 if (FAILED(hr = VariantChangeType(&varStr, &value, 0, VT_BSTR)))
3037 return hr;
3038 bstr = V_BSTR(&varStr);
3040 else
3041 bstr = V_BSTR(&value);
3043 hr = S_OK;
3044 if (lstrcmpiW(bstr, PropValueXPathW) == 0)
3045 This->properties->XPath = TRUE;
3046 else if (lstrcmpiW(bstr, PropValueXSLPatternW) == 0)
3047 This->properties->XPath = FALSE;
3048 else
3049 hr = E_FAIL;
3051 VariantClear(&varStr);
3052 return hr;
3054 else if (lstrcmpiW(p, PropertySelectionNamespacesW) == 0)
3056 xmlChar *nsStr = (xmlChar*)This->properties->selectNsStr;
3057 struct list *pNsList;
3058 VARIANT varStr;
3059 HRESULT hr;
3060 BSTR bstr;
3062 V_VT(&varStr) = VT_EMPTY;
3063 if (V_VT(&value) != VT_BSTR)
3065 if (FAILED(hr = VariantChangeType(&varStr, &value, 0, VT_BSTR)))
3066 return hr;
3067 bstr = V_BSTR(&varStr);
3069 else
3070 bstr = V_BSTR(&value);
3072 hr = S_OK;
3074 pNsList = &(This->properties->selectNsList);
3075 clear_selectNsList(pNsList);
3076 heap_free(nsStr);
3077 nsStr = xmlchar_from_wchar(bstr);
3079 TRACE("property value: \"%s\"\n", debugstr_w(bstr));
3081 This->properties->selectNsStr = nsStr;
3082 This->properties->selectNsStr_len = xmlStrlen(nsStr);
3083 if (bstr && *bstr)
3085 xmlChar *pTokBegin, *pTokEnd, *pTokInner;
3086 select_ns_entry* ns_entry = NULL;
3087 xmlXPathContextPtr ctx;
3089 ctx = xmlXPathNewContext(This->node.node->doc);
3090 pTokBegin = nsStr;
3092 /* skip leading spaces */
3093 while (*pTokBegin == ' ' || *pTokBegin == '\n' ||
3094 *pTokBegin == '\t' || *pTokBegin == '\r')
3095 ++pTokBegin;
3097 for (; *pTokBegin; pTokBegin = pTokEnd)
3099 if (ns_entry)
3100 memset(ns_entry, 0, sizeof(select_ns_entry));
3101 else
3102 ns_entry = heap_alloc_zero(sizeof(select_ns_entry));
3104 while (*pTokBegin == ' ')
3105 ++pTokBegin;
3106 pTokEnd = pTokBegin;
3107 while (*pTokEnd != ' ' && *pTokEnd != 0)
3108 ++pTokEnd;
3110 /* so it failed to advance which means we've got some trailing spaces */
3111 if (pTokEnd == pTokBegin) break;
3113 if (xmlStrncmp(pTokBegin, (xmlChar const*)"xmlns", 5) != 0)
3115 hr = E_FAIL;
3116 WARN("Syntax error in xmlns string: %s\n\tat token: %s\n",
3117 debugstr_w(bstr), debugstr_an((const char*)pTokBegin, pTokEnd-pTokBegin));
3118 continue;
3121 pTokBegin += 5;
3122 if (*pTokBegin == '=')
3124 /*valid for XSLPattern?*/
3125 FIXME("Setting default xmlns not supported - skipping.\n");
3126 continue;
3128 else if (*pTokBegin == ':')
3130 ns_entry->prefix = ++pTokBegin;
3131 for (pTokInner = pTokBegin; pTokInner != pTokEnd && *pTokInner != '='; ++pTokInner)
3134 if (pTokInner == pTokEnd)
3136 hr = E_FAIL;
3137 WARN("Syntax error in xmlns string: %s\n\tat token: %s\n",
3138 debugstr_w(bstr), debugstr_an((const char*)pTokBegin, pTokEnd-pTokBegin));
3139 continue;
3142 ns_entry->prefix_end = *pTokInner;
3143 *pTokInner = 0;
3144 ++pTokInner;
3146 if (pTokEnd-pTokInner > 1 &&
3147 ((*pTokInner == '\'' && *(pTokEnd-1) == '\'') ||
3148 (*pTokInner == '"' && *(pTokEnd-1) == '"')))
3150 ns_entry->href = ++pTokInner;
3151 ns_entry->href_end = *(pTokEnd-1);
3152 *(pTokEnd-1) = 0;
3153 list_add_tail(pNsList, &ns_entry->entry);
3154 /*let libxml figure out if they're valid from here ;)*/
3155 if (xmlXPathRegisterNs(ctx, ns_entry->prefix, ns_entry->href) != 0)
3157 hr = E_FAIL;
3159 ns_entry = NULL;
3160 continue;
3162 else
3164 WARN("Syntax error in xmlns string: %s\n\tat token: %s\n",
3165 debugstr_w(bstr), debugstr_an((const char*)pTokInner, pTokEnd-pTokInner));
3166 list_add_tail(pNsList, &ns_entry->entry);
3168 ns_entry = NULL;
3169 hr = E_FAIL;
3170 continue;
3173 else
3175 hr = E_FAIL;
3176 continue;
3179 heap_free(ns_entry);
3180 xmlXPathFreeContext(ctx);
3183 VariantClear(&varStr);
3184 return hr;
3186 else if (lstrcmpiW(p, PropertyProhibitDTDW) == 0 ||
3187 lstrcmpiW(p, PropertyNewParserW) == 0 ||
3188 lstrcmpiW(p, PropertyResolveExternalsW) == 0 ||
3189 lstrcmpiW(p, PropertyAllowXsltScriptW) == 0 ||
3190 lstrcmpiW(p, PropertyNormalizeAttributeValuesW) == 0 ||
3191 lstrcmpiW(p, PropertyAllowDocumentFunctionW) == 0)
3193 /* Ignore */
3194 FIXME("Ignoring property %s, value %s\n", debugstr_w(p), debugstr_variant(&value));
3195 return S_OK;
3198 FIXME("Unknown property %s\n", debugstr_w(p));
3199 return E_FAIL;
3202 static HRESULT WINAPI domdoc_getProperty(
3203 IXMLDOMDocument3* iface,
3204 BSTR p,
3205 VARIANT* var)
3207 domdoc *This = impl_from_IXMLDOMDocument3( iface );
3209 TRACE("(%p)->(%s)\n", This, debugstr_w(p));
3211 if (!var)
3212 return E_INVALIDARG;
3214 if (lstrcmpiW(p, PropertySelectionLanguageW) == 0)
3216 V_VT(var) = VT_BSTR;
3217 V_BSTR(var) = This->properties->XPath ?
3218 SysAllocString(PropValueXPathW) :
3219 SysAllocString(PropValueXSLPatternW);
3220 return V_BSTR(var) ? S_OK : E_OUTOFMEMORY;
3222 else if (lstrcmpiW(p, PropertySelectionNamespacesW) == 0)
3224 int lenA, lenW;
3225 BSTR rebuiltStr, cur;
3226 const xmlChar *nsStr;
3227 struct list *pNsList;
3228 select_ns_entry* pNsEntry;
3230 V_VT(var) = VT_BSTR;
3231 nsStr = This->properties->selectNsStr;
3232 pNsList = &This->properties->selectNsList;
3233 lenA = This->properties->selectNsStr_len;
3234 lenW = MultiByteToWideChar(CP_UTF8, 0, (LPCSTR)nsStr, lenA+1, NULL, 0);
3235 rebuiltStr = heap_alloc(lenW*sizeof(WCHAR));
3236 MultiByteToWideChar(CP_UTF8, 0, (LPCSTR)nsStr, lenA+1, rebuiltStr, lenW);
3237 cur = rebuiltStr;
3238 /* this is fine because all of the chars that end tokens are ASCII*/
3239 LIST_FOR_EACH_ENTRY(pNsEntry, pNsList, select_ns_entry, entry)
3241 while (*cur != 0) ++cur;
3242 if (pNsEntry->prefix_end)
3244 *cur = pNsEntry->prefix_end;
3245 while (*cur != 0) ++cur;
3248 if (pNsEntry->href_end)
3250 *cur = pNsEntry->href_end;
3253 V_BSTR(var) = SysAllocString(rebuiltStr);
3254 heap_free(rebuiltStr);
3255 return S_OK;
3258 FIXME("Unknown property %s\n", debugstr_w(p));
3259 return E_FAIL;
3262 static HRESULT WINAPI domdoc_importNode(
3263 IXMLDOMDocument3* iface,
3264 IXMLDOMNode* node,
3265 VARIANT_BOOL deep,
3266 IXMLDOMNode** clone)
3268 domdoc *This = impl_from_IXMLDOMDocument3( iface );
3269 FIXME("(%p)->(%p %d %p): stub\n", This, node, deep, clone);
3270 return E_NOTIMPL;
3273 static const struct IXMLDOMDocument3Vtbl XMLDOMDocument3Vtbl =
3275 domdoc_QueryInterface,
3276 domdoc_AddRef,
3277 domdoc_Release,
3278 domdoc_GetTypeInfoCount,
3279 domdoc_GetTypeInfo,
3280 domdoc_GetIDsOfNames,
3281 domdoc_Invoke,
3282 domdoc_get_nodeName,
3283 domdoc_get_nodeValue,
3284 domdoc_put_nodeValue,
3285 domdoc_get_nodeType,
3286 domdoc_get_parentNode,
3287 domdoc_get_childNodes,
3288 domdoc_get_firstChild,
3289 domdoc_get_lastChild,
3290 domdoc_get_previousSibling,
3291 domdoc_get_nextSibling,
3292 domdoc_get_attributes,
3293 domdoc_insertBefore,
3294 domdoc_replaceChild,
3295 domdoc_removeChild,
3296 domdoc_appendChild,
3297 domdoc_hasChildNodes,
3298 domdoc_get_ownerDocument,
3299 domdoc_cloneNode,
3300 domdoc_get_nodeTypeString,
3301 domdoc_get_text,
3302 domdoc_put_text,
3303 domdoc_get_specified,
3304 domdoc_get_definition,
3305 domdoc_get_nodeTypedValue,
3306 domdoc_put_nodeTypedValue,
3307 domdoc_get_dataType,
3308 domdoc_put_dataType,
3309 domdoc_get_xml,
3310 domdoc_transformNode,
3311 domdoc_selectNodes,
3312 domdoc_selectSingleNode,
3313 domdoc_get_parsed,
3314 domdoc_get_namespaceURI,
3315 domdoc_get_prefix,
3316 domdoc_get_baseName,
3317 domdoc_transformNodeToObject,
3318 domdoc_get_doctype,
3319 domdoc_get_implementation,
3320 domdoc_get_documentElement,
3321 domdoc_put_documentElement,
3322 domdoc_createElement,
3323 domdoc_createDocumentFragment,
3324 domdoc_createTextNode,
3325 domdoc_createComment,
3326 domdoc_createCDATASection,
3327 domdoc_createProcessingInstruction,
3328 domdoc_createAttribute,
3329 domdoc_createEntityReference,
3330 domdoc_getElementsByTagName,
3331 domdoc_createNode,
3332 domdoc_nodeFromID,
3333 domdoc_load,
3334 domdoc_get_readyState,
3335 domdoc_get_parseError,
3336 domdoc_get_url,
3337 domdoc_get_async,
3338 domdoc_put_async,
3339 domdoc_abort,
3340 domdoc_loadXML,
3341 domdoc_save,
3342 domdoc_get_validateOnParse,
3343 domdoc_put_validateOnParse,
3344 domdoc_get_resolveExternals,
3345 domdoc_put_resolveExternals,
3346 domdoc_get_preserveWhiteSpace,
3347 domdoc_put_preserveWhiteSpace,
3348 domdoc_put_onreadystatechange,
3349 domdoc_put_onDataAvailable,
3350 domdoc_put_onTransformNode,
3351 domdoc_get_namespaces,
3352 domdoc_get_schemas,
3353 domdoc_putref_schemas,
3354 domdoc_validate,
3355 domdoc_setProperty,
3356 domdoc_getProperty,
3357 domdoc_validateNode,
3358 domdoc_importNode
3361 /* IConnectionPointContainer */
3362 static HRESULT WINAPI ConnectionPointContainer_QueryInterface(IConnectionPointContainer *iface,
3363 REFIID riid, void **ppv)
3365 domdoc *This = impl_from_IConnectionPointContainer(iface);
3366 return IXMLDOMDocument3_QueryInterface(&This->IXMLDOMDocument3_iface, riid, ppv);
3369 static ULONG WINAPI ConnectionPointContainer_AddRef(IConnectionPointContainer *iface)
3371 domdoc *This = impl_from_IConnectionPointContainer(iface);
3372 return IXMLDOMDocument3_AddRef(&This->IXMLDOMDocument3_iface);
3375 static ULONG WINAPI ConnectionPointContainer_Release(IConnectionPointContainer *iface)
3377 domdoc *This = impl_from_IConnectionPointContainer(iface);
3378 return IXMLDOMDocument3_Release(&This->IXMLDOMDocument3_iface);
3381 static HRESULT WINAPI ConnectionPointContainer_EnumConnectionPoints(IConnectionPointContainer *iface,
3382 IEnumConnectionPoints **ppEnum)
3384 domdoc *This = impl_from_IConnectionPointContainer(iface);
3385 FIXME("(%p)->(%p): stub\n", This, ppEnum);
3386 return E_NOTIMPL;
3389 static HRESULT WINAPI ConnectionPointContainer_FindConnectionPoint(IConnectionPointContainer *iface,
3390 REFIID riid, IConnectionPoint **cp)
3392 domdoc *This = impl_from_IConnectionPointContainer(iface);
3393 ConnectionPoint *iter;
3395 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), cp);
3397 *cp = NULL;
3399 for(iter = This->cp_list; iter; iter = iter->next)
3401 if (IsEqualGUID(iter->iid, riid))
3402 *cp = &iter->IConnectionPoint_iface;
3405 if (*cp)
3407 IConnectionPoint_AddRef(*cp);
3408 return S_OK;
3411 FIXME("unsupported riid %s\n", debugstr_guid(riid));
3412 return CONNECT_E_NOCONNECTION;
3416 static const struct IConnectionPointContainerVtbl ConnectionPointContainerVtbl =
3418 ConnectionPointContainer_QueryInterface,
3419 ConnectionPointContainer_AddRef,
3420 ConnectionPointContainer_Release,
3421 ConnectionPointContainer_EnumConnectionPoints,
3422 ConnectionPointContainer_FindConnectionPoint
3425 /* IConnectionPoint */
3426 static HRESULT WINAPI ConnectionPoint_QueryInterface(IConnectionPoint *iface,
3427 REFIID riid, void **ppv)
3429 ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3431 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv );
3433 *ppv = NULL;
3435 if (IsEqualGUID(&IID_IUnknown, riid) ||
3436 IsEqualGUID(&IID_IConnectionPoint, riid))
3438 *ppv = iface;
3441 if (*ppv)
3443 IConnectionPoint_AddRef(iface);
3444 return S_OK;
3447 WARN("Unsupported interface %s\n", debugstr_guid(riid));
3448 return E_NOINTERFACE;
3451 static ULONG WINAPI ConnectionPoint_AddRef(IConnectionPoint *iface)
3453 ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3454 return IConnectionPointContainer_AddRef(This->container);
3457 static ULONG WINAPI ConnectionPoint_Release(IConnectionPoint *iface)
3459 ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3460 return IConnectionPointContainer_Release(This->container);
3463 static HRESULT WINAPI ConnectionPoint_GetConnectionInterface(IConnectionPoint *iface, IID *iid)
3465 ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3467 TRACE("(%p)->(%p)\n", This, iid);
3469 if (!iid) return E_POINTER;
3471 *iid = *This->iid;
3472 return S_OK;
3475 static HRESULT WINAPI ConnectionPoint_GetConnectionPointContainer(IConnectionPoint *iface,
3476 IConnectionPointContainer **container)
3478 ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3480 TRACE("(%p)->(%p)\n", This, container);
3482 if (!container) return E_POINTER;
3484 *container = This->container;
3485 IConnectionPointContainer_AddRef(*container);
3486 return S_OK;
3489 static HRESULT WINAPI ConnectionPoint_Advise(IConnectionPoint *iface, IUnknown *unk_sink,
3490 DWORD *cookie)
3492 ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3493 IUnknown *sink;
3494 HRESULT hr;
3495 DWORD i;
3497 TRACE("(%p)->(%p %p)\n", This, unk_sink, cookie);
3499 hr = IUnknown_QueryInterface(unk_sink, This->iid, (void**)&sink);
3500 if(FAILED(hr) && !IsEqualGUID(&IID_IPropertyNotifySink, This->iid))
3501 hr = IUnknown_QueryInterface(unk_sink, &IID_IDispatch, (void**)&sink);
3502 if(FAILED(hr))
3503 return CONNECT_E_CANNOTCONNECT;
3505 if(This->sinks)
3507 for (i = 0; i < This->sinks_size; i++)
3508 if (!This->sinks[i].unk)
3509 break;
3511 if (i == This->sinks_size)
3512 This->sinks = heap_realloc(This->sinks,(++This->sinks_size)*sizeof(*This->sinks));
3514 else
3516 This->sinks = heap_alloc(sizeof(*This->sinks));
3517 This->sinks_size = 1;
3518 i = 0;
3521 This->sinks[i].unk = sink;
3522 if (cookie)
3523 *cookie = i+1;
3525 return S_OK;
3528 static HRESULT WINAPI ConnectionPoint_Unadvise(IConnectionPoint *iface, DWORD cookie)
3530 ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3532 TRACE("(%p)->(%d)\n", This, cookie);
3534 if (cookie == 0 || cookie > This->sinks_size || !This->sinks[cookie-1].unk)
3535 return CONNECT_E_NOCONNECTION;
3537 IUnknown_Release(This->sinks[cookie-1].unk);
3538 This->sinks[cookie-1].unk = NULL;
3540 return S_OK;
3543 static HRESULT WINAPI ConnectionPoint_EnumConnections(IConnectionPoint *iface,
3544 IEnumConnections **ppEnum)
3546 ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3547 FIXME("(%p)->(%p): stub\n", This, ppEnum);
3548 return E_NOTIMPL;
3551 static const IConnectionPointVtbl ConnectionPointVtbl =
3553 ConnectionPoint_QueryInterface,
3554 ConnectionPoint_AddRef,
3555 ConnectionPoint_Release,
3556 ConnectionPoint_GetConnectionInterface,
3557 ConnectionPoint_GetConnectionPointContainer,
3558 ConnectionPoint_Advise,
3559 ConnectionPoint_Unadvise,
3560 ConnectionPoint_EnumConnections
3563 static void ConnectionPoint_Init(ConnectionPoint *cp, struct domdoc *doc, REFIID riid)
3565 cp->IConnectionPoint_iface.lpVtbl = &ConnectionPointVtbl;
3566 cp->doc = doc;
3567 cp->iid = riid;
3568 cp->sinks = NULL;
3569 cp->sinks_size = 0;
3571 cp->next = doc->cp_list;
3572 doc->cp_list = cp;
3574 cp->container = &doc->IConnectionPointContainer_iface;
3577 /* domdoc implementation of IObjectWithSite */
3578 static HRESULT WINAPI
3579 domdoc_ObjectWithSite_QueryInterface( IObjectWithSite* iface, REFIID riid, void** ppvObject )
3581 domdoc *This = impl_from_IObjectWithSite(iface);
3582 return IXMLDOMDocument3_QueryInterface(&This->IXMLDOMDocument3_iface, riid, ppvObject);
3585 static ULONG WINAPI domdoc_ObjectWithSite_AddRef( IObjectWithSite* iface )
3587 domdoc *This = impl_from_IObjectWithSite(iface);
3588 return IXMLDOMDocument3_AddRef(&This->IXMLDOMDocument3_iface);
3591 static ULONG WINAPI domdoc_ObjectWithSite_Release( IObjectWithSite* iface )
3593 domdoc *This = impl_from_IObjectWithSite(iface);
3594 return IXMLDOMDocument3_Release(&This->IXMLDOMDocument3_iface);
3597 static HRESULT WINAPI domdoc_ObjectWithSite_GetSite( IObjectWithSite *iface, REFIID iid, void **ppvSite )
3599 domdoc *This = impl_from_IObjectWithSite(iface);
3601 TRACE("(%p)->(%s %p)\n", This, debugstr_guid( iid ), ppvSite );
3603 if ( !This->site )
3604 return E_FAIL;
3606 return IUnknown_QueryInterface( This->site, iid, ppvSite );
3609 static HRESULT WINAPI domdoc_ObjectWithSite_SetSite( IObjectWithSite *iface, IUnknown *punk )
3611 domdoc *This = impl_from_IObjectWithSite(iface);
3613 TRACE("(%p)->(%p)\n", iface, punk);
3615 if(!punk)
3617 if(This->site)
3619 IUnknown_Release( This->site );
3620 This->site = NULL;
3623 if(This->base_uri)
3625 IUri_Release(This->base_uri);
3626 This->base_uri = NULL;
3629 return S_OK;
3632 IUnknown_AddRef( punk );
3634 if(This->site)
3635 IUnknown_Release( This->site );
3637 This->site = punk;
3638 This->base_uri = get_base_uri(This->site);
3640 return S_OK;
3643 static const IObjectWithSiteVtbl domdocObjectSite =
3645 domdoc_ObjectWithSite_QueryInterface,
3646 domdoc_ObjectWithSite_AddRef,
3647 domdoc_ObjectWithSite_Release,
3648 domdoc_ObjectWithSite_SetSite,
3649 domdoc_ObjectWithSite_GetSite
3652 static HRESULT WINAPI domdoc_Safety_QueryInterface(IObjectSafety *iface, REFIID riid, void **ppv)
3654 domdoc *This = impl_from_IObjectSafety(iface);
3655 return IXMLDOMDocument3_QueryInterface(&This->IXMLDOMDocument3_iface, riid, ppv);
3658 static ULONG WINAPI domdoc_Safety_AddRef(IObjectSafety *iface)
3660 domdoc *This = impl_from_IObjectSafety(iface);
3661 return IXMLDOMDocument3_AddRef(&This->IXMLDOMDocument3_iface);
3664 static ULONG WINAPI domdoc_Safety_Release(IObjectSafety *iface)
3666 domdoc *This = impl_from_IObjectSafety(iface);
3667 return IXMLDOMDocument3_Release(&This->IXMLDOMDocument3_iface);
3670 #define SAFETY_SUPPORTED_OPTIONS (INTERFACESAFE_FOR_UNTRUSTED_CALLER|INTERFACESAFE_FOR_UNTRUSTED_DATA|INTERFACE_USES_SECURITY_MANAGER)
3672 static HRESULT WINAPI domdoc_Safety_GetInterfaceSafetyOptions(IObjectSafety *iface, REFIID riid,
3673 DWORD *supported, DWORD *enabled)
3675 domdoc *This = impl_from_IObjectSafety(iface);
3677 TRACE("(%p)->(%s %p %p)\n", This, debugstr_guid(riid), supported, enabled);
3679 if(!supported || !enabled) return E_POINTER;
3681 *supported = SAFETY_SUPPORTED_OPTIONS;
3682 *enabled = This->safeopt;
3684 return S_OK;
3687 static HRESULT WINAPI domdoc_Safety_SetInterfaceSafetyOptions(IObjectSafety *iface, REFIID riid,
3688 DWORD mask, DWORD enabled)
3690 domdoc *This = impl_from_IObjectSafety(iface);
3691 TRACE("(%p)->(%s %x %x)\n", This, debugstr_guid(riid), mask, enabled);
3693 if ((mask & ~SAFETY_SUPPORTED_OPTIONS) != 0)
3694 return E_FAIL;
3696 This->safeopt = (This->safeopt & ~mask) | (mask & enabled);
3698 return S_OK;
3701 #undef SAFETY_SUPPORTED_OPTIONS
3703 static const IObjectSafetyVtbl domdocObjectSafetyVtbl = {
3704 domdoc_Safety_QueryInterface,
3705 domdoc_Safety_AddRef,
3706 domdoc_Safety_Release,
3707 domdoc_Safety_GetInterfaceSafetyOptions,
3708 domdoc_Safety_SetInterfaceSafetyOptions
3711 static const tid_t domdoc_iface_tids[] = {
3712 IXMLDOMDocument3_tid,
3716 static dispex_static_data_t domdoc_dispex = {
3717 NULL,
3718 IXMLDOMDocument3_tid,
3719 NULL,
3720 domdoc_iface_tids
3723 HRESULT get_domdoc_from_xmldoc(xmlDocPtr xmldoc, IXMLDOMDocument3 **document)
3725 domdoc *doc;
3727 doc = heap_alloc( sizeof (*doc) );
3728 if( !doc )
3729 return E_OUTOFMEMORY;
3731 doc->IXMLDOMDocument3_iface.lpVtbl = &XMLDOMDocument3Vtbl;
3732 doc->IPersistStreamInit_iface.lpVtbl = &xmldoc_IPersistStreamInit_VTable;
3733 doc->IObjectWithSite_iface.lpVtbl = &domdocObjectSite;
3734 doc->IObjectSafety_iface.lpVtbl = &domdocObjectSafetyVtbl;
3735 doc->IConnectionPointContainer_iface.lpVtbl = &ConnectionPointContainerVtbl;
3736 doc->ref = 1;
3737 doc->async = VARIANT_TRUE;
3738 doc->validating = 0;
3739 doc->resolving = 0;
3740 doc->properties = properties_add_ref(properties_from_xmlDocPtr(xmldoc));
3741 doc->error = S_OK;
3742 doc->site = NULL;
3743 doc->base_uri = NULL;
3744 doc->safeopt = 0;
3745 doc->cp_list = NULL;
3746 doc->namespaces = NULL;
3747 memset(doc->events, 0, sizeof(doc->events));
3749 /* events connection points */
3750 ConnectionPoint_Init(&doc->cp_dispatch, doc, &IID_IDispatch);
3751 ConnectionPoint_Init(&doc->cp_propnotif, doc, &IID_IPropertyNotifySink);
3752 ConnectionPoint_Init(&doc->cp_domdocevents, doc, &DIID_XMLDOMDocumentEvents);
3754 init_xmlnode(&doc->node, (xmlNodePtr)xmldoc, (IXMLDOMNode*)&doc->IXMLDOMDocument3_iface,
3755 &domdoc_dispex);
3757 *document = &doc->IXMLDOMDocument3_iface;
3759 TRACE("returning iface %p\n", *document);
3760 return S_OK;
3763 HRESULT dom_document_create(MSXML_VERSION version, void **ppObj)
3765 xmlDocPtr xmldoc;
3766 HRESULT hr;
3768 TRACE("(%d, %p)\n", version, ppObj);
3770 xmldoc = xmlNewDoc(NULL);
3771 if(!xmldoc)
3772 return E_OUTOFMEMORY;
3774 xmldoc_init(xmldoc, version);
3776 hr = get_domdoc_from_xmldoc(xmldoc, (IXMLDOMDocument3**)ppObj);
3777 if(FAILED(hr))
3779 properties_release(properties_from_xmlDocPtr(xmldoc));
3780 heap_free(xmldoc->_private);
3781 xmlFreeDoc(xmldoc);
3782 return hr;
3785 return hr;
3788 IUnknown* create_domdoc( xmlNodePtr document )
3790 IUnknown *obj = NULL;
3791 HRESULT hr;
3793 TRACE("(%p)\n", document);
3795 hr = get_domdoc_from_xmldoc((xmlDocPtr)document, (IXMLDOMDocument3**)&obj);
3796 if (FAILED(hr))
3797 return NULL;
3799 return obj;