dinput: Clear DIA_APPNOMAP BuildActionMap flag with specific device semantic.
[wine.git] / dlls / msxml3 / domdoc.c
blobf0420a517ea0dbfc9df416872d94666648fa87b0
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, %ld.\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, %ld.\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, refcount %ld.\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;
630 TRACE("%p, refcount %ld.\n", doc, ref);
632 if (ref < 0)
633 WARN("negative refcount, expect troubles\n");
635 if (ref == 0)
637 orphan_entry *orphan, *orphan2;
638 TRACE("freeing docptr %p\n", doc);
640 LIST_FOR_EACH_ENTRY_SAFE( orphan, orphan2, &priv->orphans, orphan_entry, entry )
642 xmlFreeNode( orphan->node );
643 heap_free( orphan );
645 properties_release(priv->properties);
646 heap_free(doc->_private);
648 xmlFreeDoc(doc);
651 return ref;
654 LONG xmldoc_release(xmlDocPtr doc)
656 return xmldoc_release_refs(doc, 1);
659 HRESULT xmldoc_add_orphan(xmlDocPtr doc, xmlNodePtr node)
661 xmldoc_priv *priv = priv_from_xmlDocPtr(doc);
662 orphan_entry *entry;
664 entry = heap_alloc( sizeof (*entry) );
665 if(!entry)
666 return E_OUTOFMEMORY;
668 entry->node = node;
669 list_add_head( &priv->orphans, &entry->entry );
670 return S_OK;
673 HRESULT xmldoc_remove_orphan(xmlDocPtr doc, xmlNodePtr node)
675 xmldoc_priv *priv = priv_from_xmlDocPtr(doc);
676 orphan_entry *entry, *entry2;
678 LIST_FOR_EACH_ENTRY_SAFE( entry, entry2, &priv->orphans, orphan_entry, entry )
680 if( entry->node == node )
682 list_remove( &entry->entry );
683 heap_free( entry );
684 return S_OK;
688 return S_FALSE;
691 static inline xmlDocPtr get_doc( domdoc *This )
693 return This->node.node->doc;
696 static HRESULT attach_xmldoc(domdoc *This, xmlDocPtr xml )
698 release_namespaces(This);
700 if(This->node.node)
702 properties_release(properties_from_xmlDocPtr(get_doc(This)));
703 priv_from_xmlDocPtr(get_doc(This))->properties = NULL;
704 if (xmldoc_release(get_doc(This)) != 0)
706 /* The xmlDocPtr object can no longer use the properties of this
707 * domdoc object. So give it its own copy.
709 priv_from_xmlDocPtr(get_doc(This))->properties =
710 copy_properties(This->properties);
714 This->node.node = (xmlNodePtr) xml;
716 if(This->node.node)
718 xmldoc_add_ref(get_doc(This));
719 /* Only attach new xmlDocPtr objects, i.e. ones for which properties
720 * is still NULL.
722 priv_from_xmlDocPtr(get_doc(This))->properties = properties_add_ref(This->properties);
725 return S_OK;
728 static inline domdoc *impl_from_IXMLDOMDocument3( IXMLDOMDocument3 *iface )
730 return CONTAINING_RECORD(iface, domdoc, IXMLDOMDocument3_iface);
733 static inline domdoc *impl_from_IPersistStreamInit(IPersistStreamInit *iface)
735 return CONTAINING_RECORD(iface, domdoc, IPersistStreamInit_iface);
738 static inline domdoc *impl_from_IObjectWithSite(IObjectWithSite *iface)
740 return CONTAINING_RECORD(iface, domdoc, IObjectWithSite_iface);
743 static inline domdoc *impl_from_IObjectSafety(IObjectSafety *iface)
745 return CONTAINING_RECORD(iface, domdoc, IObjectSafety_iface);
748 static inline domdoc *impl_from_IConnectionPointContainer(IConnectionPointContainer *iface)
750 return CONTAINING_RECORD(iface, domdoc, IConnectionPointContainer_iface);
753 /************************************************************************
754 * domdoc implementation of IPersistStream.
756 static HRESULT WINAPI PersistStreamInit_QueryInterface(
757 IPersistStreamInit *iface, REFIID riid, void **ppvObj)
759 domdoc* This = impl_from_IPersistStreamInit(iface);
760 return IXMLDOMDocument3_QueryInterface(&This->IXMLDOMDocument3_iface, riid, ppvObj);
763 static ULONG WINAPI PersistStreamInit_AddRef(
764 IPersistStreamInit *iface)
766 domdoc* This = impl_from_IPersistStreamInit(iface);
767 return IXMLDOMDocument3_AddRef(&This->IXMLDOMDocument3_iface);
770 static ULONG WINAPI PersistStreamInit_Release(
771 IPersistStreamInit *iface)
773 domdoc* This = impl_from_IPersistStreamInit(iface);
774 return IXMLDOMDocument3_Release(&This->IXMLDOMDocument3_iface);
777 static HRESULT WINAPI PersistStreamInit_GetClassID(
778 IPersistStreamInit *iface, CLSID *classid)
780 domdoc* This = impl_from_IPersistStreamInit(iface);
781 TRACE("(%p)->(%p)\n", This, classid);
783 if(!classid)
784 return E_POINTER;
786 *classid = *DOMDocument_version(This->properties->version);
788 return S_OK;
791 static HRESULT WINAPI PersistStreamInit_IsDirty(
792 IPersistStreamInit *iface)
794 domdoc *This = impl_from_IPersistStreamInit(iface);
795 FIXME("(%p): stub!\n", This);
796 return S_FALSE;
799 static HRESULT domdoc_load_from_stream(domdoc *doc, ISequentialStream *stream)
801 DWORD read, written, len;
802 xmlDocPtr xmldoc = NULL;
803 IStream *hstream;
804 HGLOBAL hglobal;
805 BYTE buf[4096];
806 HRESULT hr;
807 char *ptr;
809 hstream = NULL;
810 hr = CreateStreamOnHGlobal(NULL, TRUE, &hstream);
811 if (FAILED(hr))
812 return hr;
816 ISequentialStream_Read(stream, buf, sizeof(buf), &read);
817 hr = IStream_Write(hstream, buf, read, &written);
818 } while(SUCCEEDED(hr) && written != 0 && read != 0);
820 if (FAILED(hr))
822 ERR("failed to copy stream, hr %#lx.\n", hr);
823 IStream_Release(hstream);
824 return hr;
827 hr = GetHGlobalFromStream(hstream, &hglobal);
828 if (FAILED(hr))
830 IStream_Release(hstream);
831 return hr;
834 len = GlobalSize(hglobal);
835 ptr = GlobalLock(hglobal);
836 if (len)
837 xmldoc = doparse(doc, ptr, len, XML_CHAR_ENCODING_NONE);
838 GlobalUnlock(hglobal);
839 IStream_Release(hstream);
841 if (!xmldoc)
843 ERR("Failed to parse xml\n");
844 return E_FAIL;
847 xmldoc->_private = create_priv();
849 return attach_xmldoc(doc, xmldoc);
852 static HRESULT WINAPI PersistStreamInit_Load(IPersistStreamInit *iface, IStream *stream)
854 domdoc *This = impl_from_IPersistStreamInit(iface);
856 TRACE("(%p)->(%p)\n", This, stream);
858 if (!stream)
859 return E_INVALIDARG;
861 return This->error = domdoc_load_from_stream(This, (ISequentialStream*)stream);
864 static HRESULT WINAPI PersistStreamInit_Save(
865 IPersistStreamInit *iface, IStream *stream, BOOL clr_dirty)
867 domdoc *This = impl_from_IPersistStreamInit(iface);
868 BSTR xmlString;
869 HRESULT hr;
871 TRACE("(%p)->(%p %d)\n", This, stream, clr_dirty);
873 hr = IXMLDOMDocument3_get_xml(&This->IXMLDOMDocument3_iface, &xmlString);
874 if(hr == S_OK)
876 DWORD len = SysStringLen(xmlString) * sizeof(WCHAR);
878 hr = IStream_Write( stream, xmlString, len, NULL );
879 SysFreeString(xmlString);
882 TRACE("hr %#lx.\n", hr);
884 return hr;
887 static HRESULT WINAPI PersistStreamInit_GetSizeMax(
888 IPersistStreamInit *iface, ULARGE_INTEGER *pcbSize)
890 domdoc *This = impl_from_IPersistStreamInit(iface);
891 TRACE("(%p)->(%p)\n", This, pcbSize);
892 return E_NOTIMPL;
895 static HRESULT WINAPI PersistStreamInit_InitNew(
896 IPersistStreamInit *iface)
898 domdoc *This = impl_from_IPersistStreamInit(iface);
899 TRACE("(%p)\n", This);
900 return S_OK;
903 static const IPersistStreamInitVtbl xmldoc_IPersistStreamInit_VTable =
905 PersistStreamInit_QueryInterface,
906 PersistStreamInit_AddRef,
907 PersistStreamInit_Release,
908 PersistStreamInit_GetClassID,
909 PersistStreamInit_IsDirty,
910 PersistStreamInit_Load,
911 PersistStreamInit_Save,
912 PersistStreamInit_GetSizeMax,
913 PersistStreamInit_InitNew
916 /* IXMLDOMDocument3 interface */
918 static const tid_t domdoc_se_tids[] = {
919 IXMLDOMNode_tid,
920 IXMLDOMDocument_tid,
921 IXMLDOMDocument2_tid,
922 IXMLDOMDocument3_tid,
923 NULL_tid
926 static HRESULT WINAPI domdoc_QueryInterface( IXMLDOMDocument3 *iface, REFIID riid, void** ppvObject )
928 domdoc *This = impl_from_IXMLDOMDocument3( iface );
930 TRACE("(%p)->(%s %p)\n", This, debugstr_guid( riid ), ppvObject );
932 *ppvObject = NULL;
934 if ( IsEqualGUID( riid, &IID_IUnknown ) ||
935 IsEqualGUID( riid, &IID_IDispatch ) ||
936 IsEqualGUID( riid, &IID_IXMLDOMNode ) ||
937 IsEqualGUID( riid, &IID_IXMLDOMDocument ) ||
938 IsEqualGUID( riid, &IID_IXMLDOMDocument2 )||
939 IsEqualGUID( riid, &IID_IXMLDOMDocument3 ))
941 *ppvObject = iface;
943 else if (IsEqualGUID(&IID_IPersistStream, riid) ||
944 IsEqualGUID(&IID_IPersistStreamInit, riid))
946 *ppvObject = &This->IPersistStreamInit_iface;
948 else if (IsEqualGUID(&IID_IObjectWithSite, riid))
950 *ppvObject = &This->IObjectWithSite_iface;
952 else if (IsEqualGUID(&IID_IObjectSafety, riid))
954 *ppvObject = &This->IObjectSafety_iface;
956 else if( IsEqualGUID( riid, &IID_ISupportErrorInfo ))
958 return node_create_supporterrorinfo(domdoc_se_tids, ppvObject);
960 else if(node_query_interface(&This->node, riid, ppvObject))
962 return *ppvObject ? S_OK : E_NOINTERFACE;
964 else if (IsEqualGUID( riid, &IID_IConnectionPointContainer ))
966 *ppvObject = &This->IConnectionPointContainer_iface;
968 else
970 TRACE("interface %s not implemented\n", debugstr_guid(riid));
971 return E_NOINTERFACE;
974 IUnknown_AddRef((IUnknown*)*ppvObject);
976 return S_OK;
979 static ULONG WINAPI domdoc_AddRef( IXMLDOMDocument3 *iface )
981 domdoc *doc = impl_from_IXMLDOMDocument3(iface);
982 ULONG ref = InterlockedIncrement(&doc->ref);
983 TRACE("%p, refcount %ld.\n", iface, ref);
984 return ref;
987 static ULONG WINAPI domdoc_Release( IXMLDOMDocument3 *iface )
989 domdoc *This = impl_from_IXMLDOMDocument3( iface );
990 LONG ref = InterlockedDecrement( &This->ref );
992 TRACE("%p, refcount %ld.\n", iface, ref);
994 if (!ref)
996 int eid;
998 if (This->site)
999 IUnknown_Release( This->site );
1000 if (This->base_uri)
1001 IUri_Release( This->base_uri );
1002 destroy_xmlnode(&This->node);
1004 for (eid = 0; eid < EVENTID_LAST; eid++)
1005 if (This->events[eid]) IDispatch_Release(This->events[eid]);
1007 properties_release(This->properties);
1008 release_namespaces(This);
1009 heap_free(This);
1012 return ref;
1015 static HRESULT WINAPI domdoc_GetTypeInfoCount( IXMLDOMDocument3 *iface, UINT* pctinfo )
1017 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1018 return IDispatchEx_GetTypeInfoCount(&This->node.dispex.IDispatchEx_iface, pctinfo);
1021 static HRESULT WINAPI domdoc_GetTypeInfo(
1022 IXMLDOMDocument3 *iface,
1023 UINT iTInfo, LCID lcid, ITypeInfo** ppTInfo )
1025 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1026 return IDispatchEx_GetTypeInfo(&This->node.dispex.IDispatchEx_iface, iTInfo, lcid, ppTInfo);
1029 static HRESULT WINAPI domdoc_GetIDsOfNames(
1030 IXMLDOMDocument3 *iface,
1031 REFIID riid,
1032 LPOLESTR* rgszNames,
1033 UINT cNames,
1034 LCID lcid,
1035 DISPID* rgDispId)
1037 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1038 return IDispatchEx_GetIDsOfNames(&This->node.dispex.IDispatchEx_iface,
1039 riid, rgszNames, cNames, lcid, rgDispId);
1042 static HRESULT WINAPI domdoc_Invoke(
1043 IXMLDOMDocument3 *iface,
1044 DISPID dispIdMember,
1045 REFIID riid,
1046 LCID lcid,
1047 WORD wFlags,
1048 DISPPARAMS* pDispParams,
1049 VARIANT* pVarResult,
1050 EXCEPINFO* pExcepInfo,
1051 UINT* puArgErr)
1053 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1054 return IDispatchEx_Invoke(&This->node.dispex.IDispatchEx_iface,
1055 dispIdMember, riid, lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
1058 static HRESULT WINAPI domdoc_get_nodeName(
1059 IXMLDOMDocument3 *iface,
1060 BSTR* name )
1062 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1064 static const WCHAR documentW[] = {'#','d','o','c','u','m','e','n','t',0};
1066 TRACE("(%p)->(%p)\n", This, name);
1068 return return_bstr(documentW, name);
1072 static HRESULT WINAPI domdoc_get_nodeValue(
1073 IXMLDOMDocument3 *iface,
1074 VARIANT* value )
1076 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1078 TRACE("(%p)->(%p)\n", This, value);
1080 if(!value)
1081 return E_INVALIDARG;
1083 V_VT(value) = VT_NULL;
1084 V_BSTR(value) = NULL; /* tests show that we should do this */
1085 return S_FALSE;
1089 static HRESULT WINAPI domdoc_put_nodeValue(
1090 IXMLDOMDocument3 *iface,
1091 VARIANT value)
1093 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1094 TRACE("(%p)->(%s)\n", This, debugstr_variant(&value));
1095 return E_FAIL;
1099 static HRESULT WINAPI domdoc_get_nodeType(
1100 IXMLDOMDocument3 *iface,
1101 DOMNodeType* type )
1103 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1105 TRACE("(%p)->(%p)\n", This, type);
1107 *type = NODE_DOCUMENT;
1108 return S_OK;
1112 static HRESULT WINAPI domdoc_get_parentNode(
1113 IXMLDOMDocument3 *iface,
1114 IXMLDOMNode** parent )
1116 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1118 TRACE("(%p)->(%p)\n", This, parent);
1120 return node_get_parent(&This->node, parent);
1124 static HRESULT WINAPI domdoc_get_childNodes(
1125 IXMLDOMDocument3 *iface,
1126 IXMLDOMNodeList** childList )
1128 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1130 TRACE("(%p)->(%p)\n", This, childList);
1132 return node_get_child_nodes(&This->node, childList);
1136 static HRESULT WINAPI domdoc_get_firstChild(
1137 IXMLDOMDocument3 *iface,
1138 IXMLDOMNode** firstChild )
1140 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1142 TRACE("(%p)->(%p)\n", This, firstChild);
1144 return node_get_first_child(&This->node, firstChild);
1148 static HRESULT WINAPI domdoc_get_lastChild(
1149 IXMLDOMDocument3 *iface,
1150 IXMLDOMNode** lastChild )
1152 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1154 TRACE("(%p)->(%p)\n", This, lastChild);
1156 return node_get_last_child(&This->node, lastChild);
1160 static HRESULT WINAPI domdoc_get_previousSibling(
1161 IXMLDOMDocument3 *iface,
1162 IXMLDOMNode** previousSibling )
1164 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1166 TRACE("(%p)->(%p)\n", This, previousSibling);
1168 return return_null_node(previousSibling);
1172 static HRESULT WINAPI domdoc_get_nextSibling(
1173 IXMLDOMDocument3 *iface,
1174 IXMLDOMNode** nextSibling )
1176 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1178 TRACE("(%p)->(%p)\n", This, nextSibling);
1180 return return_null_node(nextSibling);
1184 static HRESULT WINAPI domdoc_get_attributes(
1185 IXMLDOMDocument3 *iface,
1186 IXMLDOMNamedNodeMap** attributeMap )
1188 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1190 TRACE("(%p)->(%p)\n", This, attributeMap);
1192 return return_null_ptr((void**)attributeMap);
1196 static HRESULT WINAPI domdoc_insertBefore(
1197 IXMLDOMDocument3 *iface,
1198 IXMLDOMNode* newChild,
1199 VARIANT refChild,
1200 IXMLDOMNode** outNewChild )
1202 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1203 DOMNodeType type;
1204 HRESULT hr;
1206 TRACE("(%p)->(%p %s %p)\n", This, newChild, debugstr_variant(&refChild), outNewChild);
1208 if (!newChild) return E_INVALIDARG;
1210 hr = IXMLDOMNode_get_nodeType(newChild, &type);
1211 if (hr != S_OK) return hr;
1213 TRACE("new node type %d\n", type);
1214 switch (type)
1216 case NODE_ATTRIBUTE:
1217 case NODE_DOCUMENT:
1218 case NODE_CDATA_SECTION:
1219 if (outNewChild) *outNewChild = NULL;
1220 return E_FAIL;
1221 default:
1222 return node_insert_before(&This->node, newChild, &refChild, outNewChild);
1226 static HRESULT WINAPI domdoc_replaceChild(
1227 IXMLDOMDocument3 *iface,
1228 IXMLDOMNode* newChild,
1229 IXMLDOMNode* oldChild,
1230 IXMLDOMNode** outOldChild)
1232 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1234 TRACE("(%p)->(%p %p %p)\n", This, newChild, oldChild, outOldChild);
1236 return node_replace_child(&This->node, newChild, oldChild, outOldChild);
1240 static HRESULT WINAPI domdoc_removeChild(
1241 IXMLDOMDocument3 *iface,
1242 IXMLDOMNode *child,
1243 IXMLDOMNode **oldChild)
1245 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1246 TRACE("(%p)->(%p %p)\n", This, child, oldChild);
1247 return node_remove_child(&This->node, child, oldChild);
1251 static HRESULT WINAPI domdoc_appendChild(
1252 IXMLDOMDocument3 *iface,
1253 IXMLDOMNode *child,
1254 IXMLDOMNode **outChild)
1256 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1257 TRACE("(%p)->(%p %p)\n", This, child, outChild);
1258 return node_append_child(&This->node, child, outChild);
1262 static HRESULT WINAPI domdoc_hasChildNodes(
1263 IXMLDOMDocument3 *iface,
1264 VARIANT_BOOL *ret)
1266 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1267 TRACE("(%p)->(%p)\n", This, ret);
1268 return node_has_childnodes(&This->node, ret);
1272 static HRESULT WINAPI domdoc_get_ownerDocument(
1273 IXMLDOMDocument3 *iface,
1274 IXMLDOMDocument **doc)
1276 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1277 TRACE("(%p)->(%p)\n", This, doc);
1278 return node_get_owner_doc(&This->node, doc);
1282 static HRESULT WINAPI domdoc_cloneNode(
1283 IXMLDOMDocument3 *iface,
1284 VARIANT_BOOL deep,
1285 IXMLDOMNode** outNode)
1287 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1288 xmlNodePtr clone;
1290 TRACE("(%p)->(%d %p)\n", This, deep, outNode);
1292 if (!outNode)
1293 return E_INVALIDARG;
1295 *outNode = NULL;
1297 clone = xmlCopyNode((xmlNodePtr)get_doc(This), deep ? 1 : 2);
1298 if (!clone)
1299 return E_FAIL;
1301 clone->doc->_private = create_priv();
1302 xmldoc_add_orphan(clone->doc, clone);
1303 xmldoc_add_ref(clone->doc);
1305 priv_from_xmlDocPtr(clone->doc)->properties = copy_properties(This->properties);
1306 if (!(*outNode = (IXMLDOMNode*)create_domdoc(clone)))
1308 xmldoc_release(clone->doc);
1309 return E_FAIL;
1312 return S_OK;
1316 static HRESULT WINAPI domdoc_get_nodeTypeString(
1317 IXMLDOMDocument3 *iface,
1318 BSTR *p)
1320 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1321 static const WCHAR documentW[] = {'d','o','c','u','m','e','n','t',0};
1323 TRACE("(%p)->(%p)\n", This, p);
1325 return return_bstr(documentW, p);
1329 static HRESULT WINAPI domdoc_get_text(
1330 IXMLDOMDocument3 *iface,
1331 BSTR *p)
1333 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1334 TRACE("(%p)->(%p)\n", This, p);
1335 return node_get_text(&This->node, p);
1339 static HRESULT WINAPI domdoc_put_text(
1340 IXMLDOMDocument3 *iface,
1341 BSTR text )
1343 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1344 TRACE("(%p)->(%s)\n", This, debugstr_w(text));
1345 return E_FAIL;
1349 static HRESULT WINAPI domdoc_get_specified(
1350 IXMLDOMDocument3 *iface,
1351 VARIANT_BOOL* isSpecified )
1353 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1354 FIXME("(%p)->(%p) stub!\n", This, isSpecified);
1355 *isSpecified = VARIANT_TRUE;
1356 return S_OK;
1360 static HRESULT WINAPI domdoc_get_definition(
1361 IXMLDOMDocument3 *iface,
1362 IXMLDOMNode** definitionNode )
1364 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1365 FIXME("(%p)->(%p)\n", This, definitionNode);
1366 return E_NOTIMPL;
1370 static HRESULT WINAPI domdoc_get_nodeTypedValue(
1371 IXMLDOMDocument3 *iface,
1372 VARIANT* v )
1374 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1375 TRACE("(%p)->(%p)\n", This, v);
1376 return return_null_var(v);
1379 static HRESULT WINAPI domdoc_put_nodeTypedValue(
1380 IXMLDOMDocument3 *iface,
1381 VARIANT typedValue )
1383 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1384 FIXME("(%p)->(%s)\n", This, debugstr_variant(&typedValue));
1385 return E_NOTIMPL;
1389 static HRESULT WINAPI domdoc_get_dataType(
1390 IXMLDOMDocument3 *iface,
1391 VARIANT* typename )
1393 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1394 TRACE("(%p)->(%p)\n", This, typename);
1395 return return_null_var( typename );
1399 static HRESULT WINAPI domdoc_put_dataType(
1400 IXMLDOMDocument3 *iface,
1401 BSTR dataTypeName )
1403 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1405 FIXME("(%p)->(%s)\n", This, debugstr_w(dataTypeName));
1407 if(!dataTypeName)
1408 return E_INVALIDARG;
1410 return E_FAIL;
1413 static int XMLCALL domdoc_get_xml_writecallback(void *ctx, const char *data, int len)
1415 return xmlBufferAdd((xmlBufferPtr)ctx, (xmlChar*)data, len) == 0 ? len : 0;
1418 static HRESULT WINAPI domdoc_get_xml(
1419 IXMLDOMDocument3 *iface,
1420 BSTR* p)
1422 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1423 xmlSaveCtxtPtr ctxt;
1424 xmlBufferPtr buf;
1425 int options;
1426 long ret;
1428 TRACE("(%p)->(%p)\n", This, p);
1430 if(!p)
1431 return E_INVALIDARG;
1433 *p = NULL;
1435 buf = xmlBufferCreate();
1436 if(!buf)
1437 return E_OUTOFMEMORY;
1439 options = XML_SAVE_FORMAT | XML_SAVE_NO_DECL;
1440 ctxt = xmlSaveToIO(domdoc_get_xml_writecallback, NULL, buf, "UTF-8", options);
1442 if(!ctxt)
1444 xmlBufferFree(buf);
1445 return E_OUTOFMEMORY;
1448 ret = xmlSaveDoc(ctxt, get_doc(This));
1449 /* flushes on close */
1450 xmlSaveClose(ctxt);
1452 TRACE("%ld, len=%d\n", ret, xmlBufferLength(buf));
1453 if(ret != -1 && xmlBufferLength(buf) > 0)
1455 BSTR content;
1457 content = bstr_from_xmlChar(xmlBufferContent(buf));
1458 content = EnsureCorrectEOL(content);
1460 *p = content;
1462 else
1464 *p = SysAllocStringLen(NULL, 0);
1467 xmlBufferFree(buf);
1469 return *p ? S_OK : E_OUTOFMEMORY;
1473 static HRESULT WINAPI domdoc_transformNode(
1474 IXMLDOMDocument3 *iface,
1475 IXMLDOMNode *node,
1476 BSTR *p)
1478 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1479 TRACE("(%p)->(%p %p)\n", This, node, p);
1480 return node_transform_node(&This->node, node, p);
1484 static HRESULT WINAPI domdoc_selectNodes(
1485 IXMLDOMDocument3 *iface,
1486 BSTR p,
1487 IXMLDOMNodeList **outList)
1489 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1490 TRACE("(%p)->(%s %p)\n", This, debugstr_w(p), outList);
1491 return node_select_nodes(&This->node, p, outList);
1495 static HRESULT WINAPI domdoc_selectSingleNode(
1496 IXMLDOMDocument3 *iface,
1497 BSTR p,
1498 IXMLDOMNode **outNode)
1500 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1501 TRACE("(%p)->(%s %p)\n", This, debugstr_w(p), outNode);
1502 return node_select_singlenode(&This->node, p, outNode);
1506 static HRESULT WINAPI domdoc_get_parsed(
1507 IXMLDOMDocument3 *iface,
1508 VARIANT_BOOL* isParsed )
1510 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1511 FIXME("(%p)->(%p) stub!\n", This, isParsed);
1512 *isParsed = VARIANT_TRUE;
1513 return S_OK;
1516 static HRESULT WINAPI domdoc_get_namespaceURI(
1517 IXMLDOMDocument3 *iface,
1518 BSTR* namespaceURI )
1520 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1521 TRACE("(%p)->(%p)\n", This, namespaceURI);
1522 return return_null_bstr( namespaceURI );
1525 static HRESULT WINAPI domdoc_get_prefix(
1526 IXMLDOMDocument3 *iface,
1527 BSTR* prefix )
1529 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1530 TRACE("(%p)->(%p)\n", This, prefix);
1531 return return_null_bstr( prefix );
1535 static HRESULT WINAPI domdoc_get_baseName(
1536 IXMLDOMDocument3 *iface,
1537 BSTR* name )
1539 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1540 TRACE("(%p)->(%p)\n", This, name);
1541 return return_null_bstr( name );
1545 static HRESULT WINAPI domdoc_transformNodeToObject(
1546 IXMLDOMDocument3 *iface,
1547 IXMLDOMNode* stylesheet,
1548 VARIANT output)
1550 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1552 TRACE("(%p)->(%p %s)\n", This, stylesheet, debugstr_variant(&output));
1554 switch (V_VT(&output))
1556 case VT_UNKNOWN:
1557 case VT_DISPATCH:
1559 ISequentialStream *stream;
1560 IXMLDOMDocument *doc;
1561 HRESULT hr;
1562 BSTR str;
1564 if (!V_UNKNOWN(&output))
1565 return E_INVALIDARG;
1567 /* FIXME: we're not supposed to query for document interface, should use IStream
1568 which we don't support currently. */
1569 if (IUnknown_QueryInterface(V_UNKNOWN(&output), &IID_IXMLDOMDocument, (void **)&doc) == S_OK)
1571 VARIANT_BOOL b;
1573 if (FAILED(hr = node_transform_node(&This->node, stylesheet, &str)))
1574 return hr;
1576 hr = IXMLDOMDocument_loadXML(doc, str, &b);
1577 SysFreeString(str);
1578 return hr;
1580 else if (IUnknown_QueryInterface(V_UNKNOWN(&output), &IID_ISequentialStream, (void**)&stream) == S_OK)
1582 hr = node_transform_node_params(&This->node, stylesheet, NULL, stream, NULL);
1583 ISequentialStream_Release(stream);
1584 return hr;
1586 else
1588 FIXME("Unsupported destination type.\n");
1589 return E_INVALIDARG;
1592 default:
1593 FIXME("Output type %d not handled.\n", V_VT(&output));
1594 return E_NOTIMPL;
1597 return E_NOTIMPL;
1601 static HRESULT WINAPI domdoc_get_doctype(
1602 IXMLDOMDocument3 *iface,
1603 IXMLDOMDocumentType** doctype )
1605 domdoc *This = impl_from_IXMLDOMDocument3(iface);
1606 IXMLDOMNode *node;
1607 xmlDtdPtr dtd;
1608 HRESULT hr;
1610 TRACE("(%p)->(%p)\n", This, doctype);
1612 if (!doctype) return E_INVALIDARG;
1614 *doctype = NULL;
1616 dtd = xmlGetIntSubset(get_doc(This));
1617 if (!dtd) return S_FALSE;
1619 node = create_node((xmlNodePtr)dtd);
1620 if (!node) return S_FALSE;
1622 hr = IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMDocumentType, (void**)doctype);
1623 IXMLDOMNode_Release(node);
1625 return hr;
1629 static HRESULT WINAPI domdoc_get_implementation(
1630 IXMLDOMDocument3 *iface,
1631 IXMLDOMImplementation** impl )
1633 domdoc *This = impl_from_IXMLDOMDocument3(iface);
1635 TRACE("(%p)->(%p)\n", This, impl);
1637 if(!impl)
1638 return E_INVALIDARG;
1640 return create_dom_implementation(impl);
1643 static HRESULT WINAPI domdoc_get_documentElement(
1644 IXMLDOMDocument3 *iface,
1645 IXMLDOMElement** DOMElement )
1647 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1648 IXMLDOMNode *element_node;
1649 xmlNodePtr root;
1650 HRESULT hr;
1652 TRACE("(%p)->(%p)\n", This, DOMElement);
1654 if(!DOMElement)
1655 return E_INVALIDARG;
1657 *DOMElement = NULL;
1659 root = xmlDocGetRootElement( get_doc(This) );
1660 if ( !root )
1661 return S_FALSE;
1663 element_node = create_node( root );
1664 if(!element_node) return S_FALSE;
1666 hr = IXMLDOMNode_QueryInterface(element_node, &IID_IXMLDOMElement, (void**)DOMElement);
1667 IXMLDOMNode_Release(element_node);
1669 return hr;
1673 static HRESULT WINAPI domdoc_put_documentElement(
1674 IXMLDOMDocument3 *iface,
1675 IXMLDOMElement* DOMElement )
1677 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1678 IXMLDOMNode *elementNode;
1679 xmlNodePtr oldRoot;
1680 xmlDocPtr old_doc;
1681 xmlnode *xmlNode;
1682 int refcount = 0;
1683 HRESULT hr;
1685 TRACE("(%p)->(%p)\n", This, DOMElement);
1687 hr = IXMLDOMElement_QueryInterface( DOMElement, &IID_IXMLDOMNode, (void**)&elementNode );
1688 if(FAILED(hr))
1689 return hr;
1691 xmlNode = get_node_obj( elementNode );
1692 if(!xmlNode) return E_FAIL;
1694 if(!xmlNode->node->parent)
1695 if(xmldoc_remove_orphan(xmlNode->node->doc, xmlNode->node) != S_OK)
1696 WARN("%p is not an orphan of %p\n", xmlNode->node->doc, xmlNode->node);
1698 old_doc = xmlNode->node->doc;
1699 if (old_doc != get_doc(This))
1700 refcount = xmlnode_get_inst_cnt(xmlNode);
1702 /* old root is still orphaned by its document, update refcount from new root */
1703 if (refcount) xmldoc_add_refs(get_doc(This), refcount);
1704 oldRoot = xmlDocSetRootElement( get_doc(This), xmlNode->node);
1705 if (refcount) xmldoc_release_refs(old_doc, refcount);
1706 IXMLDOMNode_Release( elementNode );
1708 if(oldRoot)
1709 xmldoc_add_orphan(oldRoot->doc, oldRoot);
1711 return S_OK;
1715 static HRESULT WINAPI domdoc_createElement(
1716 IXMLDOMDocument3 *iface,
1717 BSTR tagname,
1718 IXMLDOMElement** element )
1720 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1721 IXMLDOMNode *node;
1722 VARIANT type;
1723 HRESULT hr;
1725 TRACE("(%p)->(%s %p)\n", This, debugstr_w(tagname), element);
1727 if (!element || !tagname) return E_INVALIDARG;
1729 V_VT(&type) = VT_I1;
1730 V_I1(&type) = NODE_ELEMENT;
1732 hr = IXMLDOMDocument3_createNode(iface, type, tagname, NULL, &node);
1733 if (hr == S_OK)
1735 IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMElement, (void**)element);
1736 IXMLDOMNode_Release(node);
1739 return hr;
1743 static HRESULT WINAPI domdoc_createDocumentFragment(
1744 IXMLDOMDocument3 *iface,
1745 IXMLDOMDocumentFragment** frag )
1747 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1748 IXMLDOMNode *node;
1749 VARIANT type;
1750 HRESULT hr;
1752 TRACE("(%p)->(%p)\n", This, frag);
1754 if (!frag) return E_INVALIDARG;
1756 *frag = NULL;
1758 V_VT(&type) = VT_I1;
1759 V_I1(&type) = NODE_DOCUMENT_FRAGMENT;
1761 hr = IXMLDOMDocument3_createNode(iface, type, NULL, NULL, &node);
1762 if (hr == S_OK)
1764 IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMDocumentFragment, (void**)frag);
1765 IXMLDOMNode_Release(node);
1768 return hr;
1772 static HRESULT WINAPI domdoc_createTextNode(
1773 IXMLDOMDocument3 *iface,
1774 BSTR data,
1775 IXMLDOMText** text )
1777 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1778 IXMLDOMNode *node;
1779 VARIANT type;
1780 HRESULT hr;
1782 TRACE("(%p)->(%s %p)\n", This, debugstr_w(data), text);
1784 if (!text) return E_INVALIDARG;
1786 *text = NULL;
1788 V_VT(&type) = VT_I1;
1789 V_I1(&type) = NODE_TEXT;
1791 hr = IXMLDOMDocument3_createNode(iface, type, NULL, NULL, &node);
1792 if (hr == S_OK)
1794 IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMText, (void**)text);
1795 IXMLDOMNode_Release(node);
1796 hr = IXMLDOMText_put_data(*text, data);
1799 return hr;
1803 static HRESULT WINAPI domdoc_createComment(
1804 IXMLDOMDocument3 *iface,
1805 BSTR data,
1806 IXMLDOMComment** comment )
1808 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1809 VARIANT type;
1810 HRESULT hr;
1811 IXMLDOMNode *node;
1813 TRACE("(%p)->(%s %p)\n", This, debugstr_w(data), comment);
1815 if (!comment) return E_INVALIDARG;
1817 *comment = NULL;
1819 V_VT(&type) = VT_I1;
1820 V_I1(&type) = NODE_COMMENT;
1822 hr = IXMLDOMDocument3_createNode(iface, type, NULL, NULL, &node);
1823 if (hr == S_OK)
1825 IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMComment, (void**)comment);
1826 IXMLDOMNode_Release(node);
1827 hr = IXMLDOMComment_put_data(*comment, data);
1830 return hr;
1834 static HRESULT WINAPI domdoc_createCDATASection(
1835 IXMLDOMDocument3 *iface,
1836 BSTR data,
1837 IXMLDOMCDATASection** cdata )
1839 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1840 IXMLDOMNode *node;
1841 VARIANT type;
1842 HRESULT hr;
1844 TRACE("(%p)->(%s %p)\n", This, debugstr_w(data), cdata);
1846 if (!cdata) return E_INVALIDARG;
1848 *cdata = NULL;
1850 V_VT(&type) = VT_I1;
1851 V_I1(&type) = NODE_CDATA_SECTION;
1853 hr = IXMLDOMDocument3_createNode(iface, type, NULL, NULL, &node);
1854 if (hr == S_OK)
1856 IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMCDATASection, (void**)cdata);
1857 IXMLDOMNode_Release(node);
1858 hr = IXMLDOMCDATASection_put_data(*cdata, data);
1861 return hr;
1865 static HRESULT WINAPI domdoc_createProcessingInstruction(
1866 IXMLDOMDocument3 *iface,
1867 BSTR target,
1868 BSTR data,
1869 IXMLDOMProcessingInstruction** pi )
1871 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1872 IXMLDOMNode *node;
1873 VARIANT type;
1874 HRESULT hr;
1876 TRACE("(%p)->(%s %s %p)\n", This, debugstr_w(target), debugstr_w(data), pi);
1878 if (!pi) return E_INVALIDARG;
1880 *pi = NULL;
1882 V_VT(&type) = VT_I1;
1883 V_I1(&type) = NODE_PROCESSING_INSTRUCTION;
1885 hr = IXMLDOMDocument3_createNode(iface, type, target, NULL, &node);
1886 if (hr == S_OK)
1888 /* this is to bypass check in ::put_data() that blocks "<?xml" PIs */
1889 hr = dom_pi_put_xml_decl(node, data);
1890 if (SUCCEEDED(hr))
1891 hr = IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMProcessingInstruction, (void**)pi);
1892 IXMLDOMNode_Release(node);
1895 return hr;
1899 static HRESULT WINAPI domdoc_createAttribute(
1900 IXMLDOMDocument3 *iface,
1901 BSTR name,
1902 IXMLDOMAttribute** attribute )
1904 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1905 IXMLDOMNode *node;
1906 VARIANT type;
1907 HRESULT hr;
1909 TRACE("(%p)->(%s %p)\n", This, debugstr_w(name), attribute);
1911 if (!attribute || !name) return E_INVALIDARG;
1913 V_VT(&type) = VT_I1;
1914 V_I1(&type) = NODE_ATTRIBUTE;
1916 hr = IXMLDOMDocument3_createNode(iface, type, name, NULL, &node);
1917 if (hr == S_OK)
1919 IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMAttribute, (void**)attribute);
1920 IXMLDOMNode_Release(node);
1923 return hr;
1927 static HRESULT WINAPI domdoc_createEntityReference(
1928 IXMLDOMDocument3 *iface,
1929 BSTR name,
1930 IXMLDOMEntityReference** entityref )
1932 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1933 IXMLDOMNode *node;
1934 VARIANT type;
1935 HRESULT hr;
1937 TRACE("(%p)->(%s %p)\n", This, debugstr_w(name), entityref);
1939 if (!entityref) return E_INVALIDARG;
1941 *entityref = NULL;
1943 V_VT(&type) = VT_I1;
1944 V_I1(&type) = NODE_ENTITY_REFERENCE;
1946 hr = IXMLDOMDocument3_createNode(iface, type, name, NULL, &node);
1947 if (hr == S_OK)
1949 IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMEntityReference, (void**)entityref);
1950 IXMLDOMNode_Release(node);
1953 return hr;
1956 xmlChar* tagName_to_XPath(const BSTR tagName)
1958 xmlChar *query, *tmp;
1959 static const xmlChar everything[] = "/descendant::node()";
1960 static const xmlChar mod_pre[] = "*[local-name()='";
1961 static const xmlChar mod_post[] = "']";
1962 static const xmlChar prefix[] = "descendant::";
1963 const WCHAR *tokBegin, *tokEnd;
1964 int len;
1966 /* Special case - empty tagname - means select all nodes,
1967 except document itself. */
1968 if (!*tagName)
1969 return xmlStrdup(everything);
1971 query = xmlStrdup(prefix);
1973 tokBegin = tagName;
1974 while (tokBegin && *tokBegin)
1976 switch (*tokBegin)
1978 case '/':
1979 query = xmlStrcat(query, BAD_CAST "/");
1980 ++tokBegin;
1981 break;
1982 case '*':
1983 query = xmlStrcat(query, BAD_CAST "*");
1984 ++tokBegin;
1985 break;
1986 default:
1987 query = xmlStrcat(query, mod_pre);
1988 tokEnd = tokBegin;
1989 while (*tokEnd && *tokEnd != '/')
1990 ++tokEnd;
1991 len = WideCharToMultiByte(CP_UTF8, 0, tokBegin, tokEnd-tokBegin, NULL, 0, NULL, NULL);
1992 tmp = xmlMalloc(len);
1993 WideCharToMultiByte(CP_UTF8, 0, tokBegin, tokEnd-tokBegin, (char*)tmp, len, NULL, NULL);
1994 query = xmlStrncat(query, tmp, len);
1995 xmlFree(tmp);
1996 tokBegin = tokEnd;
1997 query = xmlStrcat(query, mod_post);
2001 return query;
2004 static HRESULT WINAPI domdoc_getElementsByTagName(
2005 IXMLDOMDocument3 *iface,
2006 BSTR tagName,
2007 IXMLDOMNodeList** resultList )
2009 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2010 xmlChar *query;
2011 HRESULT hr;
2012 BOOL XPath;
2014 TRACE("(%p)->(%s, %p)\n", This, debugstr_w(tagName), resultList);
2016 if (!tagName || !resultList) return E_INVALIDARG;
2018 XPath = This->properties->XPath;
2019 This->properties->XPath = TRUE;
2020 query = tagName_to_XPath(tagName);
2021 hr = create_selection((xmlNodePtr)get_doc(This), query, resultList);
2022 xmlFree(query);
2023 This->properties->XPath = XPath;
2025 return hr;
2028 static HRESULT get_node_type(VARIANT Type, DOMNodeType * type)
2030 VARIANT tmp;
2031 HRESULT hr;
2033 VariantInit(&tmp);
2034 hr = VariantChangeType(&tmp, &Type, 0, VT_I4);
2035 if(FAILED(hr))
2036 return E_INVALIDARG;
2038 *type = V_I4(&tmp);
2040 return S_OK;
2043 static HRESULT WINAPI domdoc_createNode(
2044 IXMLDOMDocument3 *iface,
2045 VARIANT Type,
2046 BSTR name,
2047 BSTR namespaceURI,
2048 IXMLDOMNode** node )
2050 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2051 DOMNodeType node_type;
2052 xmlNodePtr xmlnode;
2053 xmlChar *xml_name, *href;
2054 HRESULT hr;
2056 TRACE("(%p)->(%s %s %s %p)\n", This, debugstr_variant(&Type), debugstr_w(name), debugstr_w(namespaceURI), node);
2058 if(!node) return E_INVALIDARG;
2060 hr = get_node_type(Type, &node_type);
2061 if(FAILED(hr)) return hr;
2063 TRACE("node_type %d\n", node_type);
2065 /* exit earlier for types that need name */
2066 switch(node_type)
2068 case NODE_ELEMENT:
2069 case NODE_ATTRIBUTE:
2070 case NODE_ENTITY_REFERENCE:
2071 case NODE_PROCESSING_INSTRUCTION:
2072 if (!name || *name == 0) return E_FAIL;
2073 break;
2074 default:
2075 break;
2078 xml_name = xmlchar_from_wchar(name);
2079 /* prevent empty href from being allocated */
2080 href = namespaceURI ? xmlchar_from_wchar(namespaceURI) : NULL;
2082 switch(node_type)
2084 case NODE_ELEMENT:
2086 xmlChar *local, *prefix;
2088 local = xmlSplitQName2(xml_name, &prefix);
2090 xmlnode = xmlNewDocNode(get_doc(This), NULL, local ? local : xml_name, NULL);
2092 /* allow creating the default namespace xmlns= */
2093 if (local || (href && *href))
2095 xmlNsPtr ns = xmlNewNs(xmlnode, href, prefix);
2096 xmlSetNs(xmlnode, ns);
2099 xmlFree(local);
2100 xmlFree(prefix);
2102 break;
2104 case NODE_ATTRIBUTE:
2106 xmlChar *local, *prefix;
2108 local = xmlSplitQName2(xml_name, &prefix);
2110 xmlnode = (xmlNodePtr)xmlNewDocProp(get_doc(This), local ? local : xml_name, NULL);
2112 if (local || (href && *href))
2114 /* we need a floating namespace here, it can't be created linked to attribute from
2115 a start */
2116 xmlNsPtr ns = xmlNewNs(NULL, href, prefix);
2117 xmlSetNs(xmlnode, ns);
2120 xmlFree(local);
2121 xmlFree(prefix);
2123 break;
2125 case NODE_TEXT:
2126 xmlnode = (xmlNodePtr)xmlNewDocText(get_doc(This), NULL);
2127 break;
2128 case NODE_CDATA_SECTION:
2129 xmlnode = xmlNewCDataBlock(get_doc(This), NULL, 0);
2130 break;
2131 case NODE_ENTITY_REFERENCE:
2132 xmlnode = xmlNewReference(get_doc(This), xml_name);
2133 break;
2134 case NODE_PROCESSING_INSTRUCTION:
2135 xmlnode = xmlNewDocPI(get_doc(This), xml_name, NULL);
2136 break;
2137 case NODE_COMMENT:
2138 xmlnode = xmlNewDocComment(get_doc(This), NULL);
2139 break;
2140 case NODE_DOCUMENT_FRAGMENT:
2141 xmlnode = xmlNewDocFragment(get_doc(This));
2142 break;
2143 /* unsupported types */
2144 case NODE_DOCUMENT:
2145 case NODE_DOCUMENT_TYPE:
2146 case NODE_ENTITY:
2147 case NODE_NOTATION:
2148 heap_free(xml_name);
2149 return E_INVALIDARG;
2150 default:
2151 FIXME("unhandled node type %d\n", node_type);
2152 xmlnode = NULL;
2153 break;
2156 *node = create_node(xmlnode);
2157 heap_free(xml_name);
2158 heap_free(href);
2160 if(*node)
2162 TRACE("created node (%d, %p, %p)\n", node_type, *node, xmlnode);
2163 xmldoc_add_orphan(xmlnode->doc, xmlnode);
2164 return S_OK;
2167 return E_FAIL;
2170 static HRESULT WINAPI domdoc_nodeFromID(
2171 IXMLDOMDocument3 *iface,
2172 BSTR idString,
2173 IXMLDOMNode** node )
2175 domdoc *This = impl_from_IXMLDOMDocument3(iface);
2176 FIXME("(%p)->(%s %p)\n", This, debugstr_w(idString), node);
2177 return E_NOTIMPL;
2180 static HRESULT domdoc_onDataAvailable(void *obj, char *ptr, DWORD len)
2182 domdoc *This = obj;
2183 xmlDocPtr xmldoc;
2185 xmldoc = doparse(This, ptr, len, XML_CHAR_ENCODING_NONE);
2186 if(xmldoc) {
2187 xmldoc->_private = create_priv();
2188 return attach_xmldoc(This, xmldoc);
2191 return E_FAIL;
2194 static HRESULT domdoc_load_moniker(domdoc *This, IMoniker *mon)
2196 bsc_t *bsc;
2197 HRESULT hr;
2199 hr = bind_url(mon, domdoc_onDataAvailable, This, &bsc);
2200 if(FAILED(hr))
2201 return hr;
2203 return detach_bsc(bsc);
2206 static HRESULT WINAPI domdoc_load(
2207 IXMLDOMDocument3 *iface,
2208 VARIANT source,
2209 VARIANT_BOOL* isSuccessful )
2211 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2212 LPWSTR filename = NULL;
2213 HRESULT hr = S_FALSE;
2214 xmlDocPtr xmldoc;
2216 TRACE("(%p)->(%s)\n", This, debugstr_variant(&source));
2218 if (!isSuccessful)
2219 return E_POINTER;
2220 *isSuccessful = VARIANT_FALSE;
2222 assert( &This->node );
2224 switch( V_VT(&source) )
2226 case VT_BSTR:
2227 filename = V_BSTR(&source);
2228 break;
2229 case VT_BSTR|VT_BYREF:
2230 if (!V_BSTRREF(&source)) return E_INVALIDARG;
2231 filename = *V_BSTRREF(&source);
2232 break;
2233 case VT_ARRAY|VT_UI1:
2235 SAFEARRAY *psa = V_ARRAY(&source);
2236 char *str;
2237 LONG len;
2238 UINT dim = SafeArrayGetDim(psa);
2240 switch (dim)
2242 case 0:
2243 ERR("SAFEARRAY == NULL\n");
2244 hr = This->error = E_INVALIDARG;
2245 break;
2246 case 1:
2247 /* Only takes UTF-8 strings.
2248 * NOT NULL-terminated. */
2249 hr = SafeArrayAccessData(psa, (void**)&str);
2250 if (FAILED(hr))
2252 This->error = hr;
2253 WARN("failed to access array data, hr %#lx.\n", hr);
2254 break;
2256 SafeArrayGetUBound(psa, 1, &len);
2258 if ((xmldoc = doparse(This, str, ++len, XML_CHAR_ENCODING_UTF8)))
2260 hr = This->error = S_OK;
2261 *isSuccessful = VARIANT_TRUE;
2262 TRACE("parsed document %p\n", xmldoc);
2264 else
2266 This->error = E_FAIL;
2267 TRACE("failed to parse document\n");
2270 SafeArrayUnaccessData(psa);
2272 if(xmldoc)
2274 xmldoc->_private = create_priv();
2275 return attach_xmldoc(This, xmldoc);
2277 break;
2278 default:
2279 FIXME("unhandled SAFEARRAY dim: %d\n", dim);
2280 hr = This->error = E_NOTIMPL;
2283 break;
2284 case VT_UNKNOWN:
2286 ISequentialStream *stream = NULL;
2287 IXMLDOMDocument3 *newdoc = NULL;
2289 if (!V_UNKNOWN(&source)) return E_INVALIDARG;
2291 hr = IUnknown_QueryInterface(V_UNKNOWN(&source), &IID_IXMLDOMDocument3, (void**)&newdoc);
2292 if(hr == S_OK)
2294 if(newdoc)
2296 domdoc *newDoc = impl_from_IXMLDOMDocument3( newdoc );
2298 xmldoc = xmlCopyDoc(get_doc(newDoc), 1);
2299 xmldoc->_private = create_priv();
2300 hr = attach_xmldoc(This, xmldoc);
2302 if(SUCCEEDED(hr))
2303 *isSuccessful = VARIANT_TRUE;
2305 return hr;
2309 hr = IUnknown_QueryInterface(V_UNKNOWN(&source), &IID_IStream, (void**)&stream);
2310 if (FAILED(hr))
2311 hr = IUnknown_QueryInterface(V_UNKNOWN(&source), &IID_ISequentialStream, (void**)&stream);
2313 if (hr == S_OK)
2315 hr = This->error = domdoc_load_from_stream(This, stream);
2316 if (hr == S_OK)
2317 *isSuccessful = VARIANT_TRUE;
2318 ISequentialStream_Release(stream);
2319 return hr;
2322 FIXME("unsupported IUnknown type (%#lx) (%p)\n", hr, V_UNKNOWN(&source)->lpVtbl);
2323 break;
2325 default:
2326 FIXME("VT type not supported (%d)\n", V_VT(&source));
2329 if ( filename )
2331 IUri *uri = NULL;
2332 IMoniker *mon;
2334 if (This->properties->uri)
2336 IUri_Release(This->properties->uri);
2337 This->properties->uri = NULL;
2340 hr = create_uri(This->base_uri, filename, &uri);
2341 if (SUCCEEDED(hr))
2342 hr = CreateURLMonikerEx2(NULL, uri, &mon, 0);
2343 if ( SUCCEEDED(hr) )
2345 hr = domdoc_load_moniker( This, mon );
2346 IMoniker_Release(mon);
2349 if (SUCCEEDED(hr))
2351 get_doc(This)->name = (char *)xmlchar_from_wcharn(filename, -1, TRUE);
2352 This->properties->uri = uri;
2353 hr = This->error = S_OK;
2354 *isSuccessful = VARIANT_TRUE;
2356 else
2358 if (uri)
2359 IUri_Release(uri);
2360 This->error = E_FAIL;
2364 if(!filename || FAILED(hr)) {
2365 xmldoc = xmlNewDoc(NULL);
2366 xmldoc->_private = create_priv();
2367 hr = attach_xmldoc(This, xmldoc);
2368 if(SUCCEEDED(hr))
2369 hr = S_FALSE;
2372 TRACE("hr %#lx.\n", hr);
2374 return hr;
2378 static HRESULT WINAPI domdoc_get_readyState(
2379 IXMLDOMDocument3 *iface,
2380 LONG *value )
2382 domdoc *This = impl_from_IXMLDOMDocument3(iface);
2383 FIXME("stub! (%p)->(%p)\n", This, value);
2385 if (!value)
2386 return E_INVALIDARG;
2388 *value = READYSTATE_COMPLETE;
2389 return S_OK;
2393 static HRESULT WINAPI domdoc_get_parseError(
2394 IXMLDOMDocument3 *iface,
2395 IXMLDOMParseError** errorObj )
2397 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2398 static const WCHAR err[] = {'e','r','r','o','r',0};
2399 BSTR error_string = NULL;
2401 FIXME("(%p)->(%p): creating a dummy parseError\n", iface, errorObj);
2403 if(This->error)
2404 error_string = SysAllocString(err);
2406 *errorObj = create_parseError(This->error, NULL, error_string, NULL, 0, 0, 0);
2407 if(!*errorObj) return E_OUTOFMEMORY;
2408 return S_OK;
2412 static HRESULT WINAPI domdoc_get_url(
2413 IXMLDOMDocument3 *iface,
2414 BSTR* url )
2416 domdoc *This = impl_from_IXMLDOMDocument3(iface);
2418 TRACE("(%p)->(%p)\n", This, url);
2420 if (!url)
2421 return E_INVALIDARG;
2423 if (!This->properties->uri)
2424 return return_null_bstr(url);
2426 return IUri_GetPropertyBSTR(This->properties->uri, Uri_PROPERTY_DISPLAY_URI, url, 0);
2430 static HRESULT WINAPI domdoc_get_async(
2431 IXMLDOMDocument3 *iface,
2432 VARIANT_BOOL* isAsync )
2434 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2436 TRACE("(%p)->(%p: %d)\n", This, isAsync, This->async);
2437 *isAsync = This->async;
2438 return S_OK;
2442 static HRESULT WINAPI domdoc_put_async(
2443 IXMLDOMDocument3 *iface,
2444 VARIANT_BOOL isAsync )
2446 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2448 TRACE("(%p)->(%d)\n", This, isAsync);
2449 This->async = isAsync;
2450 return S_OK;
2454 static HRESULT WINAPI domdoc_abort(
2455 IXMLDOMDocument3 *iface )
2457 domdoc *This = impl_from_IXMLDOMDocument3(iface);
2458 FIXME("%p\n", This);
2459 return E_NOTIMPL;
2462 /* don't rely on data to be in BSTR format, treat it as WCHAR string */
2463 static HRESULT WINAPI domdoc_loadXML(
2464 IXMLDOMDocument3 *iface,
2465 BSTR data,
2466 VARIANT_BOOL* isSuccessful )
2468 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2469 xmlDocPtr xmldoc = NULL;
2470 HRESULT hr = S_FALSE, hr2;
2472 TRACE("(%p)->(%s %p)\n", This, debugstr_w(data), isSuccessful );
2474 assert ( &This->node );
2476 if ( isSuccessful )
2478 *isSuccessful = VARIANT_FALSE;
2480 if (data)
2482 WCHAR *ptr = data;
2484 /* skip leading spaces if needed */
2485 if (This->properties->version == MSXML_DEFAULT || This->properties->version == MSXML26)
2486 while (*ptr && iswspace(*ptr)) ptr++;
2488 xmldoc = doparse(This, (char*)ptr, lstrlenW(ptr)*sizeof(WCHAR), XML_CHAR_ENCODING_UTF16LE);
2489 if ( !xmldoc )
2491 This->error = E_FAIL;
2492 TRACE("failed to parse document\n");
2494 else
2496 hr = This->error = S_OK;
2497 *isSuccessful = VARIANT_TRUE;
2498 TRACE("parsed document %p\n", xmldoc);
2503 if(!xmldoc)
2504 xmldoc = xmlNewDoc(NULL);
2505 xmldoc->_private = create_priv();
2506 hr2 = attach_xmldoc(This, xmldoc);
2507 if( FAILED(hr2) )
2508 hr = hr2;
2510 return hr;
2513 static int XMLCALL domdoc_save_writecallback(void *ctx, const char *buffer, int len)
2515 DWORD written = -1;
2517 if(!WriteFile(ctx, buffer, len, &written, NULL))
2519 WARN("write error\n");
2520 return -1;
2522 else
2523 return written;
2526 static int XMLCALL domdoc_save_closecallback(void *ctx)
2528 return CloseHandle(ctx) ? 0 : -1;
2531 static int XMLCALL domdoc_stream_save_writecallback(void *ctx, const char *buffer, int len)
2533 ULONG written = 0;
2534 HRESULT hr;
2536 hr = IStream_Write((IStream*)ctx, buffer, len, &written);
2537 TRACE("hr %#lx, %p, %d, %lu.\n", hr, buffer, len, written);
2538 if (hr != S_OK)
2540 WARN("stream write error, hr %#lx.\n", hr);
2541 return -1;
2543 else
2544 return len;
2547 static int XMLCALL domdoc_stream_save_closecallback(void *ctx)
2549 IStream_Release((IStream*)ctx);
2550 return 0;
2553 static char *xmldoc_encoding(IXMLDOMDocument3 *doc)
2555 HRESULT hr;
2556 IXMLDOMNode *node;
2557 char *encoding = NULL;
2559 hr = IXMLDOMDocument3_get_firstChild(doc, &node);
2560 if (hr == S_OK)
2562 DOMNodeType type;
2564 hr = IXMLDOMNode_get_nodeType(node, &type);
2565 if (hr == S_OK && type == NODE_PROCESSING_INSTRUCTION)
2567 IXMLDOMProcessingInstruction *pi;
2568 IXMLDOMNode *item;
2569 IXMLDOMNamedNodeMap *node_map;
2571 hr = IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMProcessingInstruction, (void **)&pi);
2572 if (hr == S_OK)
2574 hr = IXMLDOMNode_get_attributes(node, &node_map);
2575 if (hr == S_OK)
2577 static const WCHAR encodingW[] = {'e','n','c','o','d','i','n','g',0};
2578 BSTR bstr;
2580 bstr = SysAllocString(encodingW);
2581 hr = IXMLDOMNamedNodeMap_getNamedItem(node_map, bstr, &item);
2582 SysFreeString(bstr);
2583 if (hr == S_OK)
2585 VARIANT var;
2587 hr = IXMLDOMNode_get_nodeValue(item, &var);
2588 if (hr == S_OK)
2590 if (V_VT(&var) == VT_BSTR)
2591 encoding = (char *)xmlchar_from_wchar(V_BSTR(&var));
2593 VariantClear(&var);
2597 IXMLDOMNamedNodeMap_Release(node_map);
2600 IXMLDOMProcessingInstruction_Release(pi);
2604 IXMLDOMNode_Release(node);
2607 if (!encoding && (encoding = heap_alloc(sizeof("UTF-8"))))
2608 strcpy(encoding, "UTF-8");
2610 return encoding;
2613 static HRESULT WINAPI domdoc_save(
2614 IXMLDOMDocument3 *iface,
2615 VARIANT destination )
2617 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2618 xmlSaveCtxtPtr ctx = NULL;
2619 HRESULT ret = S_OK;
2621 TRACE("(%p)->(%s)\n", This, debugstr_variant(&destination));
2623 switch (V_VT(&destination))
2625 case VT_UNKNOWN:
2627 IUnknown *pUnk = V_UNKNOWN(&destination);
2628 IXMLDOMDocument3 *document;
2629 IStream *stream;
2631 ret = IUnknown_QueryInterface(pUnk, &IID_IXMLDOMDocument3, (void**)&document);
2632 if(ret == S_OK)
2634 VARIANT_BOOL success;
2635 BSTR xml;
2637 ret = IXMLDOMDocument3_get_xml(iface, &xml);
2638 if(ret == S_OK)
2640 ret = IXMLDOMDocument3_loadXML(document, xml, &success);
2641 SysFreeString(xml);
2644 IXMLDOMDocument3_Release(document);
2645 return ret;
2648 ret = IUnknown_QueryInterface(pUnk, &IID_IStream, (void**)&stream);
2649 if(ret == S_OK)
2651 char *encoding = xmldoc_encoding(iface);
2653 TRACE("using encoding %s\n", encoding ? debugstr_a(encoding) : "default");
2654 ctx = xmlSaveToIO(domdoc_stream_save_writecallback,
2655 domdoc_stream_save_closecallback, stream, encoding, XML_SAVE_NO_DECL);
2656 heap_free(encoding);
2658 if(!ctx)
2660 IStream_Release(stream);
2661 return E_FAIL;
2665 break;
2667 case VT_BSTR:
2668 case VT_BSTR | VT_BYREF:
2670 char *encoding;
2671 /* save with file path */
2672 HANDLE handle = CreateFileW( (V_VT(&destination) & VT_BYREF)? *V_BSTRREF(&destination) : V_BSTR(&destination),
2673 GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL );
2674 if( handle == INVALID_HANDLE_VALUE )
2676 WARN("failed to create file\n");
2677 return E_FAIL;
2680 encoding = xmldoc_encoding(iface);
2681 TRACE("using encoding %s\n", encoding ? debugstr_a(encoding) : "default");
2682 ctx = xmlSaveToIO(domdoc_save_writecallback, domdoc_save_closecallback,
2683 handle, encoding, XML_SAVE_NO_DECL);
2684 heap_free(encoding);
2686 if (!ctx)
2688 CloseHandle(handle);
2689 return E_FAIL;
2692 break;
2694 default:
2695 FIXME("Unhandled VARIANT: %s\n", debugstr_variant(&destination));
2696 return S_FALSE;
2699 if (xmlSaveDoc(ctx, get_doc(This)) == -1) ret = S_FALSE;
2701 /* will release resources through close callback */
2702 xmlSaveClose(ctx);
2704 return ret;
2707 static HRESULT WINAPI domdoc_get_validateOnParse(
2708 IXMLDOMDocument3 *iface,
2709 VARIANT_BOOL* isValidating )
2711 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2712 TRACE("(%p)->(%p: %d)\n", This, isValidating, This->validating);
2713 *isValidating = This->validating;
2714 return S_OK;
2718 static HRESULT WINAPI domdoc_put_validateOnParse(
2719 IXMLDOMDocument3 *iface,
2720 VARIANT_BOOL isValidating )
2722 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2723 TRACE("(%p)->(%d)\n", This, isValidating);
2724 This->validating = isValidating;
2725 return S_OK;
2729 static HRESULT WINAPI domdoc_get_resolveExternals(
2730 IXMLDOMDocument3 *iface,
2731 VARIANT_BOOL* isResolving )
2733 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2734 TRACE("(%p)->(%p: %d)\n", This, isResolving, This->resolving);
2735 *isResolving = This->resolving;
2736 return S_OK;
2740 static HRESULT WINAPI domdoc_put_resolveExternals(
2741 IXMLDOMDocument3 *iface,
2742 VARIANT_BOOL isResolving )
2744 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2745 TRACE("(%p)->(%d)\n", This, isResolving);
2746 This->resolving = isResolving;
2747 return S_OK;
2751 static HRESULT WINAPI domdoc_get_preserveWhiteSpace(
2752 IXMLDOMDocument3 *iface,
2753 VARIANT_BOOL* isPreserving )
2755 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2756 TRACE("(%p)->(%p: %d)\n", This, isPreserving, This->properties->preserving);
2757 *isPreserving = This->properties->preserving;
2758 return S_OK;
2762 static HRESULT WINAPI domdoc_put_preserveWhiteSpace(
2763 IXMLDOMDocument3 *iface,
2764 VARIANT_BOOL isPreserving )
2766 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2767 TRACE("(%p)->(%d)\n", This, isPreserving);
2768 This->properties->preserving = isPreserving;
2769 return S_OK;
2773 static HRESULT WINAPI domdoc_put_onreadystatechange(
2774 IXMLDOMDocument3 *iface,
2775 VARIANT event )
2777 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2779 TRACE("(%p)->(%s)\n", This, debugstr_variant(&event));
2780 return set_doc_event(This, EVENTID_READYSTATECHANGE, &event);
2784 static HRESULT WINAPI domdoc_put_onDataAvailable(IXMLDOMDocument3 *iface, VARIANT sink)
2786 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2787 FIXME("(%p)->(%s): stub\n", This, debugstr_variant(&sink));
2788 return E_NOTIMPL;
2791 static HRESULT WINAPI domdoc_put_onTransformNode(IXMLDOMDocument3 *iface, VARIANT sink )
2793 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2794 FIXME("(%p)->(%s): stub\n", This, debugstr_variant(&sink));
2795 return E_NOTIMPL;
2798 static HRESULT WINAPI domdoc_get_namespaces(
2799 IXMLDOMDocument3* iface,
2800 IXMLDOMSchemaCollection** collection )
2802 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2803 HRESULT hr;
2805 FIXME("(%p)->(%p): semi-stub\n", This, collection);
2807 if (!collection) return E_POINTER;
2809 if (!This->namespaces)
2811 hr = SchemaCache_create(This->properties->version, (void**)&This->namespaces);
2812 if (hr != S_OK) return hr;
2814 hr = cache_from_doc_ns(This->namespaces, &This->node);
2815 if (hr != S_OK)
2816 release_namespaces(This);
2819 if (This->namespaces)
2820 return IXMLDOMSchemaCollection2_QueryInterface(This->namespaces,
2821 &IID_IXMLDOMSchemaCollection, (void**)collection);
2823 return hr;
2826 static HRESULT WINAPI domdoc_get_schemas(
2827 IXMLDOMDocument3* iface,
2828 VARIANT* schema )
2830 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2831 IXMLDOMSchemaCollection2* cur_schema = This->properties->schemaCache;
2832 HRESULT hr = S_FALSE;
2834 TRACE("(%p)->(%p)\n", This, schema);
2836 V_VT(schema) = VT_NULL;
2837 /* just to reset pointer part, cause that's what application is expected to use */
2838 V_DISPATCH(schema) = NULL;
2840 if(cur_schema)
2842 hr = IXMLDOMSchemaCollection2_QueryInterface(cur_schema, &IID_IDispatch, (void**)&V_DISPATCH(schema));
2843 if(SUCCEEDED(hr))
2844 V_VT(schema) = VT_DISPATCH;
2846 return hr;
2849 static HRESULT WINAPI domdoc_putref_schemas(
2850 IXMLDOMDocument3* iface,
2851 VARIANT schema)
2853 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2854 HRESULT hr = E_FAIL;
2855 IXMLDOMSchemaCollection2* new_schema = NULL;
2857 FIXME("(%p)->(%s): semi-stub\n", This, debugstr_variant(&schema));
2858 switch(V_VT(&schema))
2860 case VT_UNKNOWN:
2861 if (V_UNKNOWN(&schema))
2863 hr = IUnknown_QueryInterface(V_UNKNOWN(&schema), &IID_IXMLDOMSchemaCollection, (void**)&new_schema);
2864 break;
2866 /* fallthrough */
2867 case VT_DISPATCH:
2868 if (V_DISPATCH(&schema))
2870 hr = IDispatch_QueryInterface(V_DISPATCH(&schema), &IID_IXMLDOMSchemaCollection, (void**)&new_schema);
2871 break;
2873 /* fallthrough */
2874 case VT_NULL:
2875 case VT_EMPTY:
2876 hr = S_OK;
2877 break;
2879 default:
2880 WARN("Can't get schema from vt %x\n", V_VT(&schema));
2883 if(SUCCEEDED(hr))
2885 IXMLDOMSchemaCollection2* old_schema = InterlockedExchangePointer((void**)&This->properties->schemaCache, new_schema);
2886 if(old_schema) IXMLDOMSchemaCollection2_Release(old_schema);
2889 return hr;
2892 static inline BOOL is_wellformed(xmlDocPtr doc)
2894 return doc->properties & XML_DOC_WELLFORMED;
2897 static void LIBXML2_LOG_CALLBACK validate_error(void* ctx, char const* msg, ...)
2899 va_list ap;
2900 va_start(ap, msg);
2901 LIBXML2_CALLBACK_ERR(domdoc_validateNode, msg, ap);
2902 va_end(ap);
2905 static void LIBXML2_LOG_CALLBACK validate_warning(void* ctx, char const* msg, ...)
2907 va_list ap;
2908 va_start(ap, msg);
2909 LIBXML2_CALLBACK_WARN(domdoc_validateNode, msg, ap);
2910 va_end(ap);
2913 static HRESULT WINAPI domdoc_validateNode(
2914 IXMLDOMDocument3* iface,
2915 IXMLDOMNode* node,
2916 IXMLDOMParseError** err)
2918 domdoc* This = impl_from_IXMLDOMDocument3(iface);
2919 LONG state, err_code = 0;
2920 HRESULT hr = S_OK;
2921 int validated = 0;
2923 TRACE("(%p)->(%p, %p)\n", This, node, err);
2924 IXMLDOMDocument3_get_readyState(iface, &state);
2925 if (state != READYSTATE_COMPLETE)
2927 if (err)
2928 *err = create_parseError(err_code, NULL, NULL, NULL, 0, 0, 0);
2929 return E_PENDING;
2932 if (!node)
2934 if (err)
2935 *err = create_parseError(err_code, NULL, NULL, NULL, 0, 0, 0);
2936 return E_POINTER;
2939 if (!get_node_obj(node)->node || get_node_obj(node)->node->doc != get_doc(This))
2941 if (err)
2942 *err = create_parseError(err_code, NULL, NULL, NULL, 0, 0, 0);
2943 return E_FAIL;
2946 if (!is_wellformed(get_doc(This)))
2948 ERR("doc not well-formed\n");
2949 if (err)
2950 *err = create_parseError(E_XML_NOTWF, NULL, NULL, NULL, 0, 0, 0);
2951 return S_FALSE;
2954 /* DTD validation */
2955 if (get_doc(This)->intSubset || get_doc(This)->extSubset)
2957 xmlValidCtxtPtr vctx = xmlNewValidCtxt();
2958 vctx->error = validate_error;
2959 vctx->warning = validate_warning;
2960 ++validated;
2962 if (!((node == (IXMLDOMNode*)iface)?
2963 xmlValidateDocument(vctx, get_doc(This)) :
2964 xmlValidateElement(vctx, get_doc(This), get_node_obj(node)->node)))
2966 /* TODO: get a real error code here */
2967 TRACE("DTD validation failed\n");
2968 err_code = E_XML_INVALID;
2969 hr = S_FALSE;
2971 xmlFreeValidCtxt(vctx);
2974 /* Schema validation */
2975 if (hr == S_OK && This->properties->schemaCache != NULL)
2978 hr = SchemaCache_validate_tree(This->properties->schemaCache, get_node_obj(node)->node);
2979 if (SUCCEEDED(hr))
2981 ++validated;
2982 /* TODO: get a real error code here */
2983 if (hr == S_OK)
2985 TRACE("schema validation succeeded\n");
2987 else
2989 ERR("schema validation failed\n");
2990 err_code = E_XML_INVALID;
2993 else
2995 /* not really OK, just didn't find a schema for the ns */
2996 hr = S_OK;
3000 if (!validated)
3002 ERR("no DTD or schema found\n");
3003 err_code = E_XML_NODTD;
3004 hr = S_FALSE;
3007 if (err)
3008 *err = create_parseError(err_code, NULL, NULL, NULL, 0, 0, 0);
3010 return hr;
3013 static HRESULT WINAPI domdoc_validate(
3014 IXMLDOMDocument3* iface,
3015 IXMLDOMParseError** err)
3017 domdoc *This = impl_from_IXMLDOMDocument3( iface );
3018 TRACE("(%p)->(%p)\n", This, err);
3019 return IXMLDOMDocument3_validateNode(iface, (IXMLDOMNode*)iface, err);
3022 static HRESULT WINAPI domdoc_setProperty(
3023 IXMLDOMDocument3* iface,
3024 BSTR p,
3025 VARIANT value)
3027 domdoc *This = impl_from_IXMLDOMDocument3( iface );
3029 TRACE("(%p)->(%s %s)\n", This, debugstr_w(p), debugstr_variant(&value));
3031 if (lstrcmpiW(p, PropertySelectionLanguageW) == 0)
3033 VARIANT varStr;
3034 HRESULT hr;
3035 BSTR bstr;
3037 V_VT(&varStr) = VT_EMPTY;
3038 if (V_VT(&value) != VT_BSTR)
3040 if (FAILED(hr = VariantChangeType(&varStr, &value, 0, VT_BSTR)))
3041 return hr;
3042 bstr = V_BSTR(&varStr);
3044 else
3045 bstr = V_BSTR(&value);
3047 hr = S_OK;
3048 if (lstrcmpiW(bstr, PropValueXPathW) == 0)
3049 This->properties->XPath = TRUE;
3050 else if (lstrcmpiW(bstr, PropValueXSLPatternW) == 0)
3051 This->properties->XPath = FALSE;
3052 else
3053 hr = E_FAIL;
3055 VariantClear(&varStr);
3056 return hr;
3058 else if (lstrcmpiW(p, PropertySelectionNamespacesW) == 0)
3060 xmlChar *nsStr = (xmlChar*)This->properties->selectNsStr;
3061 struct list *pNsList;
3062 VARIANT varStr;
3063 HRESULT hr;
3064 BSTR bstr;
3066 V_VT(&varStr) = VT_EMPTY;
3067 if (V_VT(&value) != VT_BSTR)
3069 if (FAILED(hr = VariantChangeType(&varStr, &value, 0, VT_BSTR)))
3070 return hr;
3071 bstr = V_BSTR(&varStr);
3073 else
3074 bstr = V_BSTR(&value);
3076 hr = S_OK;
3078 pNsList = &(This->properties->selectNsList);
3079 clear_selectNsList(pNsList);
3080 heap_free(nsStr);
3081 nsStr = xmlchar_from_wchar(bstr);
3083 TRACE("property value: \"%s\"\n", debugstr_w(bstr));
3085 This->properties->selectNsStr = nsStr;
3086 This->properties->selectNsStr_len = xmlStrlen(nsStr);
3087 if (bstr && *bstr)
3089 xmlChar *pTokBegin, *pTokEnd, *pTokInner;
3090 select_ns_entry* ns_entry = NULL;
3091 xmlXPathContextPtr ctx;
3093 ctx = xmlXPathNewContext(This->node.node->doc);
3094 pTokBegin = nsStr;
3096 /* skip leading spaces */
3097 while (*pTokBegin == ' ' || *pTokBegin == '\n' ||
3098 *pTokBegin == '\t' || *pTokBegin == '\r')
3099 ++pTokBegin;
3101 for (; *pTokBegin; pTokBegin = pTokEnd)
3103 if (ns_entry)
3104 memset(ns_entry, 0, sizeof(select_ns_entry));
3105 else
3106 ns_entry = heap_alloc_zero(sizeof(select_ns_entry));
3108 while (*pTokBegin == ' ')
3109 ++pTokBegin;
3110 pTokEnd = pTokBegin;
3111 while (*pTokEnd != ' ' && *pTokEnd != 0)
3112 ++pTokEnd;
3114 /* so it failed to advance which means we've got some trailing spaces */
3115 if (pTokEnd == pTokBegin) break;
3117 if (xmlStrncmp(pTokBegin, (xmlChar const*)"xmlns", 5) != 0)
3119 hr = E_FAIL;
3120 WARN("Syntax error in xmlns string: %s\n\tat token: %s\n",
3121 debugstr_w(bstr), debugstr_an((const char*)pTokBegin, pTokEnd-pTokBegin));
3122 continue;
3125 pTokBegin += 5;
3126 if (*pTokBegin == '=')
3128 /*valid for XSLPattern?*/
3129 FIXME("Setting default xmlns not supported - skipping.\n");
3130 continue;
3132 else if (*pTokBegin == ':')
3134 ns_entry->prefix = ++pTokBegin;
3135 for (pTokInner = pTokBegin; pTokInner != pTokEnd && *pTokInner != '='; ++pTokInner)
3138 if (pTokInner == pTokEnd)
3140 hr = E_FAIL;
3141 WARN("Syntax error in xmlns string: %s\n\tat token: %s\n",
3142 debugstr_w(bstr), debugstr_an((const char*)pTokBegin, pTokEnd-pTokBegin));
3143 continue;
3146 ns_entry->prefix_end = *pTokInner;
3147 *pTokInner = 0;
3148 ++pTokInner;
3150 if (pTokEnd-pTokInner > 1 &&
3151 ((*pTokInner == '\'' && *(pTokEnd-1) == '\'') ||
3152 (*pTokInner == '"' && *(pTokEnd-1) == '"')))
3154 ns_entry->href = ++pTokInner;
3155 ns_entry->href_end = *(pTokEnd-1);
3156 *(pTokEnd-1) = 0;
3157 list_add_tail(pNsList, &ns_entry->entry);
3158 /*let libxml figure out if they're valid from here ;)*/
3159 if (xmlXPathRegisterNs(ctx, ns_entry->prefix, ns_entry->href) != 0)
3161 hr = E_FAIL;
3163 ns_entry = NULL;
3164 continue;
3166 else
3168 WARN("Syntax error in xmlns string: %s\n\tat token: %s\n",
3169 debugstr_w(bstr), debugstr_an((const char*)pTokInner, pTokEnd-pTokInner));
3170 list_add_tail(pNsList, &ns_entry->entry);
3172 ns_entry = NULL;
3173 hr = E_FAIL;
3174 continue;
3177 else
3179 hr = E_FAIL;
3180 continue;
3183 heap_free(ns_entry);
3184 xmlXPathFreeContext(ctx);
3187 VariantClear(&varStr);
3188 return hr;
3190 else if (lstrcmpiW(p, PropertyProhibitDTDW) == 0 ||
3191 lstrcmpiW(p, PropertyNewParserW) == 0 ||
3192 lstrcmpiW(p, PropertyResolveExternalsW) == 0 ||
3193 lstrcmpiW(p, PropertyAllowXsltScriptW) == 0 ||
3194 lstrcmpiW(p, PropertyNormalizeAttributeValuesW) == 0 ||
3195 lstrcmpiW(p, PropertyAllowDocumentFunctionW) == 0)
3197 /* Ignore */
3198 FIXME("Ignoring property %s, value %s\n", debugstr_w(p), debugstr_variant(&value));
3199 return S_OK;
3202 FIXME("Unknown property %s\n", debugstr_w(p));
3203 return E_FAIL;
3206 static HRESULT WINAPI domdoc_getProperty(
3207 IXMLDOMDocument3* iface,
3208 BSTR p,
3209 VARIANT* var)
3211 domdoc *This = impl_from_IXMLDOMDocument3( iface );
3213 TRACE("(%p)->(%s)\n", This, debugstr_w(p));
3215 if (!var)
3216 return E_INVALIDARG;
3218 if (lstrcmpiW(p, PropertySelectionLanguageW) == 0)
3220 V_VT(var) = VT_BSTR;
3221 V_BSTR(var) = This->properties->XPath ?
3222 SysAllocString(PropValueXPathW) :
3223 SysAllocString(PropValueXSLPatternW);
3224 return V_BSTR(var) ? S_OK : E_OUTOFMEMORY;
3226 else if (lstrcmpiW(p, PropertySelectionNamespacesW) == 0)
3228 int lenA, lenW;
3229 BSTR rebuiltStr, cur;
3230 const xmlChar *nsStr;
3231 struct list *pNsList;
3232 select_ns_entry* pNsEntry;
3234 V_VT(var) = VT_BSTR;
3235 nsStr = This->properties->selectNsStr;
3236 pNsList = &This->properties->selectNsList;
3237 lenA = This->properties->selectNsStr_len;
3238 lenW = MultiByteToWideChar(CP_UTF8, 0, (LPCSTR)nsStr, lenA+1, NULL, 0);
3239 rebuiltStr = heap_alloc(lenW*sizeof(WCHAR));
3240 MultiByteToWideChar(CP_UTF8, 0, (LPCSTR)nsStr, lenA+1, rebuiltStr, lenW);
3241 cur = rebuiltStr;
3242 /* this is fine because all of the chars that end tokens are ASCII*/
3243 LIST_FOR_EACH_ENTRY(pNsEntry, pNsList, select_ns_entry, entry)
3245 while (*cur != 0) ++cur;
3246 if (pNsEntry->prefix_end)
3248 *cur = pNsEntry->prefix_end;
3249 while (*cur != 0) ++cur;
3252 if (pNsEntry->href_end)
3254 *cur = pNsEntry->href_end;
3257 V_BSTR(var) = SysAllocString(rebuiltStr);
3258 heap_free(rebuiltStr);
3259 return S_OK;
3262 FIXME("Unknown property %s\n", debugstr_w(p));
3263 return E_FAIL;
3266 static HRESULT WINAPI domdoc_importNode(
3267 IXMLDOMDocument3* iface,
3268 IXMLDOMNode* node,
3269 VARIANT_BOOL deep,
3270 IXMLDOMNode** clone)
3272 domdoc *This = impl_from_IXMLDOMDocument3( iface );
3273 FIXME("(%p)->(%p %d %p): stub\n", This, node, deep, clone);
3274 return E_NOTIMPL;
3277 static const struct IXMLDOMDocument3Vtbl XMLDOMDocument3Vtbl =
3279 domdoc_QueryInterface,
3280 domdoc_AddRef,
3281 domdoc_Release,
3282 domdoc_GetTypeInfoCount,
3283 domdoc_GetTypeInfo,
3284 domdoc_GetIDsOfNames,
3285 domdoc_Invoke,
3286 domdoc_get_nodeName,
3287 domdoc_get_nodeValue,
3288 domdoc_put_nodeValue,
3289 domdoc_get_nodeType,
3290 domdoc_get_parentNode,
3291 domdoc_get_childNodes,
3292 domdoc_get_firstChild,
3293 domdoc_get_lastChild,
3294 domdoc_get_previousSibling,
3295 domdoc_get_nextSibling,
3296 domdoc_get_attributes,
3297 domdoc_insertBefore,
3298 domdoc_replaceChild,
3299 domdoc_removeChild,
3300 domdoc_appendChild,
3301 domdoc_hasChildNodes,
3302 domdoc_get_ownerDocument,
3303 domdoc_cloneNode,
3304 domdoc_get_nodeTypeString,
3305 domdoc_get_text,
3306 domdoc_put_text,
3307 domdoc_get_specified,
3308 domdoc_get_definition,
3309 domdoc_get_nodeTypedValue,
3310 domdoc_put_nodeTypedValue,
3311 domdoc_get_dataType,
3312 domdoc_put_dataType,
3313 domdoc_get_xml,
3314 domdoc_transformNode,
3315 domdoc_selectNodes,
3316 domdoc_selectSingleNode,
3317 domdoc_get_parsed,
3318 domdoc_get_namespaceURI,
3319 domdoc_get_prefix,
3320 domdoc_get_baseName,
3321 domdoc_transformNodeToObject,
3322 domdoc_get_doctype,
3323 domdoc_get_implementation,
3324 domdoc_get_documentElement,
3325 domdoc_put_documentElement,
3326 domdoc_createElement,
3327 domdoc_createDocumentFragment,
3328 domdoc_createTextNode,
3329 domdoc_createComment,
3330 domdoc_createCDATASection,
3331 domdoc_createProcessingInstruction,
3332 domdoc_createAttribute,
3333 domdoc_createEntityReference,
3334 domdoc_getElementsByTagName,
3335 domdoc_createNode,
3336 domdoc_nodeFromID,
3337 domdoc_load,
3338 domdoc_get_readyState,
3339 domdoc_get_parseError,
3340 domdoc_get_url,
3341 domdoc_get_async,
3342 domdoc_put_async,
3343 domdoc_abort,
3344 domdoc_loadXML,
3345 domdoc_save,
3346 domdoc_get_validateOnParse,
3347 domdoc_put_validateOnParse,
3348 domdoc_get_resolveExternals,
3349 domdoc_put_resolveExternals,
3350 domdoc_get_preserveWhiteSpace,
3351 domdoc_put_preserveWhiteSpace,
3352 domdoc_put_onreadystatechange,
3353 domdoc_put_onDataAvailable,
3354 domdoc_put_onTransformNode,
3355 domdoc_get_namespaces,
3356 domdoc_get_schemas,
3357 domdoc_putref_schemas,
3358 domdoc_validate,
3359 domdoc_setProperty,
3360 domdoc_getProperty,
3361 domdoc_validateNode,
3362 domdoc_importNode
3365 /* IConnectionPointContainer */
3366 static HRESULT WINAPI ConnectionPointContainer_QueryInterface(IConnectionPointContainer *iface,
3367 REFIID riid, void **ppv)
3369 domdoc *This = impl_from_IConnectionPointContainer(iface);
3370 return IXMLDOMDocument3_QueryInterface(&This->IXMLDOMDocument3_iface, riid, ppv);
3373 static ULONG WINAPI ConnectionPointContainer_AddRef(IConnectionPointContainer *iface)
3375 domdoc *This = impl_from_IConnectionPointContainer(iface);
3376 return IXMLDOMDocument3_AddRef(&This->IXMLDOMDocument3_iface);
3379 static ULONG WINAPI ConnectionPointContainer_Release(IConnectionPointContainer *iface)
3381 domdoc *This = impl_from_IConnectionPointContainer(iface);
3382 return IXMLDOMDocument3_Release(&This->IXMLDOMDocument3_iface);
3385 static HRESULT WINAPI ConnectionPointContainer_EnumConnectionPoints(IConnectionPointContainer *iface,
3386 IEnumConnectionPoints **ppEnum)
3388 domdoc *This = impl_from_IConnectionPointContainer(iface);
3389 FIXME("(%p)->(%p): stub\n", This, ppEnum);
3390 return E_NOTIMPL;
3393 static HRESULT WINAPI ConnectionPointContainer_FindConnectionPoint(IConnectionPointContainer *iface,
3394 REFIID riid, IConnectionPoint **cp)
3396 domdoc *This = impl_from_IConnectionPointContainer(iface);
3397 ConnectionPoint *iter;
3399 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), cp);
3401 *cp = NULL;
3403 for(iter = This->cp_list; iter; iter = iter->next)
3405 if (IsEqualGUID(iter->iid, riid))
3406 *cp = &iter->IConnectionPoint_iface;
3409 if (*cp)
3411 IConnectionPoint_AddRef(*cp);
3412 return S_OK;
3415 FIXME("unsupported riid %s\n", debugstr_guid(riid));
3416 return CONNECT_E_NOCONNECTION;
3420 static const struct IConnectionPointContainerVtbl ConnectionPointContainerVtbl =
3422 ConnectionPointContainer_QueryInterface,
3423 ConnectionPointContainer_AddRef,
3424 ConnectionPointContainer_Release,
3425 ConnectionPointContainer_EnumConnectionPoints,
3426 ConnectionPointContainer_FindConnectionPoint
3429 /* IConnectionPoint */
3430 static HRESULT WINAPI ConnectionPoint_QueryInterface(IConnectionPoint *iface,
3431 REFIID riid, void **ppv)
3433 ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3435 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv );
3437 *ppv = NULL;
3439 if (IsEqualGUID(&IID_IUnknown, riid) ||
3440 IsEqualGUID(&IID_IConnectionPoint, riid))
3442 *ppv = iface;
3445 if (*ppv)
3447 IConnectionPoint_AddRef(iface);
3448 return S_OK;
3451 WARN("Unsupported interface %s\n", debugstr_guid(riid));
3452 return E_NOINTERFACE;
3455 static ULONG WINAPI ConnectionPoint_AddRef(IConnectionPoint *iface)
3457 ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3458 return IConnectionPointContainer_AddRef(This->container);
3461 static ULONG WINAPI ConnectionPoint_Release(IConnectionPoint *iface)
3463 ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3464 return IConnectionPointContainer_Release(This->container);
3467 static HRESULT WINAPI ConnectionPoint_GetConnectionInterface(IConnectionPoint *iface, IID *iid)
3469 ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3471 TRACE("(%p)->(%p)\n", This, iid);
3473 if (!iid) return E_POINTER;
3475 *iid = *This->iid;
3476 return S_OK;
3479 static HRESULT WINAPI ConnectionPoint_GetConnectionPointContainer(IConnectionPoint *iface,
3480 IConnectionPointContainer **container)
3482 ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3484 TRACE("(%p)->(%p)\n", This, container);
3486 if (!container) return E_POINTER;
3488 *container = This->container;
3489 IConnectionPointContainer_AddRef(*container);
3490 return S_OK;
3493 static HRESULT WINAPI ConnectionPoint_Advise(IConnectionPoint *iface, IUnknown *unk_sink,
3494 DWORD *cookie)
3496 ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3497 IUnknown *sink;
3498 HRESULT hr;
3499 DWORD i;
3501 TRACE("(%p)->(%p %p)\n", This, unk_sink, cookie);
3503 hr = IUnknown_QueryInterface(unk_sink, This->iid, (void**)&sink);
3504 if(FAILED(hr) && !IsEqualGUID(&IID_IPropertyNotifySink, This->iid))
3505 hr = IUnknown_QueryInterface(unk_sink, &IID_IDispatch, (void**)&sink);
3506 if(FAILED(hr))
3507 return CONNECT_E_CANNOTCONNECT;
3509 if(This->sinks)
3511 for (i = 0; i < This->sinks_size; i++)
3512 if (!This->sinks[i].unk)
3513 break;
3515 if (i == This->sinks_size)
3516 This->sinks = heap_realloc(This->sinks,(++This->sinks_size)*sizeof(*This->sinks));
3518 else
3520 This->sinks = heap_alloc(sizeof(*This->sinks));
3521 This->sinks_size = 1;
3522 i = 0;
3525 This->sinks[i].unk = sink;
3526 if (cookie)
3527 *cookie = i+1;
3529 return S_OK;
3532 static HRESULT WINAPI ConnectionPoint_Unadvise(IConnectionPoint *iface, DWORD cookie)
3534 ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3536 TRACE("%p, %ld.\n", iface, cookie);
3538 if (cookie == 0 || cookie > This->sinks_size || !This->sinks[cookie-1].unk)
3539 return CONNECT_E_NOCONNECTION;
3541 IUnknown_Release(This->sinks[cookie-1].unk);
3542 This->sinks[cookie-1].unk = NULL;
3544 return S_OK;
3547 static HRESULT WINAPI ConnectionPoint_EnumConnections(IConnectionPoint *iface,
3548 IEnumConnections **ppEnum)
3550 ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3551 FIXME("(%p)->(%p): stub\n", This, ppEnum);
3552 return E_NOTIMPL;
3555 static const IConnectionPointVtbl ConnectionPointVtbl =
3557 ConnectionPoint_QueryInterface,
3558 ConnectionPoint_AddRef,
3559 ConnectionPoint_Release,
3560 ConnectionPoint_GetConnectionInterface,
3561 ConnectionPoint_GetConnectionPointContainer,
3562 ConnectionPoint_Advise,
3563 ConnectionPoint_Unadvise,
3564 ConnectionPoint_EnumConnections
3567 static void ConnectionPoint_Init(ConnectionPoint *cp, struct domdoc *doc, REFIID riid)
3569 cp->IConnectionPoint_iface.lpVtbl = &ConnectionPointVtbl;
3570 cp->doc = doc;
3571 cp->iid = riid;
3572 cp->sinks = NULL;
3573 cp->sinks_size = 0;
3575 cp->next = doc->cp_list;
3576 doc->cp_list = cp;
3578 cp->container = &doc->IConnectionPointContainer_iface;
3581 /* domdoc implementation of IObjectWithSite */
3582 static HRESULT WINAPI
3583 domdoc_ObjectWithSite_QueryInterface( IObjectWithSite* iface, REFIID riid, void** ppvObject )
3585 domdoc *This = impl_from_IObjectWithSite(iface);
3586 return IXMLDOMDocument3_QueryInterface(&This->IXMLDOMDocument3_iface, riid, ppvObject);
3589 static ULONG WINAPI domdoc_ObjectWithSite_AddRef( IObjectWithSite* iface )
3591 domdoc *This = impl_from_IObjectWithSite(iface);
3592 return IXMLDOMDocument3_AddRef(&This->IXMLDOMDocument3_iface);
3595 static ULONG WINAPI domdoc_ObjectWithSite_Release( IObjectWithSite* iface )
3597 domdoc *This = impl_from_IObjectWithSite(iface);
3598 return IXMLDOMDocument3_Release(&This->IXMLDOMDocument3_iface);
3601 static HRESULT WINAPI domdoc_ObjectWithSite_GetSite( IObjectWithSite *iface, REFIID iid, void **ppvSite )
3603 domdoc *This = impl_from_IObjectWithSite(iface);
3605 TRACE("(%p)->(%s %p)\n", This, debugstr_guid( iid ), ppvSite );
3607 if ( !This->site )
3608 return E_FAIL;
3610 return IUnknown_QueryInterface( This->site, iid, ppvSite );
3613 static HRESULT WINAPI domdoc_ObjectWithSite_SetSite( IObjectWithSite *iface, IUnknown *punk )
3615 domdoc *This = impl_from_IObjectWithSite(iface);
3617 TRACE("(%p)->(%p)\n", iface, punk);
3619 if(!punk)
3621 if(This->site)
3623 IUnknown_Release( This->site );
3624 This->site = NULL;
3627 if(This->base_uri)
3629 IUri_Release(This->base_uri);
3630 This->base_uri = NULL;
3633 return S_OK;
3636 IUnknown_AddRef( punk );
3638 if(This->site)
3639 IUnknown_Release( This->site );
3641 This->site = punk;
3642 This->base_uri = get_base_uri(This->site);
3644 return S_OK;
3647 static const IObjectWithSiteVtbl domdocObjectSite =
3649 domdoc_ObjectWithSite_QueryInterface,
3650 domdoc_ObjectWithSite_AddRef,
3651 domdoc_ObjectWithSite_Release,
3652 domdoc_ObjectWithSite_SetSite,
3653 domdoc_ObjectWithSite_GetSite
3656 static HRESULT WINAPI domdoc_Safety_QueryInterface(IObjectSafety *iface, REFIID riid, void **ppv)
3658 domdoc *This = impl_from_IObjectSafety(iface);
3659 return IXMLDOMDocument3_QueryInterface(&This->IXMLDOMDocument3_iface, riid, ppv);
3662 static ULONG WINAPI domdoc_Safety_AddRef(IObjectSafety *iface)
3664 domdoc *This = impl_from_IObjectSafety(iface);
3665 return IXMLDOMDocument3_AddRef(&This->IXMLDOMDocument3_iface);
3668 static ULONG WINAPI domdoc_Safety_Release(IObjectSafety *iface)
3670 domdoc *This = impl_from_IObjectSafety(iface);
3671 return IXMLDOMDocument3_Release(&This->IXMLDOMDocument3_iface);
3674 #define SAFETY_SUPPORTED_OPTIONS (INTERFACESAFE_FOR_UNTRUSTED_CALLER|INTERFACESAFE_FOR_UNTRUSTED_DATA|INTERFACE_USES_SECURITY_MANAGER)
3676 static HRESULT WINAPI domdoc_Safety_GetInterfaceSafetyOptions(IObjectSafety *iface, REFIID riid,
3677 DWORD *supported, DWORD *enabled)
3679 domdoc *This = impl_from_IObjectSafety(iface);
3681 TRACE("(%p)->(%s %p %p)\n", This, debugstr_guid(riid), supported, enabled);
3683 if(!supported || !enabled) return E_POINTER;
3685 *supported = SAFETY_SUPPORTED_OPTIONS;
3686 *enabled = This->safeopt;
3688 return S_OK;
3691 static HRESULT WINAPI domdoc_Safety_SetInterfaceSafetyOptions(IObjectSafety *iface, REFIID riid,
3692 DWORD mask, DWORD enabled)
3694 domdoc *doc = impl_from_IObjectSafety(iface);
3696 TRACE("%p, %s, %lx, %lx.\n", iface, debugstr_guid(riid), mask, enabled);
3698 if ((mask & ~SAFETY_SUPPORTED_OPTIONS) != 0)
3699 return E_FAIL;
3701 doc->safeopt = (doc->safeopt & ~mask) | (mask & enabled);
3703 return S_OK;
3706 #undef SAFETY_SUPPORTED_OPTIONS
3708 static const IObjectSafetyVtbl domdocObjectSafetyVtbl = {
3709 domdoc_Safety_QueryInterface,
3710 domdoc_Safety_AddRef,
3711 domdoc_Safety_Release,
3712 domdoc_Safety_GetInterfaceSafetyOptions,
3713 domdoc_Safety_SetInterfaceSafetyOptions
3716 static const tid_t domdoc_iface_tids[] = {
3717 IXMLDOMDocument3_tid,
3721 static dispex_static_data_t domdoc_dispex = {
3722 NULL,
3723 IXMLDOMDocument3_tid,
3724 NULL,
3725 domdoc_iface_tids
3728 HRESULT get_domdoc_from_xmldoc(xmlDocPtr xmldoc, IXMLDOMDocument3 **document)
3730 domdoc *doc;
3732 doc = heap_alloc( sizeof (*doc) );
3733 if( !doc )
3734 return E_OUTOFMEMORY;
3736 doc->IXMLDOMDocument3_iface.lpVtbl = &XMLDOMDocument3Vtbl;
3737 doc->IPersistStreamInit_iface.lpVtbl = &xmldoc_IPersistStreamInit_VTable;
3738 doc->IObjectWithSite_iface.lpVtbl = &domdocObjectSite;
3739 doc->IObjectSafety_iface.lpVtbl = &domdocObjectSafetyVtbl;
3740 doc->IConnectionPointContainer_iface.lpVtbl = &ConnectionPointContainerVtbl;
3741 doc->ref = 1;
3742 doc->async = VARIANT_TRUE;
3743 doc->validating = 0;
3744 doc->resolving = 0;
3745 doc->properties = properties_add_ref(properties_from_xmlDocPtr(xmldoc));
3746 doc->error = S_OK;
3747 doc->site = NULL;
3748 doc->base_uri = NULL;
3749 doc->safeopt = 0;
3750 doc->cp_list = NULL;
3751 doc->namespaces = NULL;
3752 memset(doc->events, 0, sizeof(doc->events));
3754 /* events connection points */
3755 ConnectionPoint_Init(&doc->cp_dispatch, doc, &IID_IDispatch);
3756 ConnectionPoint_Init(&doc->cp_propnotif, doc, &IID_IPropertyNotifySink);
3757 ConnectionPoint_Init(&doc->cp_domdocevents, doc, &DIID_XMLDOMDocumentEvents);
3759 init_xmlnode(&doc->node, (xmlNodePtr)xmldoc, (IXMLDOMNode*)&doc->IXMLDOMDocument3_iface,
3760 &domdoc_dispex);
3762 *document = &doc->IXMLDOMDocument3_iface;
3764 TRACE("returning iface %p\n", *document);
3765 return S_OK;
3768 HRESULT dom_document_create(MSXML_VERSION version, void **ppObj)
3770 xmlDocPtr xmldoc;
3771 HRESULT hr;
3773 TRACE("(%d, %p)\n", version, ppObj);
3775 xmldoc = xmlNewDoc(NULL);
3776 if(!xmldoc)
3777 return E_OUTOFMEMORY;
3779 xmldoc_init(xmldoc, version);
3781 hr = get_domdoc_from_xmldoc(xmldoc, (IXMLDOMDocument3**)ppObj);
3782 if(FAILED(hr))
3784 properties_release(properties_from_xmlDocPtr(xmldoc));
3785 heap_free(xmldoc->_private);
3786 xmlFreeDoc(xmldoc);
3787 return hr;
3790 return hr;
3793 IUnknown* create_domdoc( xmlNodePtr document )
3795 IUnknown *obj = NULL;
3796 HRESULT hr;
3798 TRACE("(%p)\n", document);
3800 hr = get_domdoc_from_xmldoc((xmlDocPtr)document, (IXMLDOMDocument3**)&obj);
3801 if (FAILED(hr))
3802 return NULL;
3804 return obj;