dmime/tests: Check more notification / dirty messages fields.
[wine.git] / dlls / msxml3 / domdoc.c
bloba8679d9b782d995dc9956b89e682912c3c6698a9
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};
71 static const WCHAR PropertyValidateOnParse[] = L"ValidateOnParse";
73 /* Anything that passes the test_get_ownerDocument()
74 * tests can go here (data shared between all instances).
75 * We need to preserve this when reloading a document,
76 * and also need access to it from the libxml backend. */
77 typedef struct {
78 LONG refs;
79 MSXML_VERSION version;
80 VARIANT_BOOL preserving;
81 VARIANT_BOOL validating;
82 IXMLDOMSchemaCollection2* schemaCache;
83 struct list selectNsList;
84 xmlChar const* selectNsStr;
85 LONG selectNsStr_len;
86 BOOL XPath;
87 IUri *uri;
88 } domdoc_properties;
90 typedef struct ConnectionPoint ConnectionPoint;
91 typedef struct domdoc domdoc;
93 struct ConnectionPoint
95 IConnectionPoint IConnectionPoint_iface;
96 const IID *iid;
98 ConnectionPoint *next;
99 IConnectionPointContainer *container;
100 domdoc *doc;
102 union
104 IUnknown *unk;
105 IDispatch *disp;
106 IPropertyNotifySink *propnotif;
107 } *sinks;
108 DWORD sinks_size;
111 typedef enum {
112 EVENTID_READYSTATECHANGE = 0,
113 EVENTID_DATAAVAILABLE,
114 EVENTID_TRANSFORMNODE,
115 EVENTID_LAST
116 } eventid_t;
118 struct domdoc
120 xmlnode node;
121 IXMLDOMDocument3 IXMLDOMDocument3_iface;
122 IPersistStreamInit IPersistStreamInit_iface;
123 IObjectWithSite IObjectWithSite_iface;
124 IObjectSafety IObjectSafety_iface;
125 IConnectionPointContainer IConnectionPointContainer_iface;
126 LONG ref;
127 VARIANT_BOOL async;
128 VARIANT_BOOL resolving;
129 domdoc_properties* properties;
130 HRESULT error;
132 /* IObjectWithSite */
133 IUnknown *site;
134 IUri *base_uri;
136 /* IObjectSafety */
137 DWORD safeopt;
139 /* connection list */
140 ConnectionPoint *cp_list;
141 ConnectionPoint cp_domdocevents;
142 ConnectionPoint cp_propnotif;
143 ConnectionPoint cp_dispatch;
145 /* events */
146 IDispatch *events[EVENTID_LAST];
148 IXMLDOMSchemaCollection2 *namespaces;
151 static HRESULT set_doc_event(domdoc *doc, eventid_t eid, const VARIANT *v)
153 IDispatch *disp;
155 switch (V_VT(v))
157 case VT_UNKNOWN:
158 if (V_UNKNOWN(v))
159 IUnknown_QueryInterface(V_UNKNOWN(v), &IID_IDispatch, (void**)&disp);
160 else
161 disp = NULL;
162 break;
163 case VT_DISPATCH:
164 disp = V_DISPATCH(v);
165 if (disp) IDispatch_AddRef(disp);
166 break;
167 default:
168 return DISP_E_TYPEMISMATCH;
171 if (doc->events[eid]) IDispatch_Release(doc->events[eid]);
172 doc->events[eid] = disp;
174 return S_OK;
177 static inline ConnectionPoint *impl_from_IConnectionPoint(IConnectionPoint *iface)
179 return CONTAINING_RECORD(iface, ConnectionPoint, IConnectionPoint_iface);
183 In native windows, the whole lifetime management of XMLDOMNodes is
184 managed automatically using reference counts. Wine emulates that by
185 maintaining a reference count to the document that is increased for
186 each IXMLDOMNode pointer passed out for this document. If all these
187 pointers are gone, the document is unreachable and gets freed, that
188 is, all nodes in the tree of the document get freed.
190 You are able to create nodes that are associated to a document (in
191 fact, in msxml's XMLDOM model, all nodes are associated to a document),
192 but not in the tree of that document, for example using the createFoo
193 functions from IXMLDOMDocument. These nodes do not get cleaned up
194 by libxml, so we have to do it ourselves.
196 To catch these nodes, a list of "orphan nodes" is introduced.
197 It contains pointers to all roots of node trees that are
198 associated with the document without being part of the document
199 tree. All nodes with parent==NULL (except for the document root nodes)
200 should be in the orphan node list of their document. All orphan nodes
201 get freed together with the document itself.
204 typedef struct _xmldoc_priv {
205 LONG refs;
206 struct list orphans;
207 domdoc_properties* properties;
208 } xmldoc_priv;
210 typedef struct _orphan_entry {
211 struct list entry;
212 xmlNode * node;
213 } orphan_entry;
215 typedef struct _select_ns_entry {
216 struct list entry;
217 xmlChar const* prefix;
218 xmlChar prefix_end;
219 xmlChar const* href;
220 xmlChar href_end;
221 } select_ns_entry;
223 static inline xmldoc_priv * priv_from_xmlDocPtr(const xmlDocPtr doc)
225 return doc->_private;
228 static inline domdoc_properties * properties_from_xmlDocPtr(xmlDocPtr doc)
230 return priv_from_xmlDocPtr(doc)->properties;
233 BOOL is_xpathmode(const xmlDocPtr doc)
235 return properties_from_xmlDocPtr(doc)->XPath;
238 void set_xpathmode(xmlDocPtr doc, BOOL xpath)
240 properties_from_xmlDocPtr(doc)->XPath = xpath;
243 int registerNamespaces(xmlXPathContextPtr ctxt)
245 int n = 0;
246 const select_ns_entry* ns = NULL;
247 const struct list* pNsList = &properties_from_xmlDocPtr(ctxt->doc)->selectNsList;
249 TRACE("(%p)\n", ctxt);
251 LIST_FOR_EACH_ENTRY( ns, pNsList, select_ns_entry, entry )
253 xmlXPathRegisterNs(ctxt, ns->prefix, ns->href);
254 ++n;
257 return n;
260 static inline void clear_selectNsList(struct list* pNsList)
262 select_ns_entry *ns, *ns2;
263 LIST_FOR_EACH_ENTRY_SAFE( ns, ns2, pNsList, select_ns_entry, entry )
265 heap_free( ns );
267 list_init(pNsList);
270 static xmldoc_priv * create_priv(void)
272 xmldoc_priv *priv;
273 priv = heap_alloc( sizeof (*priv) );
275 if (priv)
277 priv->refs = 0;
278 list_init( &priv->orphans );
279 priv->properties = NULL;
282 return priv;
285 static domdoc_properties *create_properties(MSXML_VERSION version)
287 domdoc_properties *properties = heap_alloc(sizeof(domdoc_properties));
289 properties->refs = 1;
290 list_init(&properties->selectNsList);
291 properties->preserving = VARIANT_FALSE;
292 properties->validating = VARIANT_TRUE;
293 properties->schemaCache = NULL;
294 properties->selectNsStr = heap_alloc_zero(sizeof(xmlChar));
295 properties->selectNsStr_len = 0;
297 /* properties that are dependent on object versions */
298 properties->version = version;
299 properties->XPath = (version == MSXML4 || version == MSXML6);
301 /* document uri */
302 properties->uri = NULL;
304 return properties;
307 static domdoc_properties* copy_properties(domdoc_properties const* properties)
309 domdoc_properties* pcopy = heap_alloc(sizeof(domdoc_properties));
310 select_ns_entry const* ns = NULL;
311 select_ns_entry* new_ns = NULL;
312 int len = (properties->selectNsStr_len+1)*sizeof(xmlChar);
313 ptrdiff_t offset;
315 if (pcopy)
317 pcopy->refs = 1;
318 pcopy->version = properties->version;
319 pcopy->preserving = properties->preserving;
320 pcopy->validating = properties->validating;
321 pcopy->schemaCache = properties->schemaCache;
322 if (pcopy->schemaCache)
323 IXMLDOMSchemaCollection2_AddRef(pcopy->schemaCache);
324 pcopy->XPath = properties->XPath;
325 pcopy->selectNsStr_len = properties->selectNsStr_len;
326 list_init( &pcopy->selectNsList );
327 pcopy->selectNsStr = heap_alloc(len);
328 memcpy((xmlChar*)pcopy->selectNsStr, properties->selectNsStr, len);
329 offset = pcopy->selectNsStr - properties->selectNsStr;
331 LIST_FOR_EACH_ENTRY( ns, (&properties->selectNsList), select_ns_entry, entry )
333 new_ns = heap_alloc(sizeof(select_ns_entry));
334 memcpy(new_ns, ns, sizeof(select_ns_entry));
335 new_ns->href += offset;
336 new_ns->prefix += offset;
337 list_add_tail(&pcopy->selectNsList, &new_ns->entry);
340 pcopy->uri = properties->uri;
341 if (pcopy->uri)
342 IUri_AddRef(pcopy->uri);
345 return pcopy;
348 static domdoc_properties * properties_add_ref(domdoc_properties *properties)
350 LONG ref;
352 if (!properties) return NULL;
354 ref = InterlockedIncrement(&properties->refs);
355 TRACE("%p, %ld.\n", properties, ref);
356 return properties;
359 static void properties_release(domdoc_properties *properties)
361 LONG ref;
363 if (!properties) return;
365 ref = InterlockedDecrement(&properties->refs);
367 TRACE("%p, %ld.\n", properties, ref);
369 if (ref < 0)
370 WARN("negative refcount, expect troubles\n");
372 if (ref == 0)
374 if (properties->schemaCache)
375 IXMLDOMSchemaCollection2_Release(properties->schemaCache);
376 clear_selectNsList(&properties->selectNsList);
377 heap_free((xmlChar*)properties->selectNsStr);
378 if (properties->uri)
379 IUri_Release(properties->uri);
380 heap_free(properties);
384 static void release_namespaces(domdoc *This)
386 if (This->namespaces)
388 IXMLDOMSchemaCollection2_Release(This->namespaces);
389 This->namespaces = NULL;
393 /* links a "<?xml" node as a first child */
394 void xmldoc_link_xmldecl(xmlDocPtr doc, xmlNodePtr node)
396 assert(doc != NULL);
397 if (doc->standalone != -1) xmlAddPrevSibling( doc->children, node );
400 /* unlinks a first "<?xml" child if it was created */
401 xmlNodePtr xmldoc_unlink_xmldecl(xmlDocPtr doc)
403 static const xmlChar xmlA[] = "xml";
404 xmlNodePtr node, first_child;
406 assert(doc != NULL);
408 /* xml declaration node could be created automatically after parsing or added
409 to a tree later */
410 first_child = doc->children;
411 if (first_child && first_child->type == XML_PI_NODE && xmlStrEqual(first_child->name, xmlA))
413 node = first_child;
414 xmlUnlinkNode( node );
416 else
417 node = NULL;
419 return node;
422 MSXML_VERSION xmldoc_version(xmlDocPtr doc)
424 return properties_from_xmlDocPtr(doc)->version;
427 BOOL is_preserving_whitespace(xmlNodePtr node)
429 domdoc_properties* properties = NULL;
430 /* during parsing the xmlDoc._private stuff is not there */
431 if (priv_from_xmlDocPtr(node->doc))
432 properties = properties_from_xmlDocPtr(node->doc);
433 return ((properties && properties->preserving == VARIANT_TRUE) ||
434 xmlNodeGetSpacePreserve(node) == 1);
437 static inline BOOL strn_isspace(xmlChar const* str, int len)
439 for (; str && len > 0 && *str; ++str, --len)
440 if (!isspace(*str))
441 break;
443 return len == 0;
446 static void sax_characters(void *ctx, const xmlChar *ch, int len)
448 xmlParserCtxtPtr ctxt;
449 const domdoc *This;
451 ctxt = (xmlParserCtxtPtr) ctx;
452 This = (const domdoc*) ctxt->_private;
454 if (ctxt->node)
456 xmlChar cur = *(ctxt->input->cur);
458 /* Characters are reported with multiple calls, for example each charref is reported with a separate
459 call and then parser appends it to a single text node or creates a new node if not created.
460 It's not possible to tell if it's ignorable data or not just looking at data itself cause it could be
461 space chars that separate charrefs or similar case. We only need to skip leading and trailing spaces,
462 or whole node if it has nothing but space chars, so to detect leading space node->last is checked that
463 contains text node pointer if already created, trailing spaces are detected directly looking at parser input
464 for next '<' opening bracket - similar logic is used by libxml2 itself. Basically 'cur' == '<' means the last
465 chunk of char data, in case it's not the last chunk we check for previously added node type and if it's not
466 a text node it's safe to ignore.
468 Note that during domdoc_loadXML() the xmlDocPtr->_private data is not available. */
470 if (!This->properties->preserving &&
471 !is_preserving_whitespace(ctxt->node) &&
472 strn_isspace(ch, len) &&
473 (!ctxt->node->last ||
474 ((ctxt->node->last && (cur == '<' || ctxt->node->last->type != XML_TEXT_NODE))
477 /* Keep information about ignorable whitespace text node in previous or parent node */
478 if (ctxt->node->last)
479 *(DWORD*)&ctxt->node->last->_private |= NODE_PRIV_TRAILING_IGNORABLE_WS;
480 else if (ctxt->node->type != XML_DOCUMENT_NODE)
481 *(DWORD*)&ctxt->node->_private |= NODE_PRIV_CHILD_IGNORABLE_WS;
482 return;
486 xmlSAX2Characters(ctxt, ch, len);
489 static void LIBXML2_LOG_CALLBACK sax_error(void* ctx, char const* msg, ...)
491 va_list ap;
492 va_start(ap, msg);
493 LIBXML2_CALLBACK_ERR(doparse, msg, ap);
494 va_end(ap);
497 static void LIBXML2_LOG_CALLBACK sax_warning(void* ctx, char const* msg, ...)
499 va_list ap;
500 va_start(ap, msg);
501 LIBXML2_CALLBACK_WARN(doparse, msg, ap);
502 va_end(ap);
505 static void sax_serror(void* ctx, xmlErrorPtr err)
507 LIBXML2_CALLBACK_SERROR(doparse, err);
510 static xmlDocPtr doparse(domdoc* This, char const* ptr, int len, xmlCharEncoding encoding)
512 xmlDocPtr doc = NULL;
513 xmlParserCtxtPtr pctx;
514 static xmlSAXHandler sax_handler = {
515 xmlSAX2InternalSubset, /* internalSubset */
516 xmlSAX2IsStandalone, /* isStandalone */
517 xmlSAX2HasInternalSubset, /* hasInternalSubset */
518 xmlSAX2HasExternalSubset, /* hasExternalSubset */
519 xmlSAX2ResolveEntity, /* resolveEntity */
520 xmlSAX2GetEntity, /* getEntity */
521 xmlSAX2EntityDecl, /* entityDecl */
522 xmlSAX2NotationDecl, /* notationDecl */
523 xmlSAX2AttributeDecl, /* attributeDecl */
524 xmlSAX2ElementDecl, /* elementDecl */
525 xmlSAX2UnparsedEntityDecl, /* unparsedEntityDecl */
526 xmlSAX2SetDocumentLocator, /* setDocumentLocator */
527 xmlSAX2StartDocument, /* startDocument */
528 xmlSAX2EndDocument, /* endDocument */
529 xmlSAX2StartElement, /* startElement */
530 xmlSAX2EndElement, /* endElement */
531 xmlSAX2Reference, /* reference */
532 sax_characters, /* characters */
533 sax_characters, /* ignorableWhitespace */
534 xmlSAX2ProcessingInstruction, /* processingInstruction */
535 xmlSAX2Comment, /* comment */
536 sax_warning, /* warning */
537 sax_error, /* error */
538 sax_error, /* fatalError */
539 xmlSAX2GetParameterEntity, /* getParameterEntity */
540 xmlSAX2CDataBlock, /* cdataBlock */
541 xmlSAX2ExternalSubset, /* externalSubset */
542 0, /* initialized */
543 NULL, /* _private */
544 xmlSAX2StartElementNs, /* startElementNs */
545 xmlSAX2EndElementNs, /* endElementNs */
546 sax_serror /* serror */
549 pctx = xmlCreateMemoryParserCtxt(ptr, len);
550 if (!pctx)
552 ERR("Failed to create parser context\n");
553 return NULL;
556 if (pctx->sax) xmlFree(pctx->sax);
557 pctx->sax = &sax_handler;
558 pctx->_private = This;
559 pctx->recovery = 0;
561 if (encoding != XML_CHAR_ENCODING_NONE)
562 xmlSwitchEncoding(pctx, encoding);
564 xmlParseDocument(pctx);
566 if (pctx->wellFormed)
568 doc = pctx->myDoc;
570 else
572 xmlFreeDoc(pctx->myDoc);
573 pctx->myDoc = NULL;
575 pctx->sax = NULL;
576 xmlFreeParserCtxt(pctx);
578 /* TODO: put this in one of the SAX callbacks */
579 /* create first child as a <?xml...?> */
580 if (doc && doc->standalone != -1)
582 xmlNodePtr node;
583 char buff[30];
584 xmlChar *xmlbuff = (xmlChar*)buff;
586 node = xmlNewDocPI( doc, (xmlChar*)"xml", NULL );
588 /* version attribute can't be omitted */
589 sprintf(buff, "version=\"%s\"", doc->version ? (char*)doc->version : "1.0");
590 xmlNodeAddContent( node, xmlbuff );
592 if (doc->encoding)
594 sprintf(buff, " encoding=\"%s\"", doc->encoding);
595 xmlNodeAddContent( node, xmlbuff );
598 if (doc->standalone != -2)
600 sprintf(buff, " standalone=\"%s\"", doc->standalone == 0 ? "no" : "yes");
601 xmlNodeAddContent( node, xmlbuff );
604 xmldoc_link_xmldecl( doc, node );
607 return doc;
610 void xmldoc_init(xmlDocPtr doc, MSXML_VERSION version)
612 doc->_private = create_priv();
613 priv_from_xmlDocPtr(doc)->properties = create_properties(version);
616 LONG xmldoc_add_refs(xmlDocPtr doc, LONG refs)
618 LONG ref = InterlockedExchangeAdd(&priv_from_xmlDocPtr(doc)->refs, refs) + refs;
619 TRACE("%p, refcount %ld.\n", doc, ref);
620 return ref;
623 LONG xmldoc_add_ref(xmlDocPtr doc)
625 return xmldoc_add_refs(doc, 1);
628 LONG xmldoc_release_refs(xmlDocPtr doc, LONG refs)
630 xmldoc_priv *priv = priv_from_xmlDocPtr(doc);
631 LONG ref = InterlockedExchangeAdd(&priv->refs, -refs) - refs;
633 TRACE("%p, refcount %ld.\n", doc, ref);
635 if (ref < 0)
636 WARN("negative refcount, expect troubles\n");
638 if (ref == 0)
640 orphan_entry *orphan, *orphan2;
641 TRACE("freeing docptr %p\n", doc);
643 LIST_FOR_EACH_ENTRY_SAFE( orphan, orphan2, &priv->orphans, orphan_entry, entry )
645 xmlFreeNode( orphan->node );
646 heap_free( orphan );
648 properties_release(priv->properties);
649 heap_free(doc->_private);
651 xmlFreeDoc(doc);
654 return ref;
657 LONG xmldoc_release(xmlDocPtr doc)
659 return xmldoc_release_refs(doc, 1);
662 HRESULT xmldoc_add_orphan(xmlDocPtr doc, xmlNodePtr node)
664 xmldoc_priv *priv = priv_from_xmlDocPtr(doc);
665 orphan_entry *entry;
667 entry = heap_alloc( sizeof (*entry) );
668 if(!entry)
669 return E_OUTOFMEMORY;
671 entry->node = node;
672 list_add_head( &priv->orphans, &entry->entry );
673 return S_OK;
676 HRESULT xmldoc_remove_orphan(xmlDocPtr doc, xmlNodePtr node)
678 xmldoc_priv *priv = priv_from_xmlDocPtr(doc);
679 orphan_entry *entry, *entry2;
681 LIST_FOR_EACH_ENTRY_SAFE( entry, entry2, &priv->orphans, orphan_entry, entry )
683 if( entry->node == node )
685 list_remove( &entry->entry );
686 heap_free( entry );
687 return S_OK;
691 return S_FALSE;
694 static inline xmlDocPtr get_doc( domdoc *This )
696 return This->node.node->doc;
699 static HRESULT attach_xmldoc(domdoc *This, xmlDocPtr xml )
701 release_namespaces(This);
703 if(This->node.node)
705 properties_release(properties_from_xmlDocPtr(get_doc(This)));
706 priv_from_xmlDocPtr(get_doc(This))->properties = NULL;
707 if (xmldoc_release(get_doc(This)) != 0)
709 /* The xmlDocPtr object can no longer use the properties of this
710 * domdoc object. So give it its own copy.
712 priv_from_xmlDocPtr(get_doc(This))->properties =
713 copy_properties(This->properties);
717 This->node.node = (xmlNodePtr) xml;
719 if(This->node.node)
721 xmldoc_add_ref(get_doc(This));
722 /* Only attach new xmlDocPtr objects, i.e. ones for which properties
723 * is still NULL.
725 priv_from_xmlDocPtr(get_doc(This))->properties = properties_add_ref(This->properties);
728 return S_OK;
731 static inline domdoc *impl_from_IXMLDOMDocument3( IXMLDOMDocument3 *iface )
733 return CONTAINING_RECORD(iface, domdoc, IXMLDOMDocument3_iface);
736 static inline domdoc *impl_from_IPersistStreamInit(IPersistStreamInit *iface)
738 return CONTAINING_RECORD(iface, domdoc, IPersistStreamInit_iface);
741 static inline domdoc *impl_from_IObjectWithSite(IObjectWithSite *iface)
743 return CONTAINING_RECORD(iface, domdoc, IObjectWithSite_iface);
746 static inline domdoc *impl_from_IObjectSafety(IObjectSafety *iface)
748 return CONTAINING_RECORD(iface, domdoc, IObjectSafety_iface);
751 static inline domdoc *impl_from_IConnectionPointContainer(IConnectionPointContainer *iface)
753 return CONTAINING_RECORD(iface, domdoc, IConnectionPointContainer_iface);
756 /************************************************************************
757 * domdoc implementation of IPersistStream.
759 static HRESULT WINAPI PersistStreamInit_QueryInterface(
760 IPersistStreamInit *iface, REFIID riid, void **ppvObj)
762 domdoc* This = impl_from_IPersistStreamInit(iface);
763 return IXMLDOMDocument3_QueryInterface(&This->IXMLDOMDocument3_iface, riid, ppvObj);
766 static ULONG WINAPI PersistStreamInit_AddRef(
767 IPersistStreamInit *iface)
769 domdoc* This = impl_from_IPersistStreamInit(iface);
770 return IXMLDOMDocument3_AddRef(&This->IXMLDOMDocument3_iface);
773 static ULONG WINAPI PersistStreamInit_Release(
774 IPersistStreamInit *iface)
776 domdoc* This = impl_from_IPersistStreamInit(iface);
777 return IXMLDOMDocument3_Release(&This->IXMLDOMDocument3_iface);
780 static HRESULT WINAPI PersistStreamInit_GetClassID(
781 IPersistStreamInit *iface, CLSID *classid)
783 domdoc* This = impl_from_IPersistStreamInit(iface);
784 TRACE("(%p)->(%p)\n", This, classid);
786 if(!classid)
787 return E_POINTER;
789 *classid = *DOMDocument_version(This->properties->version);
791 return S_OK;
794 static HRESULT WINAPI PersistStreamInit_IsDirty(
795 IPersistStreamInit *iface)
797 domdoc *This = impl_from_IPersistStreamInit(iface);
798 FIXME("(%p): stub!\n", This);
799 return S_FALSE;
802 static HRESULT domdoc_load_from_stream(domdoc *doc, ISequentialStream *stream)
804 DWORD read, written, len;
805 xmlDocPtr xmldoc = NULL;
806 IStream *hstream;
807 HGLOBAL hglobal;
808 BYTE buf[4096];
809 HRESULT hr;
810 char *ptr;
812 hstream = NULL;
813 hr = CreateStreamOnHGlobal(NULL, TRUE, &hstream);
814 if (FAILED(hr))
815 return hr;
819 ISequentialStream_Read(stream, buf, sizeof(buf), &read);
820 hr = IStream_Write(hstream, buf, read, &written);
821 } while(SUCCEEDED(hr) && written != 0 && read != 0);
823 if (FAILED(hr))
825 ERR("failed to copy stream, hr %#lx.\n", hr);
826 IStream_Release(hstream);
827 return hr;
830 hr = GetHGlobalFromStream(hstream, &hglobal);
831 if (FAILED(hr))
833 IStream_Release(hstream);
834 return hr;
837 len = GlobalSize(hglobal);
838 ptr = GlobalLock(hglobal);
839 if (len)
840 xmldoc = doparse(doc, ptr, len, XML_CHAR_ENCODING_NONE);
841 GlobalUnlock(hglobal);
842 IStream_Release(hstream);
844 if (!xmldoc)
846 ERR("Failed to parse xml\n");
847 return E_FAIL;
850 xmldoc->_private = create_priv();
852 return attach_xmldoc(doc, xmldoc);
855 static HRESULT WINAPI PersistStreamInit_Load(IPersistStreamInit *iface, IStream *stream)
857 domdoc *This = impl_from_IPersistStreamInit(iface);
859 TRACE("(%p)->(%p)\n", This, stream);
861 if (!stream)
862 return E_INVALIDARG;
864 return This->error = domdoc_load_from_stream(This, (ISequentialStream*)stream);
867 static HRESULT WINAPI PersistStreamInit_Save(
868 IPersistStreamInit *iface, IStream *stream, BOOL clr_dirty)
870 domdoc *This = impl_from_IPersistStreamInit(iface);
871 BSTR xmlString;
872 HRESULT hr;
874 TRACE("(%p)->(%p %d)\n", This, stream, clr_dirty);
876 hr = IXMLDOMDocument3_get_xml(&This->IXMLDOMDocument3_iface, &xmlString);
877 if(hr == S_OK)
879 DWORD len = SysStringLen(xmlString) * sizeof(WCHAR);
881 hr = IStream_Write( stream, xmlString, len, NULL );
882 SysFreeString(xmlString);
885 TRACE("hr %#lx.\n", hr);
887 return hr;
890 static HRESULT WINAPI PersistStreamInit_GetSizeMax(
891 IPersistStreamInit *iface, ULARGE_INTEGER *pcbSize)
893 domdoc *This = impl_from_IPersistStreamInit(iface);
894 TRACE("(%p)->(%p)\n", This, pcbSize);
895 return E_NOTIMPL;
898 static HRESULT WINAPI PersistStreamInit_InitNew(
899 IPersistStreamInit *iface)
901 domdoc *This = impl_from_IPersistStreamInit(iface);
902 TRACE("(%p)\n", This);
903 return S_OK;
906 static const IPersistStreamInitVtbl xmldoc_IPersistStreamInit_VTable =
908 PersistStreamInit_QueryInterface,
909 PersistStreamInit_AddRef,
910 PersistStreamInit_Release,
911 PersistStreamInit_GetClassID,
912 PersistStreamInit_IsDirty,
913 PersistStreamInit_Load,
914 PersistStreamInit_Save,
915 PersistStreamInit_GetSizeMax,
916 PersistStreamInit_InitNew
919 /* IXMLDOMDocument3 interface */
921 static const tid_t domdoc_se_tids[] = {
922 IXMLDOMNode_tid,
923 IXMLDOMDocument_tid,
924 IXMLDOMDocument2_tid,
925 IXMLDOMDocument3_tid,
926 NULL_tid
929 static HRESULT WINAPI domdoc_QueryInterface( IXMLDOMDocument3 *iface, REFIID riid, void** ppvObject )
931 domdoc *This = impl_from_IXMLDOMDocument3( iface );
933 TRACE("(%p)->(%s %p)\n", This, debugstr_guid( riid ), ppvObject );
935 *ppvObject = NULL;
937 if ( IsEqualGUID( riid, &IID_IUnknown ) ||
938 IsEqualGUID( riid, &IID_IDispatch ) ||
939 IsEqualGUID( riid, &IID_IXMLDOMNode ) ||
940 IsEqualGUID( riid, &IID_IXMLDOMDocument ) ||
941 IsEqualGUID( riid, &IID_IXMLDOMDocument2 )||
942 IsEqualGUID( riid, &IID_IXMLDOMDocument3 ))
944 *ppvObject = iface;
946 else if (IsEqualGUID(&IID_IPersistStream, riid) ||
947 IsEqualGUID(&IID_IPersistStreamInit, riid))
949 *ppvObject = &This->IPersistStreamInit_iface;
951 else if (IsEqualGUID(&IID_IObjectWithSite, riid))
953 *ppvObject = &This->IObjectWithSite_iface;
955 else if (IsEqualGUID(&IID_IObjectSafety, riid))
957 *ppvObject = &This->IObjectSafety_iface;
959 else if( IsEqualGUID( riid, &IID_ISupportErrorInfo ))
961 return node_create_supporterrorinfo(domdoc_se_tids, ppvObject);
963 else if(node_query_interface(&This->node, riid, ppvObject))
965 return *ppvObject ? S_OK : E_NOINTERFACE;
967 else if (IsEqualGUID( riid, &IID_IConnectionPointContainer ))
969 *ppvObject = &This->IConnectionPointContainer_iface;
971 else
973 TRACE("interface %s not implemented\n", debugstr_guid(riid));
974 return E_NOINTERFACE;
977 IUnknown_AddRef((IUnknown*)*ppvObject);
979 return S_OK;
982 static ULONG WINAPI domdoc_AddRef( IXMLDOMDocument3 *iface )
984 domdoc *doc = impl_from_IXMLDOMDocument3(iface);
985 ULONG ref = InterlockedIncrement(&doc->ref);
986 TRACE("%p, refcount %ld.\n", iface, ref);
987 return ref;
990 static ULONG WINAPI domdoc_Release( IXMLDOMDocument3 *iface )
992 domdoc *This = impl_from_IXMLDOMDocument3( iface );
993 LONG ref = InterlockedDecrement( &This->ref );
995 TRACE("%p, refcount %ld.\n", iface, ref);
997 if (!ref)
999 int eid;
1001 if (This->site)
1002 IUnknown_Release( This->site );
1003 if (This->base_uri)
1004 IUri_Release( This->base_uri );
1005 destroy_xmlnode(&This->node);
1007 for (eid = 0; eid < EVENTID_LAST; eid++)
1008 if (This->events[eid]) IDispatch_Release(This->events[eid]);
1010 properties_release(This->properties);
1011 release_namespaces(This);
1012 heap_free(This);
1015 return ref;
1018 static HRESULT WINAPI domdoc_GetTypeInfoCount( IXMLDOMDocument3 *iface, UINT* pctinfo )
1020 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1021 return IDispatchEx_GetTypeInfoCount(&This->node.dispex.IDispatchEx_iface, pctinfo);
1024 static HRESULT WINAPI domdoc_GetTypeInfo(
1025 IXMLDOMDocument3 *iface,
1026 UINT iTInfo, LCID lcid, ITypeInfo** ppTInfo )
1028 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1029 return IDispatchEx_GetTypeInfo(&This->node.dispex.IDispatchEx_iface, iTInfo, lcid, ppTInfo);
1032 static HRESULT WINAPI domdoc_GetIDsOfNames(
1033 IXMLDOMDocument3 *iface,
1034 REFIID riid,
1035 LPOLESTR* rgszNames,
1036 UINT cNames,
1037 LCID lcid,
1038 DISPID* rgDispId)
1040 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1041 return IDispatchEx_GetIDsOfNames(&This->node.dispex.IDispatchEx_iface,
1042 riid, rgszNames, cNames, lcid, rgDispId);
1045 static HRESULT WINAPI domdoc_Invoke(
1046 IXMLDOMDocument3 *iface,
1047 DISPID dispIdMember,
1048 REFIID riid,
1049 LCID lcid,
1050 WORD wFlags,
1051 DISPPARAMS* pDispParams,
1052 VARIANT* pVarResult,
1053 EXCEPINFO* pExcepInfo,
1054 UINT* puArgErr)
1056 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1057 return IDispatchEx_Invoke(&This->node.dispex.IDispatchEx_iface,
1058 dispIdMember, riid, lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
1061 static HRESULT WINAPI domdoc_get_nodeName(
1062 IXMLDOMDocument3 *iface,
1063 BSTR* name )
1065 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1067 static const WCHAR documentW[] = {'#','d','o','c','u','m','e','n','t',0};
1069 TRACE("(%p)->(%p)\n", This, name);
1071 return return_bstr(documentW, name);
1075 static HRESULT WINAPI domdoc_get_nodeValue(
1076 IXMLDOMDocument3 *iface,
1077 VARIANT* value )
1079 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1081 TRACE("(%p)->(%p)\n", This, value);
1083 if(!value)
1084 return E_INVALIDARG;
1086 V_VT(value) = VT_NULL;
1087 V_BSTR(value) = NULL; /* tests show that we should do this */
1088 return S_FALSE;
1092 static HRESULT WINAPI domdoc_put_nodeValue(
1093 IXMLDOMDocument3 *iface,
1094 VARIANT value)
1096 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1097 TRACE("(%p)->(%s)\n", This, debugstr_variant(&value));
1098 return E_FAIL;
1102 static HRESULT WINAPI domdoc_get_nodeType(
1103 IXMLDOMDocument3 *iface,
1104 DOMNodeType* type )
1106 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1108 TRACE("(%p)->(%p)\n", This, type);
1110 *type = NODE_DOCUMENT;
1111 return S_OK;
1115 static HRESULT WINAPI domdoc_get_parentNode(
1116 IXMLDOMDocument3 *iface,
1117 IXMLDOMNode** parent )
1119 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1121 TRACE("(%p)->(%p)\n", This, parent);
1123 return node_get_parent(&This->node, parent);
1127 static HRESULT WINAPI domdoc_get_childNodes(
1128 IXMLDOMDocument3 *iface,
1129 IXMLDOMNodeList** childList )
1131 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1133 TRACE("(%p)->(%p)\n", This, childList);
1135 return node_get_child_nodes(&This->node, childList);
1139 static HRESULT WINAPI domdoc_get_firstChild(
1140 IXMLDOMDocument3 *iface,
1141 IXMLDOMNode** firstChild )
1143 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1145 TRACE("(%p)->(%p)\n", This, firstChild);
1147 return node_get_first_child(&This->node, firstChild);
1151 static HRESULT WINAPI domdoc_get_lastChild(
1152 IXMLDOMDocument3 *iface,
1153 IXMLDOMNode** lastChild )
1155 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1157 TRACE("(%p)->(%p)\n", This, lastChild);
1159 return node_get_last_child(&This->node, lastChild);
1163 static HRESULT WINAPI domdoc_get_previousSibling(
1164 IXMLDOMDocument3 *iface,
1165 IXMLDOMNode** previousSibling )
1167 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1169 TRACE("(%p)->(%p)\n", This, previousSibling);
1171 return return_null_node(previousSibling);
1175 static HRESULT WINAPI domdoc_get_nextSibling(
1176 IXMLDOMDocument3 *iface,
1177 IXMLDOMNode** nextSibling )
1179 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1181 TRACE("(%p)->(%p)\n", This, nextSibling);
1183 return return_null_node(nextSibling);
1187 static HRESULT WINAPI domdoc_get_attributes(
1188 IXMLDOMDocument3 *iface,
1189 IXMLDOMNamedNodeMap** attributeMap )
1191 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1193 TRACE("(%p)->(%p)\n", This, attributeMap);
1195 return return_null_ptr((void**)attributeMap);
1199 static HRESULT WINAPI domdoc_insertBefore(
1200 IXMLDOMDocument3 *iface,
1201 IXMLDOMNode* newChild,
1202 VARIANT refChild,
1203 IXMLDOMNode** outNewChild )
1205 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1206 DOMNodeType type;
1207 HRESULT hr;
1209 TRACE("(%p)->(%p %s %p)\n", This, newChild, debugstr_variant(&refChild), outNewChild);
1211 if (!newChild) return E_INVALIDARG;
1213 hr = IXMLDOMNode_get_nodeType(newChild, &type);
1214 if (hr != S_OK) return hr;
1216 TRACE("new node type %d\n", type);
1217 switch (type)
1219 case NODE_ATTRIBUTE:
1220 case NODE_DOCUMENT:
1221 case NODE_CDATA_SECTION:
1222 if (outNewChild) *outNewChild = NULL;
1223 return E_FAIL;
1224 default:
1225 return node_insert_before(&This->node, newChild, &refChild, outNewChild);
1229 static HRESULT WINAPI domdoc_replaceChild(
1230 IXMLDOMDocument3 *iface,
1231 IXMLDOMNode* newChild,
1232 IXMLDOMNode* oldChild,
1233 IXMLDOMNode** outOldChild)
1235 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1237 TRACE("(%p)->(%p %p %p)\n", This, newChild, oldChild, outOldChild);
1239 return node_replace_child(&This->node, newChild, oldChild, outOldChild);
1243 static HRESULT WINAPI domdoc_removeChild(
1244 IXMLDOMDocument3 *iface,
1245 IXMLDOMNode *child,
1246 IXMLDOMNode **oldChild)
1248 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1249 TRACE("(%p)->(%p %p)\n", This, child, oldChild);
1250 return node_remove_child(&This->node, child, oldChild);
1254 static HRESULT WINAPI domdoc_appendChild(
1255 IXMLDOMDocument3 *iface,
1256 IXMLDOMNode *child,
1257 IXMLDOMNode **outChild)
1259 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1260 TRACE("(%p)->(%p %p)\n", This, child, outChild);
1261 return node_append_child(&This->node, child, outChild);
1265 static HRESULT WINAPI domdoc_hasChildNodes(
1266 IXMLDOMDocument3 *iface,
1267 VARIANT_BOOL *ret)
1269 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1270 TRACE("(%p)->(%p)\n", This, ret);
1271 return node_has_childnodes(&This->node, ret);
1275 static HRESULT WINAPI domdoc_get_ownerDocument(
1276 IXMLDOMDocument3 *iface,
1277 IXMLDOMDocument **doc)
1279 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1280 TRACE("(%p)->(%p)\n", This, doc);
1281 return node_get_owner_doc(&This->node, doc);
1285 static HRESULT WINAPI domdoc_cloneNode(
1286 IXMLDOMDocument3 *iface,
1287 VARIANT_BOOL deep,
1288 IXMLDOMNode** outNode)
1290 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1291 xmlNodePtr clone;
1293 TRACE("(%p)->(%d %p)\n", This, deep, outNode);
1295 if (!outNode)
1296 return E_INVALIDARG;
1298 *outNode = NULL;
1300 clone = xmlCopyNode((xmlNodePtr)get_doc(This), deep ? 1 : 2);
1301 if (!clone)
1302 return E_FAIL;
1304 clone->doc->_private = create_priv();
1305 xmldoc_add_orphan(clone->doc, clone);
1306 xmldoc_add_ref(clone->doc);
1308 priv_from_xmlDocPtr(clone->doc)->properties = copy_properties(This->properties);
1309 if (!(*outNode = (IXMLDOMNode*)create_domdoc(clone)))
1311 xmldoc_release(clone->doc);
1312 return E_FAIL;
1315 return S_OK;
1319 static HRESULT WINAPI domdoc_get_nodeTypeString(
1320 IXMLDOMDocument3 *iface,
1321 BSTR *p)
1323 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1324 static const WCHAR documentW[] = {'d','o','c','u','m','e','n','t',0};
1326 TRACE("(%p)->(%p)\n", This, p);
1328 return return_bstr(documentW, p);
1332 static HRESULT WINAPI domdoc_get_text(
1333 IXMLDOMDocument3 *iface,
1334 BSTR *p)
1336 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1337 TRACE("(%p)->(%p)\n", This, p);
1338 return node_get_text(&This->node, p);
1342 static HRESULT WINAPI domdoc_put_text(
1343 IXMLDOMDocument3 *iface,
1344 BSTR text )
1346 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1347 TRACE("(%p)->(%s)\n", This, debugstr_w(text));
1348 return E_FAIL;
1352 static HRESULT WINAPI domdoc_get_specified(
1353 IXMLDOMDocument3 *iface,
1354 VARIANT_BOOL* isSpecified )
1356 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1357 FIXME("(%p)->(%p) stub!\n", This, isSpecified);
1358 *isSpecified = VARIANT_TRUE;
1359 return S_OK;
1363 static HRESULT WINAPI domdoc_get_definition(
1364 IXMLDOMDocument3 *iface,
1365 IXMLDOMNode** definitionNode )
1367 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1368 FIXME("(%p)->(%p)\n", This, definitionNode);
1369 return E_NOTIMPL;
1373 static HRESULT WINAPI domdoc_get_nodeTypedValue(
1374 IXMLDOMDocument3 *iface,
1375 VARIANT* v )
1377 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1378 TRACE("(%p)->(%p)\n", This, v);
1379 return return_null_var(v);
1382 static HRESULT WINAPI domdoc_put_nodeTypedValue(
1383 IXMLDOMDocument3 *iface,
1384 VARIANT typedValue )
1386 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1387 FIXME("(%p)->(%s)\n", This, debugstr_variant(&typedValue));
1388 return E_NOTIMPL;
1392 static HRESULT WINAPI domdoc_get_dataType(
1393 IXMLDOMDocument3 *iface,
1394 VARIANT* typename )
1396 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1397 TRACE("(%p)->(%p)\n", This, typename);
1398 return return_null_var( typename );
1402 static HRESULT WINAPI domdoc_put_dataType(
1403 IXMLDOMDocument3 *iface,
1404 BSTR dataTypeName )
1406 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1408 FIXME("(%p)->(%s)\n", This, debugstr_w(dataTypeName));
1410 if(!dataTypeName)
1411 return E_INVALIDARG;
1413 return E_FAIL;
1416 static int XMLCALL domdoc_get_xml_writecallback(void *ctx, const char *data, int len)
1418 return xmlBufferAdd((xmlBufferPtr)ctx, (xmlChar*)data, len) == 0 ? len : 0;
1421 static HRESULT WINAPI domdoc_get_xml(
1422 IXMLDOMDocument3 *iface,
1423 BSTR* p)
1425 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1426 xmlSaveCtxtPtr ctxt;
1427 xmlBufferPtr buf;
1428 int options;
1429 long ret;
1431 TRACE("(%p)->(%p)\n", This, p);
1433 if(!p)
1434 return E_INVALIDARG;
1436 *p = NULL;
1438 buf = xmlBufferCreate();
1439 if(!buf)
1440 return E_OUTOFMEMORY;
1442 options = XML_SAVE_FORMAT | XML_SAVE_NO_DECL;
1443 ctxt = xmlSaveToIO(domdoc_get_xml_writecallback, NULL, buf, "UTF-8", options);
1445 if(!ctxt)
1447 xmlBufferFree(buf);
1448 return E_OUTOFMEMORY;
1451 ret = xmlSaveDoc(ctxt, get_doc(This));
1452 /* flushes on close */
1453 xmlSaveClose(ctxt);
1455 TRACE("%ld, len=%d\n", ret, xmlBufferLength(buf));
1456 if(ret != -1 && xmlBufferLength(buf) > 0)
1458 BSTR content;
1460 content = bstr_from_xmlChar(xmlBufferContent(buf));
1461 content = EnsureCorrectEOL(content);
1463 *p = content;
1465 else
1467 *p = SysAllocStringLen(NULL, 0);
1470 xmlBufferFree(buf);
1472 return *p ? S_OK : E_OUTOFMEMORY;
1476 static HRESULT WINAPI domdoc_transformNode(
1477 IXMLDOMDocument3 *iface,
1478 IXMLDOMNode *node,
1479 BSTR *p)
1481 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1482 TRACE("(%p)->(%p %p)\n", This, node, p);
1483 return node_transform_node(&This->node, node, p);
1487 static HRESULT WINAPI domdoc_selectNodes(
1488 IXMLDOMDocument3 *iface,
1489 BSTR p,
1490 IXMLDOMNodeList **outList)
1492 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1493 TRACE("(%p)->(%s %p)\n", This, debugstr_w(p), outList);
1494 return node_select_nodes(&This->node, p, outList);
1498 static HRESULT WINAPI domdoc_selectSingleNode(
1499 IXMLDOMDocument3 *iface,
1500 BSTR p,
1501 IXMLDOMNode **outNode)
1503 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1504 TRACE("(%p)->(%s %p)\n", This, debugstr_w(p), outNode);
1505 return node_select_singlenode(&This->node, p, outNode);
1509 static HRESULT WINAPI domdoc_get_parsed(
1510 IXMLDOMDocument3 *iface,
1511 VARIANT_BOOL* isParsed )
1513 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1514 FIXME("(%p)->(%p) stub!\n", This, isParsed);
1515 *isParsed = VARIANT_TRUE;
1516 return S_OK;
1519 static HRESULT WINAPI domdoc_get_namespaceURI(
1520 IXMLDOMDocument3 *iface,
1521 BSTR* namespaceURI )
1523 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1524 TRACE("(%p)->(%p)\n", This, namespaceURI);
1525 return return_null_bstr( namespaceURI );
1528 static HRESULT WINAPI domdoc_get_prefix(
1529 IXMLDOMDocument3 *iface,
1530 BSTR* prefix )
1532 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1533 TRACE("(%p)->(%p)\n", This, prefix);
1534 return return_null_bstr( prefix );
1538 static HRESULT WINAPI domdoc_get_baseName(
1539 IXMLDOMDocument3 *iface,
1540 BSTR* name )
1542 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1543 TRACE("(%p)->(%p)\n", This, name);
1544 return return_null_bstr( name );
1548 static HRESULT WINAPI domdoc_transformNodeToObject(
1549 IXMLDOMDocument3 *iface,
1550 IXMLDOMNode* stylesheet,
1551 VARIANT output)
1553 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1555 TRACE("(%p)->(%p %s)\n", This, stylesheet, debugstr_variant(&output));
1557 switch (V_VT(&output))
1559 case VT_UNKNOWN:
1560 case VT_DISPATCH:
1562 ISequentialStream *stream;
1563 IXMLDOMDocument *doc;
1564 HRESULT hr;
1565 BSTR str;
1567 if (!V_UNKNOWN(&output))
1568 return E_INVALIDARG;
1570 /* FIXME: we're not supposed to query for document interface, should use IStream
1571 which we don't support currently. */
1572 if (IUnknown_QueryInterface(V_UNKNOWN(&output), &IID_IXMLDOMDocument, (void **)&doc) == S_OK)
1574 VARIANT_BOOL b;
1576 if (FAILED(hr = node_transform_node(&This->node, stylesheet, &str)))
1577 return hr;
1579 hr = IXMLDOMDocument_loadXML(doc, str, &b);
1580 SysFreeString(str);
1581 return hr;
1583 else if (IUnknown_QueryInterface(V_UNKNOWN(&output), &IID_ISequentialStream, (void**)&stream) == S_OK)
1585 hr = node_transform_node_params(&This->node, stylesheet, NULL, stream, NULL);
1586 ISequentialStream_Release(stream);
1587 return hr;
1589 else
1591 FIXME("Unsupported destination type.\n");
1592 return E_INVALIDARG;
1595 default:
1596 FIXME("Output type %d not handled.\n", V_VT(&output));
1597 return E_NOTIMPL;
1600 return E_NOTIMPL;
1604 static HRESULT WINAPI domdoc_get_doctype(
1605 IXMLDOMDocument3 *iface,
1606 IXMLDOMDocumentType** doctype )
1608 domdoc *This = impl_from_IXMLDOMDocument3(iface);
1609 IXMLDOMNode *node;
1610 xmlDtdPtr dtd;
1611 HRESULT hr;
1613 TRACE("(%p)->(%p)\n", This, doctype);
1615 if (!doctype) return E_INVALIDARG;
1617 *doctype = NULL;
1619 dtd = xmlGetIntSubset(get_doc(This));
1620 if (!dtd) return S_FALSE;
1622 node = create_node((xmlNodePtr)dtd);
1623 if (!node) return S_FALSE;
1625 hr = IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMDocumentType, (void**)doctype);
1626 IXMLDOMNode_Release(node);
1628 return hr;
1632 static HRESULT WINAPI domdoc_get_implementation(
1633 IXMLDOMDocument3 *iface,
1634 IXMLDOMImplementation** impl )
1636 domdoc *This = impl_from_IXMLDOMDocument3(iface);
1638 TRACE("(%p)->(%p)\n", This, impl);
1640 if(!impl)
1641 return E_INVALIDARG;
1643 return create_dom_implementation(impl);
1646 static HRESULT WINAPI domdoc_get_documentElement(
1647 IXMLDOMDocument3 *iface,
1648 IXMLDOMElement** DOMElement )
1650 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1651 IXMLDOMNode *element_node;
1652 xmlNodePtr root;
1653 HRESULT hr;
1655 TRACE("(%p)->(%p)\n", This, DOMElement);
1657 if(!DOMElement)
1658 return E_INVALIDARG;
1660 *DOMElement = NULL;
1662 root = xmlDocGetRootElement( get_doc(This) );
1663 if ( !root )
1664 return S_FALSE;
1666 element_node = create_node( root );
1667 if(!element_node) return S_FALSE;
1669 hr = IXMLDOMNode_QueryInterface(element_node, &IID_IXMLDOMElement, (void**)DOMElement);
1670 IXMLDOMNode_Release(element_node);
1672 return hr;
1676 static HRESULT WINAPI domdoc_put_documentElement(
1677 IXMLDOMDocument3 *iface,
1678 IXMLDOMElement* DOMElement )
1680 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1681 IXMLDOMNode *elementNode;
1682 xmlNodePtr oldRoot;
1683 xmlDocPtr old_doc;
1684 xmlnode *xmlNode;
1685 int refcount = 0;
1686 HRESULT hr;
1688 TRACE("(%p)->(%p)\n", This, DOMElement);
1690 hr = IXMLDOMElement_QueryInterface( DOMElement, &IID_IXMLDOMNode, (void**)&elementNode );
1691 if(FAILED(hr))
1692 return hr;
1694 xmlNode = get_node_obj( elementNode );
1695 if(!xmlNode) return E_FAIL;
1697 if(!xmlNode->node->parent)
1698 if(xmldoc_remove_orphan(xmlNode->node->doc, xmlNode->node) != S_OK)
1699 WARN("%p is not an orphan of %p\n", xmlNode->node->doc, xmlNode->node);
1701 old_doc = xmlNode->node->doc;
1702 if (old_doc != get_doc(This))
1703 refcount = xmlnode_get_inst_cnt(xmlNode);
1705 /* old root is still orphaned by its document, update refcount from new root */
1706 if (refcount) xmldoc_add_refs(get_doc(This), refcount);
1707 oldRoot = xmlDocSetRootElement( get_doc(This), xmlNode->node);
1708 if (refcount) xmldoc_release_refs(old_doc, refcount);
1709 IXMLDOMNode_Release( elementNode );
1711 if(oldRoot)
1712 xmldoc_add_orphan(oldRoot->doc, oldRoot);
1714 return S_OK;
1718 static HRESULT WINAPI domdoc_createElement(
1719 IXMLDOMDocument3 *iface,
1720 BSTR tagname,
1721 IXMLDOMElement** element )
1723 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1724 IXMLDOMNode *node;
1725 VARIANT type;
1726 HRESULT hr;
1728 TRACE("(%p)->(%s %p)\n", This, debugstr_w(tagname), element);
1730 if (!element || !tagname) return E_INVALIDARG;
1732 V_VT(&type) = VT_I1;
1733 V_I1(&type) = NODE_ELEMENT;
1735 hr = IXMLDOMDocument3_createNode(iface, type, tagname, NULL, &node);
1736 if (hr == S_OK)
1738 IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMElement, (void**)element);
1739 IXMLDOMNode_Release(node);
1742 return hr;
1746 static HRESULT WINAPI domdoc_createDocumentFragment(
1747 IXMLDOMDocument3 *iface,
1748 IXMLDOMDocumentFragment** frag )
1750 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1751 IXMLDOMNode *node;
1752 VARIANT type;
1753 HRESULT hr;
1755 TRACE("(%p)->(%p)\n", This, frag);
1757 if (!frag) return E_INVALIDARG;
1759 *frag = NULL;
1761 V_VT(&type) = VT_I1;
1762 V_I1(&type) = NODE_DOCUMENT_FRAGMENT;
1764 hr = IXMLDOMDocument3_createNode(iface, type, NULL, NULL, &node);
1765 if (hr == S_OK)
1767 IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMDocumentFragment, (void**)frag);
1768 IXMLDOMNode_Release(node);
1771 return hr;
1775 static HRESULT WINAPI domdoc_createTextNode(
1776 IXMLDOMDocument3 *iface,
1777 BSTR data,
1778 IXMLDOMText** text )
1780 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1781 IXMLDOMNode *node;
1782 VARIANT type;
1783 HRESULT hr;
1785 TRACE("(%p)->(%s %p)\n", This, debugstr_w(data), text);
1787 if (!text) return E_INVALIDARG;
1789 *text = NULL;
1791 V_VT(&type) = VT_I1;
1792 V_I1(&type) = NODE_TEXT;
1794 hr = IXMLDOMDocument3_createNode(iface, type, NULL, NULL, &node);
1795 if (hr == S_OK)
1797 IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMText, (void**)text);
1798 IXMLDOMNode_Release(node);
1799 hr = IXMLDOMText_put_data(*text, data);
1802 return hr;
1806 static HRESULT WINAPI domdoc_createComment(
1807 IXMLDOMDocument3 *iface,
1808 BSTR data,
1809 IXMLDOMComment** comment )
1811 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1812 VARIANT type;
1813 HRESULT hr;
1814 IXMLDOMNode *node;
1816 TRACE("(%p)->(%s %p)\n", This, debugstr_w(data), comment);
1818 if (!comment) return E_INVALIDARG;
1820 *comment = NULL;
1822 V_VT(&type) = VT_I1;
1823 V_I1(&type) = NODE_COMMENT;
1825 hr = IXMLDOMDocument3_createNode(iface, type, NULL, NULL, &node);
1826 if (hr == S_OK)
1828 IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMComment, (void**)comment);
1829 IXMLDOMNode_Release(node);
1830 hr = IXMLDOMComment_put_data(*comment, data);
1833 return hr;
1837 static HRESULT WINAPI domdoc_createCDATASection(
1838 IXMLDOMDocument3 *iface,
1839 BSTR data,
1840 IXMLDOMCDATASection** cdata )
1842 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1843 IXMLDOMNode *node;
1844 VARIANT type;
1845 HRESULT hr;
1847 TRACE("(%p)->(%s %p)\n", This, debugstr_w(data), cdata);
1849 if (!cdata) return E_INVALIDARG;
1851 *cdata = NULL;
1853 V_VT(&type) = VT_I1;
1854 V_I1(&type) = NODE_CDATA_SECTION;
1856 hr = IXMLDOMDocument3_createNode(iface, type, NULL, NULL, &node);
1857 if (hr == S_OK)
1859 IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMCDATASection, (void**)cdata);
1860 IXMLDOMNode_Release(node);
1861 hr = IXMLDOMCDATASection_put_data(*cdata, data);
1864 return hr;
1868 static HRESULT WINAPI domdoc_createProcessingInstruction(
1869 IXMLDOMDocument3 *iface,
1870 BSTR target,
1871 BSTR data,
1872 IXMLDOMProcessingInstruction** pi )
1874 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1875 IXMLDOMNode *node;
1876 VARIANT type;
1877 HRESULT hr;
1879 TRACE("(%p)->(%s %s %p)\n", This, debugstr_w(target), debugstr_w(data), pi);
1881 if (!pi) return E_INVALIDARG;
1883 *pi = NULL;
1885 V_VT(&type) = VT_I1;
1886 V_I1(&type) = NODE_PROCESSING_INSTRUCTION;
1888 hr = IXMLDOMDocument3_createNode(iface, type, target, NULL, &node);
1889 if (hr == S_OK)
1891 /* this is to bypass check in ::put_data() that blocks "<?xml" PIs */
1892 hr = dom_pi_put_xml_decl(node, data);
1893 if (SUCCEEDED(hr))
1894 hr = IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMProcessingInstruction, (void**)pi);
1895 IXMLDOMNode_Release(node);
1898 return hr;
1902 static HRESULT WINAPI domdoc_createAttribute(
1903 IXMLDOMDocument3 *iface,
1904 BSTR name,
1905 IXMLDOMAttribute** attribute )
1907 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1908 IXMLDOMNode *node;
1909 VARIANT type;
1910 HRESULT hr;
1912 TRACE("(%p)->(%s %p)\n", This, debugstr_w(name), attribute);
1914 if (!attribute || !name) return E_INVALIDARG;
1916 V_VT(&type) = VT_I1;
1917 V_I1(&type) = NODE_ATTRIBUTE;
1919 hr = IXMLDOMDocument3_createNode(iface, type, name, NULL, &node);
1920 if (hr == S_OK)
1922 IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMAttribute, (void**)attribute);
1923 IXMLDOMNode_Release(node);
1926 return hr;
1930 static HRESULT WINAPI domdoc_createEntityReference(
1931 IXMLDOMDocument3 *iface,
1932 BSTR name,
1933 IXMLDOMEntityReference** entityref )
1935 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1936 IXMLDOMNode *node;
1937 VARIANT type;
1938 HRESULT hr;
1940 TRACE("(%p)->(%s %p)\n", This, debugstr_w(name), entityref);
1942 if (!entityref) return E_INVALIDARG;
1944 *entityref = NULL;
1946 V_VT(&type) = VT_I1;
1947 V_I1(&type) = NODE_ENTITY_REFERENCE;
1949 hr = IXMLDOMDocument3_createNode(iface, type, name, NULL, &node);
1950 if (hr == S_OK)
1952 IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMEntityReference, (void**)entityref);
1953 IXMLDOMNode_Release(node);
1956 return hr;
1959 xmlChar* tagName_to_XPath(const BSTR tagName)
1961 xmlChar *query, *tmp;
1962 static const xmlChar everything[] = "/descendant::node()";
1963 static const xmlChar mod_pre[] = "*[local-name()='";
1964 static const xmlChar mod_post[] = "']";
1965 static const xmlChar prefix[] = "descendant::";
1966 const WCHAR *tokBegin, *tokEnd;
1967 int len;
1969 /* Special case - empty tagname - means select all nodes,
1970 except document itself. */
1971 if (!*tagName)
1972 return xmlStrdup(everything);
1974 query = xmlStrdup(prefix);
1976 tokBegin = tagName;
1977 while (tokBegin && *tokBegin)
1979 switch (*tokBegin)
1981 case '/':
1982 query = xmlStrcat(query, BAD_CAST "/");
1983 ++tokBegin;
1984 break;
1985 case '*':
1986 query = xmlStrcat(query, BAD_CAST "*");
1987 ++tokBegin;
1988 break;
1989 default:
1990 query = xmlStrcat(query, mod_pre);
1991 tokEnd = tokBegin;
1992 while (*tokEnd && *tokEnd != '/')
1993 ++tokEnd;
1994 len = WideCharToMultiByte(CP_UTF8, 0, tokBegin, tokEnd-tokBegin, NULL, 0, NULL, NULL);
1995 tmp = xmlMalloc(len);
1996 WideCharToMultiByte(CP_UTF8, 0, tokBegin, tokEnd-tokBegin, (char*)tmp, len, NULL, NULL);
1997 query = xmlStrncat(query, tmp, len);
1998 xmlFree(tmp);
1999 tokBegin = tokEnd;
2000 query = xmlStrcat(query, mod_post);
2004 return query;
2007 static HRESULT WINAPI domdoc_getElementsByTagName(
2008 IXMLDOMDocument3 *iface,
2009 BSTR tagName,
2010 IXMLDOMNodeList** resultList )
2012 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2013 xmlChar *query;
2014 HRESULT hr;
2015 BOOL XPath;
2017 TRACE("(%p)->(%s, %p)\n", This, debugstr_w(tagName), resultList);
2019 if (!tagName || !resultList) return E_INVALIDARG;
2021 XPath = This->properties->XPath;
2022 This->properties->XPath = TRUE;
2023 query = tagName_to_XPath(tagName);
2024 hr = create_selection((xmlNodePtr)get_doc(This), query, resultList);
2025 xmlFree(query);
2026 This->properties->XPath = XPath;
2028 return hr;
2031 static HRESULT get_node_type(VARIANT Type, DOMNodeType * type)
2033 VARIANT tmp;
2034 HRESULT hr;
2036 VariantInit(&tmp);
2037 hr = VariantChangeType(&tmp, &Type, 0, VT_I4);
2038 if(FAILED(hr))
2039 return E_INVALIDARG;
2041 *type = V_I4(&tmp);
2043 return S_OK;
2046 static HRESULT WINAPI domdoc_createNode(
2047 IXMLDOMDocument3 *iface,
2048 VARIANT Type,
2049 BSTR name,
2050 BSTR namespaceURI,
2051 IXMLDOMNode** node )
2053 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2054 DOMNodeType node_type;
2055 xmlNodePtr xmlnode;
2056 xmlChar *xml_name, *href;
2057 HRESULT hr;
2059 TRACE("(%p)->(%s %s %s %p)\n", This, debugstr_variant(&Type), debugstr_w(name), debugstr_w(namespaceURI), node);
2061 if(!node) return E_INVALIDARG;
2063 hr = get_node_type(Type, &node_type);
2064 if(FAILED(hr)) return hr;
2066 TRACE("node_type %d\n", node_type);
2068 /* exit earlier for types that need name */
2069 switch(node_type)
2071 case NODE_ELEMENT:
2072 case NODE_ATTRIBUTE:
2073 case NODE_ENTITY_REFERENCE:
2074 case NODE_PROCESSING_INSTRUCTION:
2075 if (!name || *name == 0) return E_FAIL;
2076 break;
2077 default:
2078 break;
2081 xml_name = xmlchar_from_wchar(name);
2082 /* prevent empty href from being allocated */
2083 href = namespaceURI ? xmlchar_from_wchar(namespaceURI) : NULL;
2085 switch(node_type)
2087 case NODE_ELEMENT:
2089 xmlChar *local, *prefix;
2091 local = xmlSplitQName2(xml_name, &prefix);
2093 xmlnode = xmlNewDocNode(get_doc(This), NULL, local ? local : xml_name, NULL);
2095 /* allow creating the default namespace xmlns= */
2096 if (local || (href && *href))
2098 xmlNsPtr ns = xmlNewNs(xmlnode, href, prefix);
2099 xmlSetNs(xmlnode, ns);
2102 xmlFree(local);
2103 xmlFree(prefix);
2105 break;
2107 case NODE_ATTRIBUTE:
2109 xmlChar *local, *prefix;
2111 local = xmlSplitQName2(xml_name, &prefix);
2113 xmlnode = (xmlNodePtr)xmlNewDocProp(get_doc(This), local ? local : xml_name, NULL);
2115 if (local || (href && *href))
2117 /* we need a floating namespace here, it can't be created linked to attribute from
2118 a start */
2119 xmlNsPtr ns = xmlNewNs(NULL, href, prefix);
2120 xmlSetNs(xmlnode, ns);
2123 xmlFree(local);
2124 xmlFree(prefix);
2126 break;
2128 case NODE_TEXT:
2129 xmlnode = (xmlNodePtr)xmlNewDocText(get_doc(This), NULL);
2130 break;
2131 case NODE_CDATA_SECTION:
2132 xmlnode = xmlNewCDataBlock(get_doc(This), NULL, 0);
2133 break;
2134 case NODE_ENTITY_REFERENCE:
2135 xmlnode = xmlNewReference(get_doc(This), xml_name);
2136 break;
2137 case NODE_PROCESSING_INSTRUCTION:
2138 xmlnode = xmlNewDocPI(get_doc(This), xml_name, NULL);
2139 break;
2140 case NODE_COMMENT:
2141 xmlnode = xmlNewDocComment(get_doc(This), NULL);
2142 break;
2143 case NODE_DOCUMENT_FRAGMENT:
2144 xmlnode = xmlNewDocFragment(get_doc(This));
2145 break;
2146 /* unsupported types */
2147 case NODE_DOCUMENT:
2148 case NODE_DOCUMENT_TYPE:
2149 case NODE_ENTITY:
2150 case NODE_NOTATION:
2151 heap_free(xml_name);
2152 return E_INVALIDARG;
2153 default:
2154 FIXME("unhandled node type %d\n", node_type);
2155 xmlnode = NULL;
2156 break;
2159 *node = create_node(xmlnode);
2160 heap_free(xml_name);
2161 heap_free(href);
2163 if(*node)
2165 TRACE("created node (%d, %p, %p)\n", node_type, *node, xmlnode);
2166 xmldoc_add_orphan(xmlnode->doc, xmlnode);
2167 return S_OK;
2170 return E_FAIL;
2173 static HRESULT WINAPI domdoc_nodeFromID(
2174 IXMLDOMDocument3 *iface,
2175 BSTR idString,
2176 IXMLDOMNode** node )
2178 domdoc *This = impl_from_IXMLDOMDocument3(iface);
2179 FIXME("(%p)->(%s %p)\n", This, debugstr_w(idString), node);
2180 return E_NOTIMPL;
2183 static HRESULT domdoc_onDataAvailable(void *obj, char *ptr, DWORD len)
2185 domdoc *This = obj;
2186 xmlDocPtr xmldoc;
2188 xmldoc = doparse(This, ptr, len, XML_CHAR_ENCODING_NONE);
2189 if(xmldoc) {
2190 xmldoc->_private = create_priv();
2191 return attach_xmldoc(This, xmldoc);
2194 return E_FAIL;
2197 static HRESULT domdoc_load_moniker(domdoc *This, IMoniker *mon)
2199 bsc_t *bsc;
2200 HRESULT hr;
2202 hr = bind_url(mon, domdoc_onDataAvailable, This, &bsc);
2203 if(FAILED(hr))
2204 return hr;
2206 return detach_bsc(bsc);
2209 static HRESULT WINAPI domdoc_load(
2210 IXMLDOMDocument3 *iface,
2211 VARIANT source,
2212 VARIANT_BOOL* isSuccessful )
2214 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2215 LPWSTR filename = NULL;
2216 HRESULT hr = S_FALSE;
2217 xmlDocPtr xmldoc;
2219 TRACE("(%p)->(%s)\n", This, debugstr_variant(&source));
2221 if (!isSuccessful)
2222 return E_POINTER;
2223 *isSuccessful = VARIANT_FALSE;
2225 assert( &This->node );
2227 switch( V_VT(&source) )
2229 case VT_BSTR:
2230 filename = V_BSTR(&source);
2231 break;
2232 case VT_BSTR|VT_BYREF:
2233 if (!V_BSTRREF(&source)) return E_INVALIDARG;
2234 filename = *V_BSTRREF(&source);
2235 break;
2236 case VT_ARRAY|VT_UI1:
2238 SAFEARRAY *psa = V_ARRAY(&source);
2239 char *str;
2240 LONG len;
2241 UINT dim = SafeArrayGetDim(psa);
2243 switch (dim)
2245 case 0:
2246 ERR("SAFEARRAY == NULL\n");
2247 hr = This->error = E_INVALIDARG;
2248 break;
2249 case 1:
2250 /* Only takes UTF-8 strings.
2251 * NOT NULL-terminated. */
2252 hr = SafeArrayAccessData(psa, (void**)&str);
2253 if (FAILED(hr))
2255 This->error = hr;
2256 WARN("failed to access array data, hr %#lx.\n", hr);
2257 break;
2259 SafeArrayGetUBound(psa, 1, &len);
2261 if ((xmldoc = doparse(This, str, ++len, XML_CHAR_ENCODING_UTF8)))
2263 hr = This->error = S_OK;
2264 *isSuccessful = VARIANT_TRUE;
2265 TRACE("parsed document %p\n", xmldoc);
2267 else
2269 This->error = E_FAIL;
2270 TRACE("failed to parse document\n");
2273 SafeArrayUnaccessData(psa);
2275 if(xmldoc)
2277 xmldoc->_private = create_priv();
2278 return attach_xmldoc(This, xmldoc);
2280 break;
2281 default:
2282 FIXME("unhandled SAFEARRAY dim: %d\n", dim);
2283 hr = This->error = E_NOTIMPL;
2286 break;
2287 case VT_UNKNOWN:
2289 ISequentialStream *stream = NULL;
2290 IXMLDOMDocument3 *newdoc = NULL;
2292 if (!V_UNKNOWN(&source)) return E_INVALIDARG;
2294 hr = IUnknown_QueryInterface(V_UNKNOWN(&source), &IID_IXMLDOMDocument3, (void**)&newdoc);
2295 if(hr == S_OK)
2297 if(newdoc)
2299 domdoc *newDoc = impl_from_IXMLDOMDocument3( newdoc );
2301 xmldoc = xmlCopyDoc(get_doc(newDoc), 1);
2302 xmldoc->_private = create_priv();
2303 hr = attach_xmldoc(This, xmldoc);
2305 if(SUCCEEDED(hr))
2306 *isSuccessful = VARIANT_TRUE;
2308 return hr;
2312 hr = IUnknown_QueryInterface(V_UNKNOWN(&source), &IID_IStream, (void**)&stream);
2313 if (FAILED(hr))
2314 hr = IUnknown_QueryInterface(V_UNKNOWN(&source), &IID_ISequentialStream, (void**)&stream);
2316 if (hr == S_OK)
2318 hr = This->error = domdoc_load_from_stream(This, stream);
2319 if (hr == S_OK)
2320 *isSuccessful = VARIANT_TRUE;
2321 ISequentialStream_Release(stream);
2322 return hr;
2325 FIXME("unsupported IUnknown type (%#lx) (%p)\n", hr, V_UNKNOWN(&source)->lpVtbl);
2326 break;
2328 default:
2329 FIXME("VT type not supported (%d)\n", V_VT(&source));
2332 if ( filename )
2334 IUri *uri = NULL;
2335 IMoniker *mon;
2337 if (This->properties->uri)
2339 IUri_Release(This->properties->uri);
2340 This->properties->uri = NULL;
2343 hr = create_uri(This->base_uri, filename, &uri);
2344 if (SUCCEEDED(hr))
2345 hr = CreateURLMonikerEx2(NULL, uri, &mon, 0);
2346 if ( SUCCEEDED(hr) )
2348 hr = domdoc_load_moniker( This, mon );
2349 IMoniker_Release(mon);
2352 if (SUCCEEDED(hr))
2354 get_doc(This)->name = (char *)xmlchar_from_wcharn(filename, -1, TRUE);
2355 This->properties->uri = uri;
2356 hr = This->error = S_OK;
2357 *isSuccessful = VARIANT_TRUE;
2359 else
2361 if (uri)
2362 IUri_Release(uri);
2363 This->error = E_FAIL;
2367 if(!filename || FAILED(hr)) {
2368 xmldoc = xmlNewDoc(NULL);
2369 xmldoc->_private = create_priv();
2370 hr = attach_xmldoc(This, xmldoc);
2371 if(SUCCEEDED(hr))
2372 hr = S_FALSE;
2375 TRACE("hr %#lx.\n", hr);
2377 return hr;
2381 static HRESULT WINAPI domdoc_get_readyState(
2382 IXMLDOMDocument3 *iface,
2383 LONG *value )
2385 domdoc *This = impl_from_IXMLDOMDocument3(iface);
2386 FIXME("stub! (%p)->(%p)\n", This, value);
2388 if (!value)
2389 return E_INVALIDARG;
2391 *value = READYSTATE_COMPLETE;
2392 return S_OK;
2396 static HRESULT WINAPI domdoc_get_parseError(
2397 IXMLDOMDocument3 *iface,
2398 IXMLDOMParseError** errorObj )
2400 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2401 static const WCHAR err[] = {'e','r','r','o','r',0};
2402 BSTR error_string = NULL;
2404 FIXME("(%p)->(%p): creating a dummy parseError\n", iface, errorObj);
2406 if(This->error)
2407 error_string = SysAllocString(err);
2409 *errorObj = create_parseError(This->error, NULL, error_string, NULL, 0, 0, 0);
2410 if(!*errorObj) return E_OUTOFMEMORY;
2411 return S_OK;
2415 static HRESULT WINAPI domdoc_get_url(
2416 IXMLDOMDocument3 *iface,
2417 BSTR* url )
2419 domdoc *This = impl_from_IXMLDOMDocument3(iface);
2421 TRACE("(%p)->(%p)\n", This, url);
2423 if (!url)
2424 return E_INVALIDARG;
2426 if (!This->properties->uri)
2427 return return_null_bstr(url);
2429 return IUri_GetPropertyBSTR(This->properties->uri, Uri_PROPERTY_DISPLAY_URI, url, 0);
2433 static HRESULT WINAPI domdoc_get_async(
2434 IXMLDOMDocument3 *iface,
2435 VARIANT_BOOL* isAsync )
2437 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2439 TRACE("(%p)->(%p: %d)\n", This, isAsync, This->async);
2440 *isAsync = This->async;
2441 return S_OK;
2445 static HRESULT WINAPI domdoc_put_async(
2446 IXMLDOMDocument3 *iface,
2447 VARIANT_BOOL isAsync )
2449 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2451 TRACE("(%p)->(%d)\n", This, isAsync);
2452 This->async = isAsync;
2453 return S_OK;
2457 static HRESULT WINAPI domdoc_abort(
2458 IXMLDOMDocument3 *iface )
2460 domdoc *This = impl_from_IXMLDOMDocument3(iface);
2461 FIXME("%p\n", This);
2462 return E_NOTIMPL;
2465 /* don't rely on data to be in BSTR format, treat it as WCHAR string */
2466 static HRESULT WINAPI domdoc_loadXML(
2467 IXMLDOMDocument3 *iface,
2468 BSTR data,
2469 VARIANT_BOOL* isSuccessful )
2471 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2472 xmlDocPtr xmldoc = NULL;
2473 HRESULT hr = S_FALSE, hr2;
2475 TRACE("(%p)->(%s %p)\n", This, debugstr_w(data), isSuccessful );
2477 assert ( &This->node );
2479 if ( isSuccessful )
2481 *isSuccessful = VARIANT_FALSE;
2483 if (data)
2485 WCHAR *ptr = data;
2487 /* skip leading spaces if needed */
2488 if (This->properties->version == MSXML_DEFAULT || This->properties->version == MSXML26)
2489 while (*ptr && iswspace(*ptr)) ptr++;
2491 xmldoc = doparse(This, (char*)ptr, lstrlenW(ptr)*sizeof(WCHAR), XML_CHAR_ENCODING_UTF16LE);
2492 if ( !xmldoc )
2494 This->error = E_FAIL;
2495 TRACE("failed to parse document\n");
2497 else
2499 hr = This->error = S_OK;
2500 *isSuccessful = VARIANT_TRUE;
2501 TRACE("parsed document %p\n", xmldoc);
2506 if(!xmldoc)
2507 xmldoc = xmlNewDoc(NULL);
2508 xmldoc->_private = create_priv();
2509 hr2 = attach_xmldoc(This, xmldoc);
2510 if( FAILED(hr2) )
2511 hr = hr2;
2513 return hr;
2516 static int XMLCALL domdoc_save_writecallback(void *ctx, const char *buffer, int len)
2518 DWORD written = -1;
2520 if(!WriteFile(ctx, buffer, len, &written, NULL))
2522 WARN("write error\n");
2523 return -1;
2525 else
2526 return written;
2529 static int XMLCALL domdoc_save_closecallback(void *ctx)
2531 return CloseHandle(ctx) ? 0 : -1;
2534 static int XMLCALL domdoc_stream_save_writecallback(void *ctx, const char *buffer, int len)
2536 ULONG written = 0;
2537 HRESULT hr;
2539 hr = IStream_Write((IStream*)ctx, buffer, len, &written);
2540 TRACE("hr %#lx, %p, %d, %lu.\n", hr, buffer, len, written);
2541 if (hr != S_OK)
2543 WARN("stream write error, hr %#lx.\n", hr);
2544 return -1;
2546 else
2547 return len;
2550 static int XMLCALL domdoc_stream_save_closecallback(void *ctx)
2552 IStream_Release((IStream*)ctx);
2553 return 0;
2556 static char *xmldoc_encoding(IXMLDOMDocument3 *doc)
2558 HRESULT hr;
2559 IXMLDOMNode *node;
2560 char *encoding = NULL;
2562 hr = IXMLDOMDocument3_get_firstChild(doc, &node);
2563 if (hr == S_OK)
2565 DOMNodeType type;
2567 hr = IXMLDOMNode_get_nodeType(node, &type);
2568 if (hr == S_OK && type == NODE_PROCESSING_INSTRUCTION)
2570 IXMLDOMProcessingInstruction *pi;
2571 IXMLDOMNode *item;
2572 IXMLDOMNamedNodeMap *node_map;
2574 hr = IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMProcessingInstruction, (void **)&pi);
2575 if (hr == S_OK)
2577 hr = IXMLDOMNode_get_attributes(node, &node_map);
2578 if (hr == S_OK)
2580 static const WCHAR encodingW[] = {'e','n','c','o','d','i','n','g',0};
2581 BSTR bstr;
2583 bstr = SysAllocString(encodingW);
2584 hr = IXMLDOMNamedNodeMap_getNamedItem(node_map, bstr, &item);
2585 SysFreeString(bstr);
2586 if (hr == S_OK)
2588 VARIANT var;
2590 hr = IXMLDOMNode_get_nodeValue(item, &var);
2591 if (hr == S_OK)
2593 if (V_VT(&var) == VT_BSTR)
2594 encoding = (char *)xmlchar_from_wchar(V_BSTR(&var));
2596 VariantClear(&var);
2600 IXMLDOMNamedNodeMap_Release(node_map);
2603 IXMLDOMProcessingInstruction_Release(pi);
2607 IXMLDOMNode_Release(node);
2610 if (!encoding && (encoding = heap_alloc(sizeof("UTF-8"))))
2611 strcpy(encoding, "UTF-8");
2613 return encoding;
2616 static HRESULT WINAPI domdoc_save(
2617 IXMLDOMDocument3 *iface,
2618 VARIANT destination )
2620 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2621 xmlSaveCtxtPtr ctx = NULL;
2622 HRESULT ret = S_OK;
2624 TRACE("(%p)->(%s)\n", This, debugstr_variant(&destination));
2626 switch (V_VT(&destination))
2628 case VT_UNKNOWN:
2630 IUnknown *pUnk = V_UNKNOWN(&destination);
2631 IXMLDOMDocument3 *document;
2632 IStream *stream;
2634 ret = IUnknown_QueryInterface(pUnk, &IID_IXMLDOMDocument3, (void**)&document);
2635 if(ret == S_OK)
2637 VARIANT_BOOL success;
2638 BSTR xml;
2640 ret = IXMLDOMDocument3_get_xml(iface, &xml);
2641 if(ret == S_OK)
2643 ret = IXMLDOMDocument3_loadXML(document, xml, &success);
2644 SysFreeString(xml);
2647 IXMLDOMDocument3_Release(document);
2648 return ret;
2651 ret = IUnknown_QueryInterface(pUnk, &IID_IStream, (void**)&stream);
2652 if(ret == S_OK)
2654 char *encoding = xmldoc_encoding(iface);
2656 TRACE("using encoding %s\n", encoding ? debugstr_a(encoding) : "default");
2657 ctx = xmlSaveToIO(domdoc_stream_save_writecallback,
2658 domdoc_stream_save_closecallback, stream, encoding, XML_SAVE_NO_DECL);
2659 heap_free(encoding);
2661 if(!ctx)
2663 IStream_Release(stream);
2664 return E_FAIL;
2668 break;
2670 case VT_BSTR:
2671 case VT_BSTR | VT_BYREF:
2673 char *encoding;
2674 /* save with file path */
2675 HANDLE handle = CreateFileW( (V_VT(&destination) & VT_BYREF)? *V_BSTRREF(&destination) : V_BSTR(&destination),
2676 GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL );
2677 if( handle == INVALID_HANDLE_VALUE )
2679 WARN("failed to create file\n");
2680 return E_FAIL;
2683 encoding = xmldoc_encoding(iface);
2684 TRACE("using encoding %s\n", encoding ? debugstr_a(encoding) : "default");
2685 ctx = xmlSaveToIO(domdoc_save_writecallback, domdoc_save_closecallback,
2686 handle, encoding, XML_SAVE_NO_DECL);
2687 heap_free(encoding);
2689 if (!ctx)
2691 CloseHandle(handle);
2692 return E_FAIL;
2695 break;
2697 default:
2698 FIXME("Unhandled VARIANT: %s\n", debugstr_variant(&destination));
2699 return S_FALSE;
2702 if (xmlSaveDoc(ctx, get_doc(This)) == -1) ret = S_FALSE;
2704 /* will release resources through close callback */
2705 xmlSaveClose(ctx);
2707 return ret;
2710 static HRESULT WINAPI domdoc_get_validateOnParse(
2711 IXMLDOMDocument3 *iface,
2712 VARIANT_BOOL* isValidating )
2714 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2715 TRACE("(%p)->(%p: %d)\n", This, isValidating, This->properties->validating);
2716 *isValidating = This->properties->validating;
2717 return S_OK;
2721 static HRESULT WINAPI domdoc_put_validateOnParse(
2722 IXMLDOMDocument3 *iface,
2723 VARIANT_BOOL isValidating )
2725 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2726 TRACE("(%p)->(%d)\n", This, isValidating);
2727 This->properties->validating = isValidating;
2728 return S_OK;
2732 static HRESULT WINAPI domdoc_get_resolveExternals(
2733 IXMLDOMDocument3 *iface,
2734 VARIANT_BOOL* isResolving )
2736 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2737 TRACE("(%p)->(%p: %d)\n", This, isResolving, This->resolving);
2738 *isResolving = This->resolving;
2739 return S_OK;
2743 static HRESULT WINAPI domdoc_put_resolveExternals(
2744 IXMLDOMDocument3 *iface,
2745 VARIANT_BOOL isResolving )
2747 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2748 TRACE("(%p)->(%d)\n", This, isResolving);
2749 This->resolving = isResolving;
2750 return S_OK;
2754 static HRESULT WINAPI domdoc_get_preserveWhiteSpace(
2755 IXMLDOMDocument3 *iface,
2756 VARIANT_BOOL* isPreserving )
2758 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2759 TRACE("(%p)->(%p: %d)\n", This, isPreserving, This->properties->preserving);
2760 *isPreserving = This->properties->preserving;
2761 return S_OK;
2765 static HRESULT WINAPI domdoc_put_preserveWhiteSpace(
2766 IXMLDOMDocument3 *iface,
2767 VARIANT_BOOL isPreserving )
2769 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2770 TRACE("(%p)->(%d)\n", This, isPreserving);
2771 This->properties->preserving = isPreserving;
2772 return S_OK;
2776 static HRESULT WINAPI domdoc_put_onreadystatechange(
2777 IXMLDOMDocument3 *iface,
2778 VARIANT event )
2780 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2782 TRACE("(%p)->(%s)\n", This, debugstr_variant(&event));
2783 return set_doc_event(This, EVENTID_READYSTATECHANGE, &event);
2787 static HRESULT WINAPI domdoc_put_onDataAvailable(IXMLDOMDocument3 *iface, VARIANT sink)
2789 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2790 FIXME("(%p)->(%s): stub\n", This, debugstr_variant(&sink));
2791 return E_NOTIMPL;
2794 static HRESULT WINAPI domdoc_put_onTransformNode(IXMLDOMDocument3 *iface, VARIANT sink )
2796 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2797 FIXME("(%p)->(%s): stub\n", This, debugstr_variant(&sink));
2798 return E_NOTIMPL;
2801 static HRESULT WINAPI domdoc_get_namespaces(
2802 IXMLDOMDocument3* iface,
2803 IXMLDOMSchemaCollection** collection )
2805 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2806 HRESULT hr;
2808 FIXME("(%p)->(%p): semi-stub\n", This, collection);
2810 if (!collection) return E_POINTER;
2812 if (!This->namespaces)
2814 hr = SchemaCache_create(This->properties->version, (void**)&This->namespaces);
2815 if (hr != S_OK) return hr;
2817 hr = cache_from_doc_ns(This->namespaces, &This->node);
2818 if (hr != S_OK)
2819 release_namespaces(This);
2822 if (This->namespaces)
2823 return IXMLDOMSchemaCollection2_QueryInterface(This->namespaces,
2824 &IID_IXMLDOMSchemaCollection, (void**)collection);
2826 return hr;
2829 static HRESULT WINAPI domdoc_get_schemas(
2830 IXMLDOMDocument3* iface,
2831 VARIANT* schema )
2833 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2834 IXMLDOMSchemaCollection2* cur_schema = This->properties->schemaCache;
2835 HRESULT hr = S_FALSE;
2837 TRACE("(%p)->(%p)\n", This, schema);
2839 V_VT(schema) = VT_NULL;
2840 /* just to reset pointer part, cause that's what application is expected to use */
2841 V_DISPATCH(schema) = NULL;
2843 if(cur_schema)
2845 hr = IXMLDOMSchemaCollection2_QueryInterface(cur_schema, &IID_IDispatch, (void**)&V_DISPATCH(schema));
2846 if(SUCCEEDED(hr))
2847 V_VT(schema) = VT_DISPATCH;
2849 return hr;
2852 static HRESULT WINAPI domdoc_putref_schemas(
2853 IXMLDOMDocument3* iface,
2854 VARIANT schema)
2856 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2857 HRESULT hr = E_FAIL;
2858 IXMLDOMSchemaCollection2* new_schema = NULL;
2860 FIXME("(%p)->(%s): semi-stub\n", This, debugstr_variant(&schema));
2861 switch(V_VT(&schema))
2863 case VT_UNKNOWN:
2864 if (V_UNKNOWN(&schema))
2866 hr = IUnknown_QueryInterface(V_UNKNOWN(&schema), &IID_IXMLDOMSchemaCollection, (void**)&new_schema);
2867 break;
2869 /* fallthrough */
2870 case VT_DISPATCH:
2871 if (V_DISPATCH(&schema))
2873 hr = IDispatch_QueryInterface(V_DISPATCH(&schema), &IID_IXMLDOMSchemaCollection, (void**)&new_schema);
2874 break;
2876 /* fallthrough */
2877 case VT_NULL:
2878 case VT_EMPTY:
2879 hr = S_OK;
2880 break;
2882 default:
2883 WARN("Can't get schema from vt %x\n", V_VT(&schema));
2886 if(SUCCEEDED(hr))
2888 IXMLDOMSchemaCollection2* old_schema = InterlockedExchangePointer((void**)&This->properties->schemaCache, new_schema);
2889 if(old_schema) IXMLDOMSchemaCollection2_Release(old_schema);
2892 return hr;
2895 static inline BOOL is_wellformed(xmlDocPtr doc)
2897 return doc->properties & XML_DOC_WELLFORMED;
2900 static void LIBXML2_LOG_CALLBACK validate_error(void* ctx, char const* msg, ...)
2902 va_list ap;
2903 va_start(ap, msg);
2904 LIBXML2_CALLBACK_ERR(domdoc_validateNode, msg, ap);
2905 va_end(ap);
2908 static void LIBXML2_LOG_CALLBACK validate_warning(void* ctx, char const* msg, ...)
2910 va_list ap;
2911 va_start(ap, msg);
2912 LIBXML2_CALLBACK_WARN(domdoc_validateNode, msg, ap);
2913 va_end(ap);
2916 static HRESULT WINAPI domdoc_validateNode(
2917 IXMLDOMDocument3* iface,
2918 IXMLDOMNode* node,
2919 IXMLDOMParseError** err)
2921 domdoc* This = impl_from_IXMLDOMDocument3(iface);
2922 LONG state, err_code = 0;
2923 HRESULT hr = S_OK;
2924 int validated = 0;
2926 TRACE("(%p)->(%p, %p)\n", This, node, err);
2927 IXMLDOMDocument3_get_readyState(iface, &state);
2928 if (state != READYSTATE_COMPLETE)
2930 if (err)
2931 *err = create_parseError(err_code, NULL, NULL, NULL, 0, 0, 0);
2932 return E_PENDING;
2935 if (!node)
2937 if (err)
2938 *err = create_parseError(err_code, NULL, NULL, NULL, 0, 0, 0);
2939 return E_POINTER;
2942 if (!get_node_obj(node)->node || get_node_obj(node)->node->doc != get_doc(This))
2944 if (err)
2945 *err = create_parseError(err_code, NULL, NULL, NULL, 0, 0, 0);
2946 return E_FAIL;
2949 if (!is_wellformed(get_doc(This)))
2951 ERR("doc not well-formed\n");
2952 if (err)
2953 *err = create_parseError(E_XML_NOTWF, NULL, NULL, NULL, 0, 0, 0);
2954 return S_FALSE;
2957 /* DTD validation */
2958 if (get_doc(This)->intSubset || get_doc(This)->extSubset)
2960 xmlValidCtxtPtr vctx = xmlNewValidCtxt();
2961 vctx->error = validate_error;
2962 vctx->warning = validate_warning;
2963 ++validated;
2965 if (!((node == (IXMLDOMNode*)iface)?
2966 xmlValidateDocument(vctx, get_doc(This)) :
2967 xmlValidateElement(vctx, get_doc(This), get_node_obj(node)->node)))
2969 /* TODO: get a real error code here */
2970 TRACE("DTD validation failed\n");
2971 err_code = E_XML_INVALID;
2972 hr = S_FALSE;
2974 xmlFreeValidCtxt(vctx);
2977 /* Schema validation */
2978 if (hr == S_OK && This->properties->schemaCache != NULL)
2981 hr = SchemaCache_validate_tree(This->properties->schemaCache, get_node_obj(node)->node);
2982 if (SUCCEEDED(hr))
2984 ++validated;
2985 /* TODO: get a real error code here */
2986 if (hr == S_OK)
2988 TRACE("schema validation succeeded\n");
2990 else
2992 ERR("schema validation failed\n");
2993 err_code = E_XML_INVALID;
2996 else
2998 /* not really OK, just didn't find a schema for the ns */
2999 hr = S_OK;
3003 if (!validated)
3005 ERR("no DTD or schema found\n");
3006 err_code = E_XML_NODTD;
3007 hr = S_FALSE;
3010 if (err)
3011 *err = create_parseError(err_code, NULL, NULL, NULL, 0, 0, 0);
3013 return hr;
3016 static HRESULT WINAPI domdoc_validate(
3017 IXMLDOMDocument3* iface,
3018 IXMLDOMParseError** err)
3020 domdoc *This = impl_from_IXMLDOMDocument3( iface );
3021 TRACE("(%p)->(%p)\n", This, err);
3022 return IXMLDOMDocument3_validateNode(iface, (IXMLDOMNode*)iface, err);
3025 static HRESULT WINAPI domdoc_setProperty(
3026 IXMLDOMDocument3* iface,
3027 BSTR p,
3028 VARIANT value)
3030 domdoc *This = impl_from_IXMLDOMDocument3( iface );
3032 TRACE("(%p)->(%s %s)\n", This, debugstr_w(p), debugstr_variant(&value));
3034 if (lstrcmpiW(p, PropertySelectionLanguageW) == 0)
3036 VARIANT varStr;
3037 HRESULT hr;
3038 BSTR bstr;
3040 V_VT(&varStr) = VT_EMPTY;
3041 if (V_VT(&value) != VT_BSTR)
3043 if (FAILED(hr = VariantChangeType(&varStr, &value, 0, VT_BSTR)))
3044 return hr;
3045 bstr = V_BSTR(&varStr);
3047 else
3048 bstr = V_BSTR(&value);
3050 hr = S_OK;
3051 if (lstrcmpiW(bstr, PropValueXPathW) == 0)
3052 This->properties->XPath = TRUE;
3053 else if (lstrcmpiW(bstr, PropValueXSLPatternW) == 0)
3054 This->properties->XPath = FALSE;
3055 else
3056 hr = E_FAIL;
3058 VariantClear(&varStr);
3059 return hr;
3061 else if (lstrcmpiW(p, PropertySelectionNamespacesW) == 0)
3063 xmlChar *nsStr = (xmlChar*)This->properties->selectNsStr;
3064 struct list *pNsList;
3065 VARIANT varStr;
3066 HRESULT hr;
3067 BSTR bstr;
3069 V_VT(&varStr) = VT_EMPTY;
3070 if (V_VT(&value) != VT_BSTR)
3072 if (FAILED(hr = VariantChangeType(&varStr, &value, 0, VT_BSTR)))
3073 return hr;
3074 bstr = V_BSTR(&varStr);
3076 else
3077 bstr = V_BSTR(&value);
3079 hr = S_OK;
3081 pNsList = &(This->properties->selectNsList);
3082 clear_selectNsList(pNsList);
3083 heap_free(nsStr);
3084 nsStr = xmlchar_from_wchar(bstr);
3086 TRACE("property value: \"%s\"\n", debugstr_w(bstr));
3088 This->properties->selectNsStr = nsStr;
3089 This->properties->selectNsStr_len = xmlStrlen(nsStr);
3090 if (bstr && *bstr)
3092 xmlChar *pTokBegin, *pTokEnd, *pTokInner;
3093 select_ns_entry* ns_entry = NULL;
3094 xmlXPathContextPtr ctx;
3096 ctx = xmlXPathNewContext(This->node.node->doc);
3097 pTokBegin = nsStr;
3099 /* skip leading spaces */
3100 while (*pTokBegin == ' ' || *pTokBegin == '\n' ||
3101 *pTokBegin == '\t' || *pTokBegin == '\r')
3102 ++pTokBegin;
3104 for (; *pTokBegin; pTokBegin = pTokEnd)
3106 if (ns_entry)
3107 memset(ns_entry, 0, sizeof(select_ns_entry));
3108 else
3109 ns_entry = heap_alloc_zero(sizeof(select_ns_entry));
3111 while (*pTokBegin == ' ')
3112 ++pTokBegin;
3113 pTokEnd = pTokBegin;
3114 while (*pTokEnd != ' ' && *pTokEnd != 0)
3115 ++pTokEnd;
3117 /* so it failed to advance which means we've got some trailing spaces */
3118 if (pTokEnd == pTokBegin) break;
3120 if (xmlStrncmp(pTokBegin, (xmlChar const*)"xmlns", 5) != 0)
3122 hr = E_FAIL;
3123 WARN("Syntax error in xmlns string: %s\n\tat token: %s\n",
3124 debugstr_w(bstr), debugstr_an((const char*)pTokBegin, pTokEnd-pTokBegin));
3125 continue;
3128 pTokBegin += 5;
3129 if (*pTokBegin == '=')
3131 /*valid for XSLPattern?*/
3132 FIXME("Setting default xmlns not supported - skipping.\n");
3133 continue;
3135 else if (*pTokBegin == ':')
3137 ns_entry->prefix = ++pTokBegin;
3138 for (pTokInner = pTokBegin; pTokInner != pTokEnd && *pTokInner != '='; ++pTokInner)
3141 if (pTokInner == pTokEnd)
3143 hr = E_FAIL;
3144 WARN("Syntax error in xmlns string: %s\n\tat token: %s\n",
3145 debugstr_w(bstr), debugstr_an((const char*)pTokBegin, pTokEnd-pTokBegin));
3146 continue;
3149 ns_entry->prefix_end = *pTokInner;
3150 *pTokInner = 0;
3151 ++pTokInner;
3153 if (pTokEnd-pTokInner > 1 &&
3154 ((*pTokInner == '\'' && *(pTokEnd-1) == '\'') ||
3155 (*pTokInner == '"' && *(pTokEnd-1) == '"')))
3157 ns_entry->href = ++pTokInner;
3158 ns_entry->href_end = *(pTokEnd-1);
3159 *(pTokEnd-1) = 0;
3160 list_add_tail(pNsList, &ns_entry->entry);
3161 /*let libxml figure out if they're valid from here ;)*/
3162 if (xmlXPathRegisterNs(ctx, ns_entry->prefix, ns_entry->href) != 0)
3164 hr = E_FAIL;
3166 ns_entry = NULL;
3167 continue;
3169 else
3171 WARN("Syntax error in xmlns string: %s\n\tat token: %s\n",
3172 debugstr_w(bstr), debugstr_an((const char*)pTokInner, pTokEnd-pTokInner));
3173 list_add_tail(pNsList, &ns_entry->entry);
3175 ns_entry = NULL;
3176 hr = E_FAIL;
3177 continue;
3180 else
3182 hr = E_FAIL;
3183 continue;
3186 heap_free(ns_entry);
3187 xmlXPathFreeContext(ctx);
3190 VariantClear(&varStr);
3191 return hr;
3193 else if (lstrcmpiW(p, PropertyValidateOnParse) == 0)
3195 if (This->properties->version < MSXML4)
3196 return E_FAIL;
3197 else
3199 This->properties->validating = V_BOOL(&value);
3200 return S_OK;
3203 else if (lstrcmpiW(p, PropertyProhibitDTDW) == 0 ||
3204 lstrcmpiW(p, PropertyNewParserW) == 0 ||
3205 lstrcmpiW(p, PropertyResolveExternalsW) == 0 ||
3206 lstrcmpiW(p, PropertyAllowXsltScriptW) == 0 ||
3207 lstrcmpiW(p, PropertyNormalizeAttributeValuesW) == 0 ||
3208 lstrcmpiW(p, PropertyAllowDocumentFunctionW) == 0)
3210 /* Ignore */
3211 FIXME("Ignoring property %s, value %s\n", debugstr_w(p), debugstr_variant(&value));
3212 return S_OK;
3215 FIXME("Unknown property %s\n", debugstr_w(p));
3216 return E_FAIL;
3219 static HRESULT WINAPI domdoc_getProperty(
3220 IXMLDOMDocument3* iface,
3221 BSTR p,
3222 VARIANT* var)
3224 domdoc *This = impl_from_IXMLDOMDocument3( iface );
3226 TRACE("(%p)->(%s)\n", This, debugstr_w(p));
3228 if (!var)
3229 return E_INVALIDARG;
3231 if (lstrcmpiW(p, PropertySelectionLanguageW) == 0)
3233 V_VT(var) = VT_BSTR;
3234 V_BSTR(var) = This->properties->XPath ?
3235 SysAllocString(PropValueXPathW) :
3236 SysAllocString(PropValueXSLPatternW);
3237 return V_BSTR(var) ? S_OK : E_OUTOFMEMORY;
3239 else if (lstrcmpiW(p, PropertySelectionNamespacesW) == 0)
3241 int lenA, lenW;
3242 BSTR rebuiltStr, cur;
3243 const xmlChar *nsStr;
3244 struct list *pNsList;
3245 select_ns_entry* pNsEntry;
3247 V_VT(var) = VT_BSTR;
3248 nsStr = This->properties->selectNsStr;
3249 pNsList = &This->properties->selectNsList;
3250 lenA = This->properties->selectNsStr_len;
3251 lenW = MultiByteToWideChar(CP_UTF8, 0, (LPCSTR)nsStr, lenA+1, NULL, 0);
3252 rebuiltStr = heap_alloc(lenW*sizeof(WCHAR));
3253 MultiByteToWideChar(CP_UTF8, 0, (LPCSTR)nsStr, lenA+1, rebuiltStr, lenW);
3254 cur = rebuiltStr;
3255 /* this is fine because all of the chars that end tokens are ASCII*/
3256 LIST_FOR_EACH_ENTRY(pNsEntry, pNsList, select_ns_entry, entry)
3258 while (*cur != 0) ++cur;
3259 if (pNsEntry->prefix_end)
3261 *cur = pNsEntry->prefix_end;
3262 while (*cur != 0) ++cur;
3265 if (pNsEntry->href_end)
3267 *cur = pNsEntry->href_end;
3270 V_BSTR(var) = SysAllocString(rebuiltStr);
3271 heap_free(rebuiltStr);
3272 return S_OK;
3274 else if (lstrcmpiW(p, PropertyValidateOnParse) == 0)
3276 if (This->properties->version < MSXML4)
3277 return E_FAIL;
3278 else
3280 V_VT(var) = VT_BOOL;
3281 V_BOOL(var) = This->properties->validating;
3282 return S_OK;
3286 FIXME("Unknown property %s\n", debugstr_w(p));
3287 return E_FAIL;
3290 static HRESULT WINAPI domdoc_importNode(
3291 IXMLDOMDocument3* iface,
3292 IXMLDOMNode* node,
3293 VARIANT_BOOL deep,
3294 IXMLDOMNode** clone)
3296 domdoc *This = impl_from_IXMLDOMDocument3( iface );
3297 FIXME("(%p)->(%p %d %p): stub\n", This, node, deep, clone);
3298 return E_NOTIMPL;
3301 static const struct IXMLDOMDocument3Vtbl XMLDOMDocument3Vtbl =
3303 domdoc_QueryInterface,
3304 domdoc_AddRef,
3305 domdoc_Release,
3306 domdoc_GetTypeInfoCount,
3307 domdoc_GetTypeInfo,
3308 domdoc_GetIDsOfNames,
3309 domdoc_Invoke,
3310 domdoc_get_nodeName,
3311 domdoc_get_nodeValue,
3312 domdoc_put_nodeValue,
3313 domdoc_get_nodeType,
3314 domdoc_get_parentNode,
3315 domdoc_get_childNodes,
3316 domdoc_get_firstChild,
3317 domdoc_get_lastChild,
3318 domdoc_get_previousSibling,
3319 domdoc_get_nextSibling,
3320 domdoc_get_attributes,
3321 domdoc_insertBefore,
3322 domdoc_replaceChild,
3323 domdoc_removeChild,
3324 domdoc_appendChild,
3325 domdoc_hasChildNodes,
3326 domdoc_get_ownerDocument,
3327 domdoc_cloneNode,
3328 domdoc_get_nodeTypeString,
3329 domdoc_get_text,
3330 domdoc_put_text,
3331 domdoc_get_specified,
3332 domdoc_get_definition,
3333 domdoc_get_nodeTypedValue,
3334 domdoc_put_nodeTypedValue,
3335 domdoc_get_dataType,
3336 domdoc_put_dataType,
3337 domdoc_get_xml,
3338 domdoc_transformNode,
3339 domdoc_selectNodes,
3340 domdoc_selectSingleNode,
3341 domdoc_get_parsed,
3342 domdoc_get_namespaceURI,
3343 domdoc_get_prefix,
3344 domdoc_get_baseName,
3345 domdoc_transformNodeToObject,
3346 domdoc_get_doctype,
3347 domdoc_get_implementation,
3348 domdoc_get_documentElement,
3349 domdoc_put_documentElement,
3350 domdoc_createElement,
3351 domdoc_createDocumentFragment,
3352 domdoc_createTextNode,
3353 domdoc_createComment,
3354 domdoc_createCDATASection,
3355 domdoc_createProcessingInstruction,
3356 domdoc_createAttribute,
3357 domdoc_createEntityReference,
3358 domdoc_getElementsByTagName,
3359 domdoc_createNode,
3360 domdoc_nodeFromID,
3361 domdoc_load,
3362 domdoc_get_readyState,
3363 domdoc_get_parseError,
3364 domdoc_get_url,
3365 domdoc_get_async,
3366 domdoc_put_async,
3367 domdoc_abort,
3368 domdoc_loadXML,
3369 domdoc_save,
3370 domdoc_get_validateOnParse,
3371 domdoc_put_validateOnParse,
3372 domdoc_get_resolveExternals,
3373 domdoc_put_resolveExternals,
3374 domdoc_get_preserveWhiteSpace,
3375 domdoc_put_preserveWhiteSpace,
3376 domdoc_put_onreadystatechange,
3377 domdoc_put_onDataAvailable,
3378 domdoc_put_onTransformNode,
3379 domdoc_get_namespaces,
3380 domdoc_get_schemas,
3381 domdoc_putref_schemas,
3382 domdoc_validate,
3383 domdoc_setProperty,
3384 domdoc_getProperty,
3385 domdoc_validateNode,
3386 domdoc_importNode
3389 /* IConnectionPointContainer */
3390 static HRESULT WINAPI ConnectionPointContainer_QueryInterface(IConnectionPointContainer *iface,
3391 REFIID riid, void **ppv)
3393 domdoc *This = impl_from_IConnectionPointContainer(iface);
3394 return IXMLDOMDocument3_QueryInterface(&This->IXMLDOMDocument3_iface, riid, ppv);
3397 static ULONG WINAPI ConnectionPointContainer_AddRef(IConnectionPointContainer *iface)
3399 domdoc *This = impl_from_IConnectionPointContainer(iface);
3400 return IXMLDOMDocument3_AddRef(&This->IXMLDOMDocument3_iface);
3403 static ULONG WINAPI ConnectionPointContainer_Release(IConnectionPointContainer *iface)
3405 domdoc *This = impl_from_IConnectionPointContainer(iface);
3406 return IXMLDOMDocument3_Release(&This->IXMLDOMDocument3_iface);
3409 static HRESULT WINAPI ConnectionPointContainer_EnumConnectionPoints(IConnectionPointContainer *iface,
3410 IEnumConnectionPoints **ppEnum)
3412 domdoc *This = impl_from_IConnectionPointContainer(iface);
3413 FIXME("(%p)->(%p): stub\n", This, ppEnum);
3414 return E_NOTIMPL;
3417 static HRESULT WINAPI ConnectionPointContainer_FindConnectionPoint(IConnectionPointContainer *iface,
3418 REFIID riid, IConnectionPoint **cp)
3420 domdoc *This = impl_from_IConnectionPointContainer(iface);
3421 ConnectionPoint *iter;
3423 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), cp);
3425 *cp = NULL;
3427 for(iter = This->cp_list; iter; iter = iter->next)
3429 if (IsEqualGUID(iter->iid, riid))
3430 *cp = &iter->IConnectionPoint_iface;
3433 if (*cp)
3435 IConnectionPoint_AddRef(*cp);
3436 return S_OK;
3439 FIXME("unsupported riid %s\n", debugstr_guid(riid));
3440 return CONNECT_E_NOCONNECTION;
3444 static const struct IConnectionPointContainerVtbl ConnectionPointContainerVtbl =
3446 ConnectionPointContainer_QueryInterface,
3447 ConnectionPointContainer_AddRef,
3448 ConnectionPointContainer_Release,
3449 ConnectionPointContainer_EnumConnectionPoints,
3450 ConnectionPointContainer_FindConnectionPoint
3453 /* IConnectionPoint */
3454 static HRESULT WINAPI ConnectionPoint_QueryInterface(IConnectionPoint *iface,
3455 REFIID riid, void **ppv)
3457 ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3459 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv );
3461 *ppv = NULL;
3463 if (IsEqualGUID(&IID_IUnknown, riid) ||
3464 IsEqualGUID(&IID_IConnectionPoint, riid))
3466 *ppv = iface;
3469 if (*ppv)
3471 IConnectionPoint_AddRef(iface);
3472 return S_OK;
3475 WARN("Unsupported interface %s\n", debugstr_guid(riid));
3476 return E_NOINTERFACE;
3479 static ULONG WINAPI ConnectionPoint_AddRef(IConnectionPoint *iface)
3481 ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3482 return IConnectionPointContainer_AddRef(This->container);
3485 static ULONG WINAPI ConnectionPoint_Release(IConnectionPoint *iface)
3487 ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3488 return IConnectionPointContainer_Release(This->container);
3491 static HRESULT WINAPI ConnectionPoint_GetConnectionInterface(IConnectionPoint *iface, IID *iid)
3493 ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3495 TRACE("(%p)->(%p)\n", This, iid);
3497 if (!iid) return E_POINTER;
3499 *iid = *This->iid;
3500 return S_OK;
3503 static HRESULT WINAPI ConnectionPoint_GetConnectionPointContainer(IConnectionPoint *iface,
3504 IConnectionPointContainer **container)
3506 ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3508 TRACE("(%p)->(%p)\n", This, container);
3510 if (!container) return E_POINTER;
3512 *container = This->container;
3513 IConnectionPointContainer_AddRef(*container);
3514 return S_OK;
3517 static HRESULT WINAPI ConnectionPoint_Advise(IConnectionPoint *iface, IUnknown *unk_sink,
3518 DWORD *cookie)
3520 ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3521 IUnknown *sink;
3522 HRESULT hr;
3523 DWORD i;
3525 TRACE("(%p)->(%p %p)\n", This, unk_sink, cookie);
3527 hr = IUnknown_QueryInterface(unk_sink, This->iid, (void**)&sink);
3528 if(FAILED(hr) && !IsEqualGUID(&IID_IPropertyNotifySink, This->iid))
3529 hr = IUnknown_QueryInterface(unk_sink, &IID_IDispatch, (void**)&sink);
3530 if(FAILED(hr))
3531 return CONNECT_E_CANNOTCONNECT;
3533 if(This->sinks)
3535 for (i = 0; i < This->sinks_size; i++)
3536 if (!This->sinks[i].unk)
3537 break;
3539 if (i == This->sinks_size)
3540 This->sinks = heap_realloc(This->sinks,(++This->sinks_size)*sizeof(*This->sinks));
3542 else
3544 This->sinks = heap_alloc(sizeof(*This->sinks));
3545 This->sinks_size = 1;
3546 i = 0;
3549 This->sinks[i].unk = sink;
3550 if (cookie)
3551 *cookie = i+1;
3553 return S_OK;
3556 static HRESULT WINAPI ConnectionPoint_Unadvise(IConnectionPoint *iface, DWORD cookie)
3558 ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3560 TRACE("%p, %ld.\n", iface, cookie);
3562 if (cookie == 0 || cookie > This->sinks_size || !This->sinks[cookie-1].unk)
3563 return CONNECT_E_NOCONNECTION;
3565 IUnknown_Release(This->sinks[cookie-1].unk);
3566 This->sinks[cookie-1].unk = NULL;
3568 return S_OK;
3571 static HRESULT WINAPI ConnectionPoint_EnumConnections(IConnectionPoint *iface,
3572 IEnumConnections **ppEnum)
3574 ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3575 FIXME("(%p)->(%p): stub\n", This, ppEnum);
3576 return E_NOTIMPL;
3579 static const IConnectionPointVtbl ConnectionPointVtbl =
3581 ConnectionPoint_QueryInterface,
3582 ConnectionPoint_AddRef,
3583 ConnectionPoint_Release,
3584 ConnectionPoint_GetConnectionInterface,
3585 ConnectionPoint_GetConnectionPointContainer,
3586 ConnectionPoint_Advise,
3587 ConnectionPoint_Unadvise,
3588 ConnectionPoint_EnumConnections
3591 static void ConnectionPoint_Init(ConnectionPoint *cp, struct domdoc *doc, REFIID riid)
3593 cp->IConnectionPoint_iface.lpVtbl = &ConnectionPointVtbl;
3594 cp->doc = doc;
3595 cp->iid = riid;
3596 cp->sinks = NULL;
3597 cp->sinks_size = 0;
3599 cp->next = doc->cp_list;
3600 doc->cp_list = cp;
3602 cp->container = &doc->IConnectionPointContainer_iface;
3605 /* domdoc implementation of IObjectWithSite */
3606 static HRESULT WINAPI
3607 domdoc_ObjectWithSite_QueryInterface( IObjectWithSite* iface, REFIID riid, void** ppvObject )
3609 domdoc *This = impl_from_IObjectWithSite(iface);
3610 return IXMLDOMDocument3_QueryInterface(&This->IXMLDOMDocument3_iface, riid, ppvObject);
3613 static ULONG WINAPI domdoc_ObjectWithSite_AddRef( IObjectWithSite* iface )
3615 domdoc *This = impl_from_IObjectWithSite(iface);
3616 return IXMLDOMDocument3_AddRef(&This->IXMLDOMDocument3_iface);
3619 static ULONG WINAPI domdoc_ObjectWithSite_Release( IObjectWithSite* iface )
3621 domdoc *This = impl_from_IObjectWithSite(iface);
3622 return IXMLDOMDocument3_Release(&This->IXMLDOMDocument3_iface);
3625 static HRESULT WINAPI domdoc_ObjectWithSite_GetSite( IObjectWithSite *iface, REFIID iid, void **ppvSite )
3627 domdoc *This = impl_from_IObjectWithSite(iface);
3629 TRACE("(%p)->(%s %p)\n", This, debugstr_guid( iid ), ppvSite );
3631 if ( !This->site )
3632 return E_FAIL;
3634 return IUnknown_QueryInterface( This->site, iid, ppvSite );
3637 static HRESULT WINAPI domdoc_ObjectWithSite_SetSite( IObjectWithSite *iface, IUnknown *punk )
3639 domdoc *This = impl_from_IObjectWithSite(iface);
3641 TRACE("(%p)->(%p)\n", iface, punk);
3643 if(!punk)
3645 if(This->site)
3647 IUnknown_Release( This->site );
3648 This->site = NULL;
3651 if(This->base_uri)
3653 IUri_Release(This->base_uri);
3654 This->base_uri = NULL;
3657 return S_OK;
3660 IUnknown_AddRef( punk );
3662 if(This->site)
3663 IUnknown_Release( This->site );
3665 This->site = punk;
3666 This->base_uri = get_base_uri(This->site);
3668 return S_OK;
3671 static const IObjectWithSiteVtbl domdocObjectSite =
3673 domdoc_ObjectWithSite_QueryInterface,
3674 domdoc_ObjectWithSite_AddRef,
3675 domdoc_ObjectWithSite_Release,
3676 domdoc_ObjectWithSite_SetSite,
3677 domdoc_ObjectWithSite_GetSite
3680 static HRESULT WINAPI domdoc_Safety_QueryInterface(IObjectSafety *iface, REFIID riid, void **ppv)
3682 domdoc *This = impl_from_IObjectSafety(iface);
3683 return IXMLDOMDocument3_QueryInterface(&This->IXMLDOMDocument3_iface, riid, ppv);
3686 static ULONG WINAPI domdoc_Safety_AddRef(IObjectSafety *iface)
3688 domdoc *This = impl_from_IObjectSafety(iface);
3689 return IXMLDOMDocument3_AddRef(&This->IXMLDOMDocument3_iface);
3692 static ULONG WINAPI domdoc_Safety_Release(IObjectSafety *iface)
3694 domdoc *This = impl_from_IObjectSafety(iface);
3695 return IXMLDOMDocument3_Release(&This->IXMLDOMDocument3_iface);
3698 #define SAFETY_SUPPORTED_OPTIONS (INTERFACESAFE_FOR_UNTRUSTED_CALLER|INTERFACESAFE_FOR_UNTRUSTED_DATA|INTERFACE_USES_SECURITY_MANAGER)
3700 static HRESULT WINAPI domdoc_Safety_GetInterfaceSafetyOptions(IObjectSafety *iface, REFIID riid,
3701 DWORD *supported, DWORD *enabled)
3703 domdoc *This = impl_from_IObjectSafety(iface);
3705 TRACE("(%p)->(%s %p %p)\n", This, debugstr_guid(riid), supported, enabled);
3707 if(!supported || !enabled) return E_POINTER;
3709 *supported = SAFETY_SUPPORTED_OPTIONS;
3710 *enabled = This->safeopt;
3712 return S_OK;
3715 static HRESULT WINAPI domdoc_Safety_SetInterfaceSafetyOptions(IObjectSafety *iface, REFIID riid,
3716 DWORD mask, DWORD enabled)
3718 domdoc *doc = impl_from_IObjectSafety(iface);
3720 TRACE("%p, %s, %lx, %lx.\n", iface, debugstr_guid(riid), mask, enabled);
3722 if ((mask & ~SAFETY_SUPPORTED_OPTIONS) != 0)
3723 return E_FAIL;
3725 doc->safeopt = (doc->safeopt & ~mask) | (mask & enabled);
3727 return S_OK;
3730 #undef SAFETY_SUPPORTED_OPTIONS
3732 static const IObjectSafetyVtbl domdocObjectSafetyVtbl = {
3733 domdoc_Safety_QueryInterface,
3734 domdoc_Safety_AddRef,
3735 domdoc_Safety_Release,
3736 domdoc_Safety_GetInterfaceSafetyOptions,
3737 domdoc_Safety_SetInterfaceSafetyOptions
3740 static const tid_t domdoc_iface_tids[] = {
3741 IXMLDOMDocument3_tid,
3745 static dispex_static_data_t domdoc_dispex = {
3746 NULL,
3747 IXMLDOMDocument3_tid,
3748 NULL,
3749 domdoc_iface_tids
3752 HRESULT get_domdoc_from_xmldoc(xmlDocPtr xmldoc, IXMLDOMDocument3 **document)
3754 domdoc *doc;
3756 doc = heap_alloc( sizeof (*doc) );
3757 if( !doc )
3758 return E_OUTOFMEMORY;
3760 doc->IXMLDOMDocument3_iface.lpVtbl = &XMLDOMDocument3Vtbl;
3761 doc->IPersistStreamInit_iface.lpVtbl = &xmldoc_IPersistStreamInit_VTable;
3762 doc->IObjectWithSite_iface.lpVtbl = &domdocObjectSite;
3763 doc->IObjectSafety_iface.lpVtbl = &domdocObjectSafetyVtbl;
3764 doc->IConnectionPointContainer_iface.lpVtbl = &ConnectionPointContainerVtbl;
3765 doc->ref = 1;
3766 doc->async = VARIANT_TRUE;
3767 doc->resolving = 0;
3768 doc->properties = properties_add_ref(properties_from_xmlDocPtr(xmldoc));
3769 doc->error = S_OK;
3770 doc->site = NULL;
3771 doc->base_uri = NULL;
3772 doc->safeopt = 0;
3773 doc->cp_list = NULL;
3774 doc->namespaces = NULL;
3775 memset(doc->events, 0, sizeof(doc->events));
3777 /* events connection points */
3778 ConnectionPoint_Init(&doc->cp_dispatch, doc, &IID_IDispatch);
3779 ConnectionPoint_Init(&doc->cp_propnotif, doc, &IID_IPropertyNotifySink);
3780 ConnectionPoint_Init(&doc->cp_domdocevents, doc, &DIID_XMLDOMDocumentEvents);
3782 init_xmlnode(&doc->node, (xmlNodePtr)xmldoc, (IXMLDOMNode*)&doc->IXMLDOMDocument3_iface,
3783 &domdoc_dispex);
3785 *document = &doc->IXMLDOMDocument3_iface;
3787 TRACE("returning iface %p\n", *document);
3788 return S_OK;
3791 HRESULT dom_document_create(MSXML_VERSION version, void **ppObj)
3793 xmlDocPtr xmldoc;
3794 HRESULT hr;
3796 TRACE("(%d, %p)\n", version, ppObj);
3798 xmldoc = xmlNewDoc(NULL);
3799 if(!xmldoc)
3800 return E_OUTOFMEMORY;
3802 xmldoc_init(xmldoc, version);
3804 hr = get_domdoc_from_xmldoc(xmldoc, (IXMLDOMDocument3**)ppObj);
3805 if(FAILED(hr))
3807 properties_release(properties_from_xmlDocPtr(xmldoc));
3808 heap_free(xmldoc->_private);
3809 xmlFreeDoc(xmldoc);
3810 return hr;
3813 return hr;
3816 IUnknown* create_domdoc( xmlNodePtr document )
3818 IUnknown *obj = NULL;
3819 HRESULT hr;
3821 TRACE("(%p)\n", document);
3823 hr = get_domdoc_from_xmldoc((xmlDocPtr)document, (IXMLDOMDocument3**)&obj);
3824 if (FAILED(hr))
3825 return NULL;
3827 return obj;