wbemprox: Implement some properties of Win32_ComputerSystem and Win32_DiskPartition.
[wine.git] / dlls / msxml3 / domdoc.c
blob67902bd7a1caaff4fd5a1a7893fce728a80f9e91
1 /*
2 * DOM Document implementation
4 * Copyright 2005 Mike McCormack
5 * Copyright 2010-2011 Adam Martinson for CodeWeavers
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
22 #define COBJMACROS
23 #define NONAMELESSUNION
25 #include "config.h"
27 #include <stdarg.h>
28 #include <assert.h>
29 #ifdef HAVE_LIBXML2
30 # include <libxml/parser.h>
31 # include <libxml/xmlerror.h>
32 # include <libxml/xpathInternals.h>
33 # include <libxml/xmlsave.h>
34 # include <libxml/SAX2.h>
35 # include <libxml/parserInternals.h>
36 #endif
38 #include "windef.h"
39 #include "winbase.h"
40 #include "winuser.h"
41 #include "winnls.h"
42 #include "ole2.h"
43 #include "olectl.h"
44 #include "msxml6.h"
45 #include "wininet.h"
46 #include "winreg.h"
47 #include "shlwapi.h"
48 #include "ocidl.h"
49 #include "objsafe.h"
51 #include "wine/debug.h"
52 #include "wine/list.h"
54 #include "msxml_private.h"
56 WINE_DEFAULT_DEBUG_CHANNEL(msxml);
58 #ifdef HAVE_LIBXML2
60 /* not defined in older versions */
61 #define XML_SAVE_FORMAT 1
62 #define XML_SAVE_NO_DECL 2
63 #define XML_SAVE_NO_EMPTY 4
64 #define XML_SAVE_NO_XHTML 8
65 #define XML_SAVE_XHTML 16
66 #define XML_SAVE_AS_XML 32
67 #define XML_SAVE_AS_HTML 64
69 static const WCHAR PropertySelectionLanguageW[] = {'S','e','l','e','c','t','i','o','n','L','a','n','g','u','a','g','e',0};
70 static const WCHAR PropertySelectionNamespacesW[] = {'S','e','l','e','c','t','i','o','n','N','a','m','e','s','p','a','c','e','s',0};
71 static const WCHAR PropertyProhibitDTDW[] = {'P','r','o','h','i','b','i','t','D','T','D',0};
72 static const WCHAR PropertyNewParserW[] = {'N','e','w','P','a','r','s','e','r',0};
73 static const WCHAR PropValueXPathW[] = {'X','P','a','t','h',0};
74 static const WCHAR PropValueXSLPatternW[] = {'X','S','L','P','a','t','t','e','r','n',0};
75 static const WCHAR PropertyResolveExternalsW[] = {'R','e','s','o','l','v','e','E','x','t','e','r','n','a','l','s',0};
77 /* Anything that passes the test_get_ownerDocument()
78 * tests can go here (data shared between all instances).
79 * We need to preserve this when reloading a document,
80 * and also need access to it from the libxml backend. */
81 typedef struct {
82 MSXML_VERSION version;
83 VARIANT_BOOL preserving;
84 IXMLDOMSchemaCollection2* schemaCache;
85 struct list selectNsList;
86 xmlChar const* selectNsStr;
87 LONG selectNsStr_len;
88 BOOL XPath;
89 } domdoc_properties;
91 typedef struct ConnectionPoint ConnectionPoint;
92 typedef struct domdoc domdoc;
94 struct ConnectionPoint
96 IConnectionPoint IConnectionPoint_iface;
97 const IID *iid;
99 ConnectionPoint *next;
100 IConnectionPointContainer *container;
101 domdoc *doc;
103 union
105 IUnknown *unk;
106 IDispatch *disp;
107 IPropertyNotifySink *propnotif;
108 } *sinks;
109 DWORD sinks_size;
112 typedef enum {
113 EVENTID_READYSTATECHANGE = 0,
114 EVENTID_DATAAVAILABLE,
115 EVENTID_TRANSFORMNODE,
116 EVENTID_LAST
117 } eventid_t;
119 struct domdoc
121 xmlnode node;
122 IXMLDOMDocument3 IXMLDOMDocument3_iface;
123 IPersistStreamInit IPersistStreamInit_iface;
124 IObjectWithSite IObjectWithSite_iface;
125 IObjectSafety IObjectSafety_iface;
126 IConnectionPointContainer IConnectionPointContainer_iface;
127 LONG ref;
128 VARIANT_BOOL async;
129 VARIANT_BOOL validating;
130 VARIANT_BOOL resolving;
131 domdoc_properties* properties;
132 bsc_t *bsc;
133 HRESULT error;
135 /* IObjectWithSite*/
136 IUnknown *site;
138 /* IObjectSafety */
139 DWORD safeopt;
141 /* connection list */
142 ConnectionPoint *cp_list;
143 ConnectionPoint cp_domdocevents;
144 ConnectionPoint cp_propnotif;
145 ConnectionPoint cp_dispatch;
147 /* events */
148 IDispatch *events[EVENTID_LAST];
150 IXMLDOMSchemaCollection2 *namespaces;
153 static HRESULT set_doc_event(domdoc *doc, eventid_t eid, const VARIANT *v)
155 IDispatch *disp;
157 switch (V_VT(v))
159 case VT_UNKNOWN:
160 if (V_UNKNOWN(v))
161 IUnknown_QueryInterface(V_UNKNOWN(v), &IID_IDispatch, (void**)&disp);
162 else
163 disp = NULL;
164 break;
165 case VT_DISPATCH:
166 disp = V_DISPATCH(v);
167 if (disp) IDispatch_AddRef(disp);
168 break;
169 default:
170 return DISP_E_TYPEMISMATCH;
173 if (doc->events[eid]) IDispatch_Release(doc->events[eid]);
174 doc->events[eid] = disp;
176 return S_OK;
179 static inline ConnectionPoint *impl_from_IConnectionPoint(IConnectionPoint *iface)
181 return CONTAINING_RECORD(iface, ConnectionPoint, IConnectionPoint_iface);
185 In native windows, the whole lifetime management of XMLDOMNodes is
186 managed automatically using reference counts. Wine emulates that by
187 maintaining a reference count to the document that is increased for
188 each IXMLDOMNode pointer passed out for this document. If all these
189 pointers are gone, the document is unreachable and gets freed, that
190 is, all nodes in the tree of the document get freed.
192 You are able to create nodes that are associated to a document (in
193 fact, in msxml's XMLDOM model, all nodes are associated to a document),
194 but not in the tree of that document, for example using the createFoo
195 functions from IXMLDOMDocument. These nodes do not get cleaned up
196 by libxml, so we have to do it ourselves.
198 To catch these nodes, a list of "orphan nodes" is introduced.
199 It contains pointers to all roots of node trees that are
200 associated with the document without being part of the document
201 tree. All nodes with parent==NULL (except for the document root nodes)
202 should be in the orphan node list of their document. All orphan nodes
203 get freed together with the document itself.
206 typedef struct _xmldoc_priv {
207 LONG refs;
208 struct list orphans;
209 domdoc_properties* properties;
210 } xmldoc_priv;
212 typedef struct _orphan_entry {
213 struct list entry;
214 xmlNode * node;
215 } orphan_entry;
217 typedef struct _select_ns_entry {
218 struct list entry;
219 xmlChar const* prefix;
220 xmlChar prefix_end;
221 xmlChar const* href;
222 xmlChar href_end;
223 } select_ns_entry;
225 static inline xmldoc_priv * priv_from_xmlDocPtr(const xmlDocPtr doc)
227 return doc->_private;
230 static inline domdoc_properties * properties_from_xmlDocPtr(xmlDocPtr doc)
232 return priv_from_xmlDocPtr(doc)->properties;
235 BOOL is_xpathmode(const xmlDocPtr doc)
237 return properties_from_xmlDocPtr(doc)->XPath;
240 void set_xpathmode(xmlDocPtr doc, BOOL xpath)
242 properties_from_xmlDocPtr(doc)->XPath = xpath;
245 int registerNamespaces(xmlXPathContextPtr ctxt)
247 int n = 0;
248 const select_ns_entry* ns = NULL;
249 const struct list* pNsList = &properties_from_xmlDocPtr(ctxt->doc)->selectNsList;
251 TRACE("(%p)\n", ctxt);
253 LIST_FOR_EACH_ENTRY( ns, pNsList, select_ns_entry, entry )
255 xmlXPathRegisterNs(ctxt, ns->prefix, ns->href);
256 ++n;
259 return n;
262 static inline void clear_selectNsList(struct list* pNsList)
264 select_ns_entry *ns, *ns2;
265 LIST_FOR_EACH_ENTRY_SAFE( ns, ns2, pNsList, select_ns_entry, entry )
267 heap_free( ns );
269 list_init(pNsList);
272 static xmldoc_priv * create_priv(void)
274 xmldoc_priv *priv;
275 priv = heap_alloc( sizeof (*priv) );
277 if (priv)
279 priv->refs = 0;
280 list_init( &priv->orphans );
281 priv->properties = NULL;
284 return priv;
287 static domdoc_properties *create_properties(MSXML_VERSION version)
289 domdoc_properties *properties = heap_alloc(sizeof(domdoc_properties));
291 list_init(&properties->selectNsList);
292 properties->preserving = VARIANT_FALSE;
293 properties->schemaCache = NULL;
294 properties->selectNsStr = heap_alloc_zero(sizeof(xmlChar));
295 properties->selectNsStr_len = 0;
297 /* properties that are dependent on object versions */
298 properties->version = version;
299 properties->XPath = (version == MSXML4 || version == MSXML6);
301 return properties;
304 static domdoc_properties* copy_properties(domdoc_properties const* properties)
306 domdoc_properties* pcopy = heap_alloc(sizeof(domdoc_properties));
307 select_ns_entry const* ns = NULL;
308 select_ns_entry* new_ns = NULL;
309 int len = (properties->selectNsStr_len+1)*sizeof(xmlChar);
310 ptrdiff_t offset;
312 if (pcopy)
314 pcopy->version = properties->version;
315 pcopy->preserving = properties->preserving;
316 pcopy->schemaCache = properties->schemaCache;
317 if (pcopy->schemaCache)
318 IXMLDOMSchemaCollection2_AddRef(pcopy->schemaCache);
319 pcopy->XPath = properties->XPath;
320 pcopy->selectNsStr_len = properties->selectNsStr_len;
321 list_init( &pcopy->selectNsList );
322 pcopy->selectNsStr = heap_alloc(len);
323 memcpy((xmlChar*)pcopy->selectNsStr, properties->selectNsStr, len);
324 offset = pcopy->selectNsStr - properties->selectNsStr;
326 LIST_FOR_EACH_ENTRY( ns, (&properties->selectNsList), select_ns_entry, entry )
328 new_ns = heap_alloc(sizeof(select_ns_entry));
329 memcpy(new_ns, ns, sizeof(select_ns_entry));
330 new_ns->href += offset;
331 new_ns->prefix += offset;
332 list_add_tail(&pcopy->selectNsList, &new_ns->entry);
337 return pcopy;
340 static void free_properties(domdoc_properties* properties)
342 if (properties)
344 if (properties->schemaCache)
345 IXMLDOMSchemaCollection2_Release(properties->schemaCache);
346 clear_selectNsList(&properties->selectNsList);
347 heap_free((xmlChar*)properties->selectNsStr);
348 heap_free(properties);
352 static void release_namespaces(domdoc *This)
354 if (This->namespaces)
356 IXMLDOMSchemaCollection2_Release(This->namespaces);
357 This->namespaces = NULL;
361 /* links a "<?xml" node as a first child */
362 void xmldoc_link_xmldecl(xmlDocPtr doc, xmlNodePtr node)
364 assert(doc != NULL);
365 if (doc->standalone != -1) xmlAddPrevSibling( doc->children, node );
368 /* unlinks a first "<?xml" child if it was created */
369 xmlNodePtr xmldoc_unlink_xmldecl(xmlDocPtr doc)
371 static const xmlChar xmlA[] = "xml";
372 xmlNodePtr node, first_child;
374 assert(doc != NULL);
376 /* xml declaration node could be created automatically after parsing or added
377 to a tree later */
378 first_child = doc->children;
379 if (first_child && first_child->type == XML_PI_NODE && xmlStrEqual(first_child->name, xmlA))
381 node = first_child;
382 xmlUnlinkNode( node );
384 else
385 node = NULL;
387 return node;
390 BOOL is_preserving_whitespace(xmlNodePtr node)
392 domdoc_properties* properties = NULL;
393 /* during parsing the xmlDoc._private stuff is not there */
394 if (priv_from_xmlDocPtr(node->doc))
395 properties = properties_from_xmlDocPtr(node->doc);
396 return ((properties && properties->preserving == VARIANT_TRUE) ||
397 xmlNodeGetSpacePreserve(node) == 1);
400 static inline BOOL strn_isspace(xmlChar const* str, int len)
402 for (; str && len > 0 && *str; ++str, --len)
403 if (!isspace(*str))
404 break;
406 return len == 0;
409 static void sax_characters(void *ctx, const xmlChar *ch, int len)
411 xmlParserCtxtPtr ctxt;
412 const domdoc *This;
414 ctxt = (xmlParserCtxtPtr) ctx;
415 This = (const domdoc*) ctxt->_private;
417 if (ctxt->node)
419 /* during domdoc_loadXML() the xmlDocPtr->_private data is not available */
420 if (!This->properties->preserving &&
421 !is_preserving_whitespace(ctxt->node) &&
422 strn_isspace(ch, len))
423 return;
426 xmlSAX2Characters(ctxt, ch, len);
429 static void LIBXML2_LOG_CALLBACK sax_error(void* ctx, char const* msg, ...)
431 va_list ap;
432 va_start(ap, msg);
433 LIBXML2_CALLBACK_ERR(doparse, msg, ap);
434 va_end(ap);
437 static void LIBXML2_LOG_CALLBACK sax_warning(void* ctx, char const* msg, ...)
439 va_list ap;
440 va_start(ap, msg);
441 LIBXML2_CALLBACK_WARN(doparse, msg, ap);
442 va_end(ap);
445 static void sax_serror(void* ctx, xmlErrorPtr err)
447 LIBXML2_CALLBACK_SERROR(doparse, err);
450 static xmlDocPtr doparse(domdoc* This, char const* ptr, int len, xmlCharEncoding encoding)
452 xmlDocPtr doc = NULL;
453 xmlParserCtxtPtr pctx;
454 static xmlSAXHandler sax_handler = {
455 xmlSAX2InternalSubset, /* internalSubset */
456 xmlSAX2IsStandalone, /* isStandalone */
457 xmlSAX2HasInternalSubset, /* hasInternalSubset */
458 xmlSAX2HasExternalSubset, /* hasExternalSubset */
459 xmlSAX2ResolveEntity, /* resolveEntity */
460 xmlSAX2GetEntity, /* getEntity */
461 xmlSAX2EntityDecl, /* entityDecl */
462 xmlSAX2NotationDecl, /* notationDecl */
463 xmlSAX2AttributeDecl, /* attributeDecl */
464 xmlSAX2ElementDecl, /* elementDecl */
465 xmlSAX2UnparsedEntityDecl, /* unparsedEntityDecl */
466 xmlSAX2SetDocumentLocator, /* setDocumentLocator */
467 xmlSAX2StartDocument, /* startDocument */
468 xmlSAX2EndDocument, /* endDocument */
469 xmlSAX2StartElement, /* startElement */
470 xmlSAX2EndElement, /* endElement */
471 xmlSAX2Reference, /* reference */
472 sax_characters, /* characters */
473 sax_characters, /* ignorableWhitespace */
474 xmlSAX2ProcessingInstruction, /* processingInstruction */
475 xmlSAX2Comment, /* comment */
476 sax_warning, /* warning */
477 sax_error, /* error */
478 sax_error, /* fatalError */
479 xmlSAX2GetParameterEntity, /* getParameterEntity */
480 xmlSAX2CDataBlock, /* cdataBlock */
481 xmlSAX2ExternalSubset, /* externalSubset */
482 0, /* initialized */
483 NULL, /* _private */
484 xmlSAX2StartElementNs, /* startElementNs */
485 xmlSAX2EndElementNs, /* endElementNs */
486 sax_serror /* serror */
489 pctx = xmlCreateMemoryParserCtxt(ptr, len);
490 if (!pctx)
492 ERR("Failed to create parser context\n");
493 return NULL;
496 if (pctx->sax) xmlFree(pctx->sax);
497 pctx->sax = &sax_handler;
498 pctx->_private = This;
499 pctx->recovery = 0;
501 if (encoding != XML_CHAR_ENCODING_NONE)
502 xmlSwitchEncoding(pctx, encoding);
504 xmlParseDocument(pctx);
506 if (pctx->wellFormed)
508 doc = pctx->myDoc;
510 else
512 xmlFreeDoc(pctx->myDoc);
513 pctx->myDoc = NULL;
515 pctx->sax = NULL;
516 xmlFreeParserCtxt(pctx);
518 /* TODO: put this in one of the SAX callbacks */
519 /* create first child as a <?xml...?> */
520 if (doc && doc->standalone != -1)
522 xmlNodePtr node;
523 char buff[30];
524 xmlChar *xmlbuff = (xmlChar*)buff;
526 node = xmlNewDocPI( doc, (xmlChar*)"xml", NULL );
528 /* version attribute can't be omitted */
529 sprintf(buff, "version=\"%s\"", doc->version ? (char*)doc->version : "1.0");
530 xmlNodeAddContent( node, xmlbuff );
532 if (doc->encoding)
534 sprintf(buff, " encoding=\"%s\"", doc->encoding);
535 xmlNodeAddContent( node, xmlbuff );
538 if (doc->standalone != -2)
540 sprintf(buff, " standalone=\"%s\"", doc->standalone == 0 ? "no" : "yes");
541 xmlNodeAddContent( node, xmlbuff );
544 xmldoc_link_xmldecl( doc, node );
547 return doc;
550 void xmldoc_init(xmlDocPtr doc, MSXML_VERSION version)
552 doc->_private = create_priv();
553 priv_from_xmlDocPtr(doc)->properties = create_properties(version);
556 LONG xmldoc_add_refs(xmlDocPtr doc, LONG refs)
558 LONG ref = InterlockedExchangeAdd(&priv_from_xmlDocPtr(doc)->refs, refs) + refs;
559 TRACE("(%p)->(%d)\n", doc, ref);
560 return ref;
563 LONG xmldoc_add_ref(xmlDocPtr doc)
565 return xmldoc_add_refs(doc, 1);
568 LONG xmldoc_release_refs(xmlDocPtr doc, LONG refs)
570 xmldoc_priv *priv = priv_from_xmlDocPtr(doc);
571 LONG ref = InterlockedExchangeAdd(&priv->refs, -refs) - refs;
572 TRACE("(%p)->(%d)\n", doc, ref);
574 if (ref < 0)
575 WARN("negative refcount, expect troubles\n");
577 if (ref == 0)
579 orphan_entry *orphan, *orphan2;
580 TRACE("freeing docptr %p\n", doc);
582 LIST_FOR_EACH_ENTRY_SAFE( orphan, orphan2, &priv->orphans, orphan_entry, entry )
584 xmlFreeNode( orphan->node );
585 heap_free( orphan );
587 free_properties(priv->properties);
588 heap_free(doc->_private);
590 xmlFreeDoc(doc);
593 return ref;
596 LONG xmldoc_release(xmlDocPtr doc)
598 return xmldoc_release_refs(doc, 1);
601 HRESULT xmldoc_add_orphan(xmlDocPtr doc, xmlNodePtr node)
603 xmldoc_priv *priv = priv_from_xmlDocPtr(doc);
604 orphan_entry *entry;
606 entry = heap_alloc( sizeof (*entry) );
607 if(!entry)
608 return E_OUTOFMEMORY;
610 entry->node = node;
611 list_add_head( &priv->orphans, &entry->entry );
612 return S_OK;
615 HRESULT xmldoc_remove_orphan(xmlDocPtr doc, xmlNodePtr node)
617 xmldoc_priv *priv = priv_from_xmlDocPtr(doc);
618 orphan_entry *entry, *entry2;
620 LIST_FOR_EACH_ENTRY_SAFE( entry, entry2, &priv->orphans, orphan_entry, entry )
622 if( entry->node == node )
624 list_remove( &entry->entry );
625 heap_free( entry );
626 return S_OK;
630 return S_FALSE;
633 static inline xmlDocPtr get_doc( domdoc *This )
635 return This->node.node->doc;
638 static HRESULT attach_xmldoc(domdoc *This, xmlDocPtr xml )
640 release_namespaces(This);
642 if(This->node.node)
644 priv_from_xmlDocPtr(get_doc(This))->properties = NULL;
645 if (xmldoc_release(get_doc(This)) != 0)
646 priv_from_xmlDocPtr(get_doc(This))->properties =
647 copy_properties(This->properties);
650 This->node.node = (xmlNodePtr) xml;
652 if(This->node.node)
654 xmldoc_add_ref(get_doc(This));
655 priv_from_xmlDocPtr(get_doc(This))->properties = This->properties;
658 return S_OK;
661 static inline domdoc *impl_from_IXMLDOMDocument3( IXMLDOMDocument3 *iface )
663 return CONTAINING_RECORD(iface, domdoc, IXMLDOMDocument3_iface);
666 static inline domdoc *impl_from_IPersistStreamInit(IPersistStreamInit *iface)
668 return CONTAINING_RECORD(iface, domdoc, IPersistStreamInit_iface);
671 static inline domdoc *impl_from_IObjectWithSite(IObjectWithSite *iface)
673 return CONTAINING_RECORD(iface, domdoc, IObjectWithSite_iface);
676 static inline domdoc *impl_from_IObjectSafety(IObjectSafety *iface)
678 return CONTAINING_RECORD(iface, domdoc, IObjectSafety_iface);
681 static inline domdoc *impl_from_IConnectionPointContainer(IConnectionPointContainer *iface)
683 return CONTAINING_RECORD(iface, domdoc, IConnectionPointContainer_iface);
686 /************************************************************************
687 * domdoc implementation of IPersistStream.
689 static HRESULT WINAPI PersistStreamInit_QueryInterface(
690 IPersistStreamInit *iface, REFIID riid, void **ppvObj)
692 domdoc* This = impl_from_IPersistStreamInit(iface);
693 return IXMLDOMDocument3_QueryInterface(&This->IXMLDOMDocument3_iface, riid, ppvObj);
696 static ULONG WINAPI PersistStreamInit_AddRef(
697 IPersistStreamInit *iface)
699 domdoc* This = impl_from_IPersistStreamInit(iface);
700 return IXMLDOMDocument3_AddRef(&This->IXMLDOMDocument3_iface);
703 static ULONG WINAPI PersistStreamInit_Release(
704 IPersistStreamInit *iface)
706 domdoc* This = impl_from_IPersistStreamInit(iface);
707 return IXMLDOMDocument3_Release(&This->IXMLDOMDocument3_iface);
710 static HRESULT WINAPI PersistStreamInit_GetClassID(
711 IPersistStreamInit *iface, CLSID *classid)
713 domdoc* This = impl_from_IPersistStreamInit(iface);
714 TRACE("(%p)->(%p)\n", This, classid);
716 if(!classid)
717 return E_POINTER;
719 *classid = *DOMDocument_version(This->properties->version);
721 return S_OK;
724 static HRESULT WINAPI PersistStreamInit_IsDirty(
725 IPersistStreamInit *iface)
727 domdoc *This = impl_from_IPersistStreamInit(iface);
728 FIXME("(%p): stub!\n", This);
729 return S_FALSE;
732 static HRESULT domdoc_load_from_stream(domdoc *doc, ISequentialStream *stream)
734 DWORD read, written, len;
735 xmlDocPtr xmldoc = NULL;
736 IStream *hstream;
737 HGLOBAL hglobal;
738 BYTE buf[4096];
739 HRESULT hr;
740 char *ptr;
742 hstream = NULL;
743 hr = CreateStreamOnHGlobal(NULL, TRUE, &hstream);
744 if (FAILED(hr))
745 return hr;
749 ISequentialStream_Read(stream, buf, sizeof(buf), &read);
750 hr = IStream_Write(hstream, buf, read, &written);
751 } while(SUCCEEDED(hr) && written != 0 && read != 0);
753 if (FAILED(hr))
755 ERR("failed to copy stream 0x%08x\n", hr);
756 IStream_Release(hstream);
757 return hr;
760 hr = GetHGlobalFromStream(hstream, &hglobal);
761 if (FAILED(hr))
762 return hr;
764 len = GlobalSize(hglobal);
765 ptr = GlobalLock(hglobal);
766 if (len)
767 xmldoc = doparse(doc, ptr, len, XML_CHAR_ENCODING_NONE);
768 GlobalUnlock(hglobal);
770 if (!xmldoc)
772 ERR("Failed to parse xml\n");
773 return E_FAIL;
776 xmldoc->_private = create_priv();
778 return attach_xmldoc(doc, xmldoc);
781 static HRESULT WINAPI PersistStreamInit_Load(IPersistStreamInit *iface, IStream *stream)
783 domdoc *This = impl_from_IPersistStreamInit(iface);
785 TRACE("(%p)->(%p)\n", This, stream);
787 if (!stream)
788 return E_INVALIDARG;
790 return domdoc_load_from_stream(This, (ISequentialStream*)stream);
793 static HRESULT WINAPI PersistStreamInit_Save(
794 IPersistStreamInit *iface, IStream *stream, BOOL clr_dirty)
796 domdoc *This = impl_from_IPersistStreamInit(iface);
797 BSTR xmlString;
798 HRESULT hr;
800 TRACE("(%p)->(%p %d)\n", This, stream, clr_dirty);
802 hr = IXMLDOMDocument3_get_xml(&This->IXMLDOMDocument3_iface, &xmlString);
803 if(hr == S_OK)
805 DWORD len = SysStringLen(xmlString) * sizeof(WCHAR);
807 hr = IStream_Write( stream, xmlString, len, NULL );
808 SysFreeString(xmlString);
811 TRACE("ret 0x%08x\n", hr);
813 return hr;
816 static HRESULT WINAPI PersistStreamInit_GetSizeMax(
817 IPersistStreamInit *iface, ULARGE_INTEGER *pcbSize)
819 domdoc *This = impl_from_IPersistStreamInit(iface);
820 TRACE("(%p)->(%p)\n", This, pcbSize);
821 return E_NOTIMPL;
824 static HRESULT WINAPI PersistStreamInit_InitNew(
825 IPersistStreamInit *iface)
827 domdoc *This = impl_from_IPersistStreamInit(iface);
828 TRACE("(%p)\n", This);
829 return S_OK;
832 static const IPersistStreamInitVtbl xmldoc_IPersistStreamInit_VTable =
834 PersistStreamInit_QueryInterface,
835 PersistStreamInit_AddRef,
836 PersistStreamInit_Release,
837 PersistStreamInit_GetClassID,
838 PersistStreamInit_IsDirty,
839 PersistStreamInit_Load,
840 PersistStreamInit_Save,
841 PersistStreamInit_GetSizeMax,
842 PersistStreamInit_InitNew
845 /* IXMLDOMDocument3 interface */
847 static const tid_t domdoc_se_tids[] = {
848 IXMLDOMNode_tid,
849 IXMLDOMDocument_tid,
850 IXMLDOMDocument2_tid,
851 IXMLDOMDocument3_tid,
855 static HRESULT WINAPI domdoc_QueryInterface( IXMLDOMDocument3 *iface, REFIID riid, void** ppvObject )
857 domdoc *This = impl_from_IXMLDOMDocument3( iface );
859 TRACE("(%p)->(%s %p)\n", This, debugstr_guid( riid ), ppvObject );
861 *ppvObject = NULL;
863 if ( IsEqualGUID( riid, &IID_IUnknown ) ||
864 IsEqualGUID( riid, &IID_IDispatch ) ||
865 IsEqualGUID( riid, &IID_IXMLDOMNode ) ||
866 IsEqualGUID( riid, &IID_IXMLDOMDocument ) ||
867 IsEqualGUID( riid, &IID_IXMLDOMDocument2 )||
868 IsEqualGUID( riid, &IID_IXMLDOMDocument3 ))
870 *ppvObject = iface;
872 else if (IsEqualGUID(&IID_IPersistStream, riid) ||
873 IsEqualGUID(&IID_IPersistStreamInit, riid))
875 *ppvObject = &This->IPersistStreamInit_iface;
877 else if (IsEqualGUID(&IID_IObjectWithSite, riid))
879 *ppvObject = &This->IObjectWithSite_iface;
881 else if (IsEqualGUID(&IID_IObjectSafety, riid))
883 *ppvObject = &This->IObjectSafety_iface;
885 else if( IsEqualGUID( riid, &IID_ISupportErrorInfo ))
887 return node_create_supporterrorinfo(domdoc_se_tids, ppvObject);
889 else if(node_query_interface(&This->node, riid, ppvObject))
891 return *ppvObject ? S_OK : E_NOINTERFACE;
893 else if (IsEqualGUID( riid, &IID_IConnectionPointContainer ))
895 *ppvObject = &This->IConnectionPointContainer_iface;
897 else
899 TRACE("interface %s not implemented\n", debugstr_guid(riid));
900 return E_NOINTERFACE;
903 IUnknown_AddRef((IUnknown*)*ppvObject);
905 return S_OK;
908 static ULONG WINAPI domdoc_AddRef( IXMLDOMDocument3 *iface )
910 domdoc *This = impl_from_IXMLDOMDocument3( iface );
911 ULONG ref = InterlockedIncrement( &This->ref );
912 TRACE("(%p)->(%d)\n", This, ref );
913 return ref;
916 static ULONG WINAPI domdoc_Release( IXMLDOMDocument3 *iface )
918 domdoc *This = impl_from_IXMLDOMDocument3( iface );
919 LONG ref = InterlockedDecrement( &This->ref );
921 TRACE("(%p)->(%d)\n", This, ref );
923 if ( ref == 0 )
925 int eid;
927 if(This->bsc)
928 detach_bsc(This->bsc);
930 if (This->site)
931 IUnknown_Release( This->site );
932 destroy_xmlnode(&This->node);
934 for (eid = 0; eid < EVENTID_LAST; eid++)
935 if (This->events[eid]) IDispatch_Release(This->events[eid]);
937 release_namespaces(This);
938 heap_free(This);
941 return ref;
944 static HRESULT WINAPI domdoc_GetTypeInfoCount( IXMLDOMDocument3 *iface, UINT* pctinfo )
946 domdoc *This = impl_from_IXMLDOMDocument3( iface );
947 return IDispatchEx_GetTypeInfoCount(&This->node.dispex.IDispatchEx_iface, pctinfo);
950 static HRESULT WINAPI domdoc_GetTypeInfo(
951 IXMLDOMDocument3 *iface,
952 UINT iTInfo, LCID lcid, ITypeInfo** ppTInfo )
954 domdoc *This = impl_from_IXMLDOMDocument3( iface );
955 return IDispatchEx_GetTypeInfo(&This->node.dispex.IDispatchEx_iface, iTInfo, lcid, ppTInfo);
958 static HRESULT WINAPI domdoc_GetIDsOfNames(
959 IXMLDOMDocument3 *iface,
960 REFIID riid,
961 LPOLESTR* rgszNames,
962 UINT cNames,
963 LCID lcid,
964 DISPID* rgDispId)
966 domdoc *This = impl_from_IXMLDOMDocument3( iface );
967 return IDispatchEx_GetIDsOfNames(&This->node.dispex.IDispatchEx_iface,
968 riid, rgszNames, cNames, lcid, rgDispId);
971 static HRESULT WINAPI domdoc_Invoke(
972 IXMLDOMDocument3 *iface,
973 DISPID dispIdMember,
974 REFIID riid,
975 LCID lcid,
976 WORD wFlags,
977 DISPPARAMS* pDispParams,
978 VARIANT* pVarResult,
979 EXCEPINFO* pExcepInfo,
980 UINT* puArgErr)
982 domdoc *This = impl_from_IXMLDOMDocument3( iface );
983 return IDispatchEx_Invoke(&This->node.dispex.IDispatchEx_iface,
984 dispIdMember, riid, lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
987 static HRESULT WINAPI domdoc_get_nodeName(
988 IXMLDOMDocument3 *iface,
989 BSTR* name )
991 domdoc *This = impl_from_IXMLDOMDocument3( iface );
993 static const WCHAR documentW[] = {'#','d','o','c','u','m','e','n','t',0};
995 TRACE("(%p)->(%p)\n", This, name);
997 return return_bstr(documentW, name);
1001 static HRESULT WINAPI domdoc_get_nodeValue(
1002 IXMLDOMDocument3 *iface,
1003 VARIANT* value )
1005 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1007 TRACE("(%p)->(%p)\n", This, value);
1009 if(!value)
1010 return E_INVALIDARG;
1012 V_VT(value) = VT_NULL;
1013 V_BSTR(value) = NULL; /* tests show that we should do this */
1014 return S_FALSE;
1018 static HRESULT WINAPI domdoc_put_nodeValue(
1019 IXMLDOMDocument3 *iface,
1020 VARIANT value)
1022 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1023 TRACE("(%p)->(%s)\n", This, debugstr_variant(&value));
1024 return E_FAIL;
1028 static HRESULT WINAPI domdoc_get_nodeType(
1029 IXMLDOMDocument3 *iface,
1030 DOMNodeType* type )
1032 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1034 TRACE("(%p)->(%p)\n", This, type);
1036 *type = NODE_DOCUMENT;
1037 return S_OK;
1041 static HRESULT WINAPI domdoc_get_parentNode(
1042 IXMLDOMDocument3 *iface,
1043 IXMLDOMNode** parent )
1045 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1047 TRACE("(%p)->(%p)\n", This, parent);
1049 return node_get_parent(&This->node, parent);
1053 static HRESULT WINAPI domdoc_get_childNodes(
1054 IXMLDOMDocument3 *iface,
1055 IXMLDOMNodeList** childList )
1057 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1059 TRACE("(%p)->(%p)\n", This, childList);
1061 return node_get_child_nodes(&This->node, childList);
1065 static HRESULT WINAPI domdoc_get_firstChild(
1066 IXMLDOMDocument3 *iface,
1067 IXMLDOMNode** firstChild )
1069 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1071 TRACE("(%p)->(%p)\n", This, firstChild);
1073 return node_get_first_child(&This->node, firstChild);
1077 static HRESULT WINAPI domdoc_get_lastChild(
1078 IXMLDOMDocument3 *iface,
1079 IXMLDOMNode** lastChild )
1081 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1083 TRACE("(%p)->(%p)\n", This, lastChild);
1085 return node_get_last_child(&This->node, lastChild);
1089 static HRESULT WINAPI domdoc_get_previousSibling(
1090 IXMLDOMDocument3 *iface,
1091 IXMLDOMNode** previousSibling )
1093 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1095 TRACE("(%p)->(%p)\n", This, previousSibling);
1097 return return_null_node(previousSibling);
1101 static HRESULT WINAPI domdoc_get_nextSibling(
1102 IXMLDOMDocument3 *iface,
1103 IXMLDOMNode** nextSibling )
1105 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1107 TRACE("(%p)->(%p)\n", This, nextSibling);
1109 return return_null_node(nextSibling);
1113 static HRESULT WINAPI domdoc_get_attributes(
1114 IXMLDOMDocument3 *iface,
1115 IXMLDOMNamedNodeMap** attributeMap )
1117 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1119 TRACE("(%p)->(%p)\n", This, attributeMap);
1121 return return_null_ptr((void**)attributeMap);
1125 static HRESULT WINAPI domdoc_insertBefore(
1126 IXMLDOMDocument3 *iface,
1127 IXMLDOMNode* newChild,
1128 VARIANT refChild,
1129 IXMLDOMNode** outNewChild )
1131 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1132 DOMNodeType type;
1133 HRESULT hr;
1135 TRACE("(%p)->(%p %s %p)\n", This, newChild, debugstr_variant(&refChild), outNewChild);
1137 hr = IXMLDOMNode_get_nodeType(newChild, &type);
1138 if (hr != S_OK) return hr;
1140 TRACE("new node type %d\n", type);
1141 switch (type)
1143 case NODE_ATTRIBUTE:
1144 case NODE_DOCUMENT:
1145 case NODE_CDATA_SECTION:
1146 if (outNewChild) *outNewChild = NULL;
1147 return E_FAIL;
1148 default:
1149 return node_insert_before(&This->node, newChild, &refChild, outNewChild);
1153 static HRESULT WINAPI domdoc_replaceChild(
1154 IXMLDOMDocument3 *iface,
1155 IXMLDOMNode* newChild,
1156 IXMLDOMNode* oldChild,
1157 IXMLDOMNode** outOldChild)
1159 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1161 TRACE("(%p)->(%p %p %p)\n", This, newChild, oldChild, outOldChild);
1163 return node_replace_child(&This->node, newChild, oldChild, outOldChild);
1167 static HRESULT WINAPI domdoc_removeChild(
1168 IXMLDOMDocument3 *iface,
1169 IXMLDOMNode *child,
1170 IXMLDOMNode **oldChild)
1172 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1173 TRACE("(%p)->(%p %p)\n", This, child, oldChild);
1174 return node_remove_child(&This->node, child, oldChild);
1178 static HRESULT WINAPI domdoc_appendChild(
1179 IXMLDOMDocument3 *iface,
1180 IXMLDOMNode *child,
1181 IXMLDOMNode **outChild)
1183 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1184 TRACE("(%p)->(%p %p)\n", This, child, outChild);
1185 return node_append_child(&This->node, child, outChild);
1189 static HRESULT WINAPI domdoc_hasChildNodes(
1190 IXMLDOMDocument3 *iface,
1191 VARIANT_BOOL *ret)
1193 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1194 TRACE("(%p)->(%p)\n", This, ret);
1195 return node_has_childnodes(&This->node, ret);
1199 static HRESULT WINAPI domdoc_get_ownerDocument(
1200 IXMLDOMDocument3 *iface,
1201 IXMLDOMDocument **doc)
1203 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1204 TRACE("(%p)->(%p)\n", This, doc);
1205 return node_get_owner_doc(&This->node, doc);
1209 static HRESULT WINAPI domdoc_cloneNode(
1210 IXMLDOMDocument3 *iface,
1211 VARIANT_BOOL deep,
1212 IXMLDOMNode** outNode)
1214 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1215 TRACE("(%p)->(%d %p)\n", This, deep, outNode);
1216 return node_clone( &This->node, deep, outNode );
1220 static HRESULT WINAPI domdoc_get_nodeTypeString(
1221 IXMLDOMDocument3 *iface,
1222 BSTR *p)
1224 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1225 static const WCHAR documentW[] = {'d','o','c','u','m','e','n','t',0};
1227 TRACE("(%p)->(%p)\n", This, p);
1229 return return_bstr(documentW, p);
1233 static HRESULT WINAPI domdoc_get_text(
1234 IXMLDOMDocument3 *iface,
1235 BSTR *p)
1237 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1238 TRACE("(%p)->(%p)\n", This, p);
1239 return node_get_text(&This->node, p);
1243 static HRESULT WINAPI domdoc_put_text(
1244 IXMLDOMDocument3 *iface,
1245 BSTR text )
1247 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1248 TRACE("(%p)->(%s)\n", This, debugstr_w(text));
1249 return E_FAIL;
1253 static HRESULT WINAPI domdoc_get_specified(
1254 IXMLDOMDocument3 *iface,
1255 VARIANT_BOOL* isSpecified )
1257 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1258 FIXME("(%p)->(%p) stub!\n", This, isSpecified);
1259 *isSpecified = VARIANT_TRUE;
1260 return S_OK;
1264 static HRESULT WINAPI domdoc_get_definition(
1265 IXMLDOMDocument3 *iface,
1266 IXMLDOMNode** definitionNode )
1268 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1269 FIXME("(%p)->(%p)\n", This, definitionNode);
1270 return E_NOTIMPL;
1274 static HRESULT WINAPI domdoc_get_nodeTypedValue(
1275 IXMLDOMDocument3 *iface,
1276 VARIANT* v )
1278 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1279 TRACE("(%p)->(%p)\n", This, v);
1280 return return_null_var(v);
1283 static HRESULT WINAPI domdoc_put_nodeTypedValue(
1284 IXMLDOMDocument3 *iface,
1285 VARIANT typedValue )
1287 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1288 FIXME("(%p)->(%s)\n", This, debugstr_variant(&typedValue));
1289 return E_NOTIMPL;
1293 static HRESULT WINAPI domdoc_get_dataType(
1294 IXMLDOMDocument3 *iface,
1295 VARIANT* typename )
1297 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1298 TRACE("(%p)->(%p)\n", This, typename);
1299 return return_null_var( typename );
1303 static HRESULT WINAPI domdoc_put_dataType(
1304 IXMLDOMDocument3 *iface,
1305 BSTR dataTypeName )
1307 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1309 FIXME("(%p)->(%s)\n", This, debugstr_w(dataTypeName));
1311 if(!dataTypeName)
1312 return E_INVALIDARG;
1314 return E_FAIL;
1317 static int XMLCALL domdoc_get_xml_writecallback(void *ctx, const char *data, int len)
1319 return xmlBufferAdd((xmlBufferPtr)ctx, (xmlChar*)data, len) == 0 ? len : 0;
1322 static HRESULT WINAPI domdoc_get_xml(
1323 IXMLDOMDocument3 *iface,
1324 BSTR* p)
1326 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1327 xmlSaveCtxtPtr ctxt;
1328 xmlBufferPtr buf;
1329 int options;
1330 long ret;
1332 TRACE("(%p)->(%p)\n", This, p);
1334 if(!p)
1335 return E_INVALIDARG;
1337 *p = NULL;
1339 buf = xmlBufferCreate();
1340 if(!buf)
1341 return E_OUTOFMEMORY;
1343 options = XML_SAVE_FORMAT | XML_SAVE_NO_DECL;
1344 ctxt = xmlSaveToIO(domdoc_get_xml_writecallback, NULL, buf, "UTF-8", options);
1346 if(!ctxt)
1348 xmlBufferFree(buf);
1349 return E_OUTOFMEMORY;
1352 ret = xmlSaveDoc(ctxt, get_doc(This));
1353 /* flushes on close */
1354 xmlSaveClose(ctxt);
1356 TRACE("%ld, len=%d\n", ret, xmlBufferLength(buf));
1357 if(ret != -1 && xmlBufferLength(buf) > 0)
1359 BSTR content;
1361 content = bstr_from_xmlChar(xmlBufferContent(buf));
1362 content = EnsureCorrectEOL(content);
1364 *p = content;
1366 else
1368 *p = SysAllocStringLen(NULL, 0);
1371 xmlBufferFree(buf);
1373 return *p ? S_OK : E_OUTOFMEMORY;
1377 static HRESULT WINAPI domdoc_transformNode(
1378 IXMLDOMDocument3 *iface,
1379 IXMLDOMNode *node,
1380 BSTR *p)
1382 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1383 TRACE("(%p)->(%p %p)\n", This, node, p);
1384 return node_transform_node(&This->node, node, p);
1388 static HRESULT WINAPI domdoc_selectNodes(
1389 IXMLDOMDocument3 *iface,
1390 BSTR p,
1391 IXMLDOMNodeList **outList)
1393 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1394 TRACE("(%p)->(%s %p)\n", This, debugstr_w(p), outList);
1395 return node_select_nodes(&This->node, p, outList);
1399 static HRESULT WINAPI domdoc_selectSingleNode(
1400 IXMLDOMDocument3 *iface,
1401 BSTR p,
1402 IXMLDOMNode **outNode)
1404 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1405 TRACE("(%p)->(%s %p)\n", This, debugstr_w(p), outNode);
1406 return node_select_singlenode(&This->node, p, outNode);
1410 static HRESULT WINAPI domdoc_get_parsed(
1411 IXMLDOMDocument3 *iface,
1412 VARIANT_BOOL* isParsed )
1414 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1415 FIXME("(%p)->(%p) stub!\n", This, isParsed);
1416 *isParsed = VARIANT_TRUE;
1417 return S_OK;
1420 static HRESULT WINAPI domdoc_get_namespaceURI(
1421 IXMLDOMDocument3 *iface,
1422 BSTR* namespaceURI )
1424 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1425 TRACE("(%p)->(%p)\n", This, namespaceURI);
1426 return return_null_bstr( namespaceURI );
1429 static HRESULT WINAPI domdoc_get_prefix(
1430 IXMLDOMDocument3 *iface,
1431 BSTR* prefix )
1433 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1434 TRACE("(%p)->(%p)\n", This, prefix);
1435 return return_null_bstr( prefix );
1439 static HRESULT WINAPI domdoc_get_baseName(
1440 IXMLDOMDocument3 *iface,
1441 BSTR* name )
1443 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1444 TRACE("(%p)->(%p)\n", This, name);
1445 return return_null_bstr( name );
1449 static HRESULT WINAPI domdoc_transformNodeToObject(
1450 IXMLDOMDocument3 *iface,
1451 IXMLDOMNode* stylesheet,
1452 VARIANT outputObject)
1454 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1455 FIXME("(%p)->(%p %s)\n", This, stylesheet, debugstr_variant(&outputObject));
1456 return E_NOTIMPL;
1460 static HRESULT WINAPI domdoc_get_doctype(
1461 IXMLDOMDocument3 *iface,
1462 IXMLDOMDocumentType** doctype )
1464 domdoc *This = impl_from_IXMLDOMDocument3(iface);
1465 IXMLDOMNode *node;
1466 xmlDtdPtr dtd;
1467 HRESULT hr;
1469 TRACE("(%p)->(%p)\n", This, doctype);
1471 if (!doctype) return E_INVALIDARG;
1473 *doctype = NULL;
1475 dtd = xmlGetIntSubset(get_doc(This));
1476 if (!dtd) return S_FALSE;
1478 node = create_node((xmlNodePtr)dtd);
1479 if (!node) return S_FALSE;
1481 hr = IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMDocumentType, (void**)doctype);
1482 IXMLDOMNode_Release(node);
1484 return hr;
1488 static HRESULT WINAPI domdoc_get_implementation(
1489 IXMLDOMDocument3 *iface,
1490 IXMLDOMImplementation** impl )
1492 domdoc *This = impl_from_IXMLDOMDocument3(iface);
1494 TRACE("(%p)->(%p)\n", This, impl);
1496 if(!impl)
1497 return E_INVALIDARG;
1499 *impl = (IXMLDOMImplementation*)create_doc_Implementation();
1501 return S_OK;
1504 static HRESULT WINAPI domdoc_get_documentElement(
1505 IXMLDOMDocument3 *iface,
1506 IXMLDOMElement** DOMElement )
1508 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1509 IXMLDOMNode *element_node;
1510 xmlNodePtr root;
1511 HRESULT hr;
1513 TRACE("(%p)->(%p)\n", This, DOMElement);
1515 if(!DOMElement)
1516 return E_INVALIDARG;
1518 *DOMElement = NULL;
1520 root = xmlDocGetRootElement( get_doc(This) );
1521 if ( !root )
1522 return S_FALSE;
1524 element_node = create_node( root );
1525 if(!element_node) return S_FALSE;
1527 hr = IXMLDOMNode_QueryInterface(element_node, &IID_IXMLDOMElement, (void**)DOMElement);
1528 IXMLDOMNode_Release(element_node);
1530 return hr;
1534 static HRESULT WINAPI domdoc_put_documentElement(
1535 IXMLDOMDocument3 *iface,
1536 IXMLDOMElement* DOMElement )
1538 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1539 IXMLDOMNode *elementNode;
1540 xmlNodePtr oldRoot;
1541 xmlDocPtr old_doc;
1542 xmlnode *xmlNode;
1543 int refcount = 0;
1544 HRESULT hr;
1546 TRACE("(%p)->(%p)\n", This, DOMElement);
1548 hr = IXMLDOMElement_QueryInterface( DOMElement, &IID_IXMLDOMNode, (void**)&elementNode );
1549 if(FAILED(hr))
1550 return hr;
1552 xmlNode = get_node_obj( elementNode );
1553 if(!xmlNode) return E_FAIL;
1555 if(!xmlNode->node->parent)
1556 if(xmldoc_remove_orphan(xmlNode->node->doc, xmlNode->node) != S_OK)
1557 WARN("%p is not an orphan of %p\n", xmlNode->node->doc, xmlNode->node);
1559 old_doc = xmlNode->node->doc;
1560 if (old_doc != get_doc(This))
1561 refcount = xmlnode_get_inst_cnt(xmlNode);
1563 /* old root is still orphaned by its document, update refcount from new root */
1564 if (refcount) xmldoc_add_refs(get_doc(This), refcount);
1565 oldRoot = xmlDocSetRootElement( get_doc(This), xmlNode->node);
1566 if (refcount) xmldoc_release_refs(old_doc, refcount);
1567 IXMLDOMNode_Release( elementNode );
1569 if(oldRoot)
1570 xmldoc_add_orphan(oldRoot->doc, oldRoot);
1572 return S_OK;
1576 static HRESULT WINAPI domdoc_createElement(
1577 IXMLDOMDocument3 *iface,
1578 BSTR tagname,
1579 IXMLDOMElement** element )
1581 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1582 IXMLDOMNode *node;
1583 VARIANT type;
1584 HRESULT hr;
1586 TRACE("(%p)->(%s %p)\n", This, debugstr_w(tagname), element);
1588 if (!element || !tagname) return E_INVALIDARG;
1590 V_VT(&type) = VT_I1;
1591 V_I1(&type) = NODE_ELEMENT;
1593 hr = IXMLDOMDocument3_createNode(iface, type, tagname, NULL, &node);
1594 if (hr == S_OK)
1596 IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMElement, (void**)element);
1597 IXMLDOMNode_Release(node);
1600 return hr;
1604 static HRESULT WINAPI domdoc_createDocumentFragment(
1605 IXMLDOMDocument3 *iface,
1606 IXMLDOMDocumentFragment** frag )
1608 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1609 IXMLDOMNode *node;
1610 VARIANT type;
1611 HRESULT hr;
1613 TRACE("(%p)->(%p)\n", This, frag);
1615 if (!frag) return E_INVALIDARG;
1617 *frag = NULL;
1619 V_VT(&type) = VT_I1;
1620 V_I1(&type) = NODE_DOCUMENT_FRAGMENT;
1622 hr = IXMLDOMDocument3_createNode(iface, type, NULL, NULL, &node);
1623 if (hr == S_OK)
1625 IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMDocumentFragment, (void**)frag);
1626 IXMLDOMNode_Release(node);
1629 return hr;
1633 static HRESULT WINAPI domdoc_createTextNode(
1634 IXMLDOMDocument3 *iface,
1635 BSTR data,
1636 IXMLDOMText** text )
1638 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1639 IXMLDOMNode *node;
1640 VARIANT type;
1641 HRESULT hr;
1643 TRACE("(%p)->(%s %p)\n", This, debugstr_w(data), text);
1645 if (!text) return E_INVALIDARG;
1647 *text = NULL;
1649 V_VT(&type) = VT_I1;
1650 V_I1(&type) = NODE_TEXT;
1652 hr = IXMLDOMDocument3_createNode(iface, type, NULL, NULL, &node);
1653 if (hr == S_OK)
1655 IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMText, (void**)text);
1656 IXMLDOMNode_Release(node);
1657 hr = IXMLDOMText_put_data(*text, data);
1660 return hr;
1664 static HRESULT WINAPI domdoc_createComment(
1665 IXMLDOMDocument3 *iface,
1666 BSTR data,
1667 IXMLDOMComment** comment )
1669 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1670 VARIANT type;
1671 HRESULT hr;
1672 IXMLDOMNode *node;
1674 TRACE("(%p)->(%s %p)\n", This, debugstr_w(data), comment);
1676 if (!comment) return E_INVALIDARG;
1678 *comment = NULL;
1680 V_VT(&type) = VT_I1;
1681 V_I1(&type) = NODE_COMMENT;
1683 hr = IXMLDOMDocument3_createNode(iface, type, NULL, NULL, &node);
1684 if (hr == S_OK)
1686 IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMComment, (void**)comment);
1687 IXMLDOMNode_Release(node);
1688 hr = IXMLDOMComment_put_data(*comment, data);
1691 return hr;
1695 static HRESULT WINAPI domdoc_createCDATASection(
1696 IXMLDOMDocument3 *iface,
1697 BSTR data,
1698 IXMLDOMCDATASection** cdata )
1700 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1701 IXMLDOMNode *node;
1702 VARIANT type;
1703 HRESULT hr;
1705 TRACE("(%p)->(%s %p)\n", This, debugstr_w(data), cdata);
1707 if (!cdata) return E_INVALIDARG;
1709 *cdata = NULL;
1711 V_VT(&type) = VT_I1;
1712 V_I1(&type) = NODE_CDATA_SECTION;
1714 hr = IXMLDOMDocument3_createNode(iface, type, NULL, NULL, &node);
1715 if (hr == S_OK)
1717 IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMCDATASection, (void**)cdata);
1718 IXMLDOMNode_Release(node);
1719 hr = IXMLDOMCDATASection_put_data(*cdata, data);
1722 return hr;
1726 static HRESULT WINAPI domdoc_createProcessingInstruction(
1727 IXMLDOMDocument3 *iface,
1728 BSTR target,
1729 BSTR data,
1730 IXMLDOMProcessingInstruction** pi )
1732 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1733 IXMLDOMNode *node;
1734 VARIANT type;
1735 HRESULT hr;
1737 TRACE("(%p)->(%s %s %p)\n", This, debugstr_w(target), debugstr_w(data), pi);
1739 if (!pi) return E_INVALIDARG;
1741 *pi = NULL;
1743 V_VT(&type) = VT_I1;
1744 V_I1(&type) = NODE_PROCESSING_INSTRUCTION;
1746 hr = IXMLDOMDocument3_createNode(iface, type, target, NULL, &node);
1747 if (hr == S_OK)
1749 xmlnode *node_obj;
1751 /* this is to bypass check in ::put_data() that blocks "<?xml" PIs */
1752 node_obj = get_node_obj(node);
1753 hr = node_set_content(node_obj, data);
1755 IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMProcessingInstruction, (void**)pi);
1756 IXMLDOMNode_Release(node);
1759 return hr;
1763 static HRESULT WINAPI domdoc_createAttribute(
1764 IXMLDOMDocument3 *iface,
1765 BSTR name,
1766 IXMLDOMAttribute** attribute )
1768 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1769 IXMLDOMNode *node;
1770 VARIANT type;
1771 HRESULT hr;
1773 TRACE("(%p)->(%s %p)\n", This, debugstr_w(name), attribute);
1775 if (!attribute || !name) return E_INVALIDARG;
1777 V_VT(&type) = VT_I1;
1778 V_I1(&type) = NODE_ATTRIBUTE;
1780 hr = IXMLDOMDocument3_createNode(iface, type, name, NULL, &node);
1781 if (hr == S_OK)
1783 IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMAttribute, (void**)attribute);
1784 IXMLDOMNode_Release(node);
1787 return hr;
1791 static HRESULT WINAPI domdoc_createEntityReference(
1792 IXMLDOMDocument3 *iface,
1793 BSTR name,
1794 IXMLDOMEntityReference** entityref )
1796 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1797 IXMLDOMNode *node;
1798 VARIANT type;
1799 HRESULT hr;
1801 TRACE("(%p)->(%s %p)\n", This, debugstr_w(name), entityref);
1803 if (!entityref) return E_INVALIDARG;
1805 *entityref = NULL;
1807 V_VT(&type) = VT_I1;
1808 V_I1(&type) = NODE_ENTITY_REFERENCE;
1810 hr = IXMLDOMDocument3_createNode(iface, type, name, NULL, &node);
1811 if (hr == S_OK)
1813 IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMEntityReference, (void**)entityref);
1814 IXMLDOMNode_Release(node);
1817 return hr;
1820 xmlChar* tagName_to_XPath(const BSTR tagName)
1822 xmlChar *query, *tmp;
1823 static const xmlChar mod_pre[] = "*[local-name()='";
1824 static const xmlChar mod_post[] = "']";
1825 static const xmlChar prefix[] = "descendant::";
1826 const WCHAR *tokBegin, *tokEnd;
1827 int len;
1829 query = xmlStrdup(prefix);
1831 tokBegin = tagName;
1832 while (tokBegin && *tokBegin)
1834 switch (*tokBegin)
1836 case '/':
1837 query = xmlStrcat(query, BAD_CAST "/");
1838 ++tokBegin;
1839 break;
1840 case '*':
1841 query = xmlStrcat(query, BAD_CAST "*");
1842 ++tokBegin;
1843 break;
1844 default:
1845 query = xmlStrcat(query, mod_pre);
1846 tokEnd = tokBegin;
1847 while (*tokEnd && *tokEnd != '/')
1848 ++tokEnd;
1849 len = WideCharToMultiByte(CP_UTF8, 0, tokBegin, tokEnd-tokBegin, NULL, 0, NULL, NULL);
1850 tmp = xmlMalloc(len);
1851 WideCharToMultiByte(CP_UTF8, 0, tokBegin, tokEnd-tokBegin, (char*)tmp, len, NULL, NULL);
1852 query = xmlStrncat(query, tmp, len);
1853 xmlFree(tmp);
1854 tokBegin = tokEnd;
1855 query = xmlStrcat(query, mod_post);
1859 return query;
1862 static HRESULT WINAPI domdoc_getElementsByTagName(
1863 IXMLDOMDocument3 *iface,
1864 BSTR tagName,
1865 IXMLDOMNodeList** resultList )
1867 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1868 xmlChar *query;
1869 HRESULT hr;
1870 BOOL XPath;
1872 TRACE("(%p)->(%s, %p)\n", This, debugstr_w(tagName), resultList);
1874 if (!tagName || !resultList) return E_INVALIDARG;
1876 XPath = This->properties->XPath;
1877 This->properties->XPath = TRUE;
1878 query = tagName_to_XPath(tagName);
1879 hr = create_selection((xmlNodePtr)get_doc(This), query, resultList);
1880 xmlFree(query);
1881 This->properties->XPath = XPath;
1883 return hr;
1886 static HRESULT get_node_type(VARIANT Type, DOMNodeType * type)
1888 VARIANT tmp;
1889 HRESULT hr;
1891 VariantInit(&tmp);
1892 hr = VariantChangeType(&tmp, &Type, 0, VT_I4);
1893 if(FAILED(hr))
1894 return E_INVALIDARG;
1896 *type = V_I4(&tmp);
1898 return S_OK;
1901 static HRESULT WINAPI domdoc_createNode(
1902 IXMLDOMDocument3 *iface,
1903 VARIANT Type,
1904 BSTR name,
1905 BSTR namespaceURI,
1906 IXMLDOMNode** node )
1908 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1909 DOMNodeType node_type;
1910 xmlNodePtr xmlnode;
1911 xmlChar *xml_name, *href;
1912 HRESULT hr;
1914 TRACE("(%p)->(%s %s %s %p)\n", This, debugstr_variant(&Type), debugstr_w(name), debugstr_w(namespaceURI), node);
1916 if(!node) return E_INVALIDARG;
1918 hr = get_node_type(Type, &node_type);
1919 if(FAILED(hr)) return hr;
1921 if(namespaceURI && namespaceURI[0] && node_type != NODE_ELEMENT)
1922 FIXME("nodes with namespaces currently not supported.\n");
1924 TRACE("node_type %d\n", node_type);
1926 /* exit earlier for types that need name */
1927 switch(node_type)
1929 case NODE_ELEMENT:
1930 case NODE_ATTRIBUTE:
1931 case NODE_ENTITY_REFERENCE:
1932 case NODE_PROCESSING_INSTRUCTION:
1933 if (!name || *name == 0) return E_FAIL;
1934 break;
1935 default:
1936 break;
1939 xml_name = xmlchar_from_wchar(name);
1940 /* prevent empty href to be allocated */
1941 href = namespaceURI ? xmlchar_from_wchar(namespaceURI) : NULL;
1943 switch(node_type)
1945 case NODE_ELEMENT:
1947 xmlChar *local, *prefix;
1949 local = xmlSplitQName2(xml_name, &prefix);
1951 xmlnode = xmlNewDocNode(get_doc(This), NULL, local ? local : xml_name, NULL);
1953 /* allow to create default namespace xmlns= */
1954 if (local || (href && *href))
1956 xmlNsPtr ns = xmlNewNs(xmlnode, href, prefix);
1957 xmlSetNs(xmlnode, ns);
1960 xmlFree(local);
1961 xmlFree(prefix);
1963 break;
1965 case NODE_ATTRIBUTE:
1966 xmlnode = (xmlNodePtr)xmlNewDocProp(get_doc(This), xml_name, NULL);
1967 break;
1968 case NODE_TEXT:
1969 xmlnode = (xmlNodePtr)xmlNewDocText(get_doc(This), NULL);
1970 break;
1971 case NODE_CDATA_SECTION:
1972 xmlnode = xmlNewCDataBlock(get_doc(This), NULL, 0);
1973 break;
1974 case NODE_ENTITY_REFERENCE:
1975 xmlnode = xmlNewReference(get_doc(This), xml_name);
1976 break;
1977 case NODE_PROCESSING_INSTRUCTION:
1978 #ifdef HAVE_XMLNEWDOCPI
1979 xmlnode = xmlNewDocPI(get_doc(This), xml_name, NULL);
1980 #else
1981 FIXME("xmlNewDocPI() not supported, use libxml2 2.6.15 or greater\n");
1982 xmlnode = NULL;
1983 #endif
1984 break;
1985 case NODE_COMMENT:
1986 xmlnode = xmlNewDocComment(get_doc(This), NULL);
1987 break;
1988 case NODE_DOCUMENT_FRAGMENT:
1989 xmlnode = xmlNewDocFragment(get_doc(This));
1990 break;
1991 /* unsupported types */
1992 case NODE_DOCUMENT:
1993 case NODE_DOCUMENT_TYPE:
1994 case NODE_ENTITY:
1995 case NODE_NOTATION:
1996 heap_free(xml_name);
1997 return E_INVALIDARG;
1998 default:
1999 FIXME("unhandled node type %d\n", node_type);
2000 xmlnode = NULL;
2001 break;
2004 *node = create_node(xmlnode);
2005 heap_free(xml_name);
2006 heap_free(href);
2008 if(*node)
2010 TRACE("created node (%d, %p, %p)\n", node_type, *node, xmlnode);
2011 xmldoc_add_orphan(xmlnode->doc, xmlnode);
2012 return S_OK;
2015 return E_FAIL;
2018 static HRESULT WINAPI domdoc_nodeFromID(
2019 IXMLDOMDocument3 *iface,
2020 BSTR idString,
2021 IXMLDOMNode** node )
2023 domdoc *This = impl_from_IXMLDOMDocument3(iface);
2024 FIXME("(%p)->(%s %p)\n", This, debugstr_w(idString), node);
2025 return E_NOTIMPL;
2028 static HRESULT domdoc_onDataAvailable(void *obj, char *ptr, DWORD len)
2030 domdoc *This = obj;
2031 xmlDocPtr xmldoc;
2033 xmldoc = doparse(This, ptr, len, XML_CHAR_ENCODING_NONE);
2034 if(xmldoc) {
2035 xmldoc->_private = create_priv();
2036 return attach_xmldoc(This, xmldoc);
2039 return S_OK;
2042 static HRESULT domdoc_load_moniker(domdoc *This, IMoniker *mon)
2044 bsc_t *bsc;
2045 HRESULT hr;
2047 hr = bind_url(mon, domdoc_onDataAvailable, This, &bsc);
2048 if(FAILED(hr))
2049 return hr;
2051 if(This->bsc) {
2052 hr = detach_bsc(This->bsc);
2053 if(FAILED(hr))
2054 return hr;
2057 This->bsc = bsc;
2058 return S_OK;
2061 static HRESULT WINAPI domdoc_load(
2062 IXMLDOMDocument3 *iface,
2063 VARIANT source,
2064 VARIANT_BOOL* isSuccessful )
2066 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2067 LPWSTR filename = NULL;
2068 HRESULT hr = S_FALSE;
2069 xmlDocPtr xmldoc;
2071 TRACE("(%p)->(%s)\n", This, debugstr_variant(&source));
2073 if (!isSuccessful)
2074 return E_POINTER;
2075 *isSuccessful = VARIANT_FALSE;
2077 assert( &This->node );
2079 switch( V_VT(&source) )
2081 case VT_BSTR:
2082 filename = V_BSTR(&source);
2083 break;
2084 case VT_BSTR|VT_BYREF:
2085 if (!V_BSTRREF(&source)) return E_INVALIDARG;
2086 filename = *V_BSTRREF(&source);
2087 break;
2088 case VT_ARRAY|VT_UI1:
2090 SAFEARRAY *psa = V_ARRAY(&source);
2091 char *str;
2092 LONG len;
2093 UINT dim = SafeArrayGetDim(psa);
2095 switch (dim)
2097 case 0:
2098 ERR("SAFEARRAY == NULL\n");
2099 hr = This->error = E_INVALIDARG;
2100 break;
2101 case 1:
2102 /* Only takes UTF-8 strings.
2103 * NOT NULL-terminated. */
2104 SafeArrayAccessData(psa, (void**)&str);
2105 SafeArrayGetUBound(psa, 1, &len);
2107 if ((xmldoc = doparse(This, str, ++len, XML_CHAR_ENCODING_UTF8)))
2109 hr = This->error = S_OK;
2110 *isSuccessful = VARIANT_TRUE;
2111 TRACE("parsed document %p\n", xmldoc);
2113 else
2115 This->error = E_FAIL;
2116 TRACE("failed to parse document\n");
2119 SafeArrayUnaccessData(psa);
2121 if(xmldoc)
2123 xmldoc->_private = create_priv();
2124 return attach_xmldoc(This, xmldoc);
2126 break;
2127 default:
2128 FIXME("unhandled SAFEARRAY dim: %d\n", dim);
2129 hr = This->error = E_NOTIMPL;
2132 break;
2133 case VT_UNKNOWN:
2135 ISequentialStream *stream = NULL;
2136 IXMLDOMDocument3 *newdoc = NULL;
2138 if (!V_UNKNOWN(&source)) return E_INVALIDARG;
2140 hr = IUnknown_QueryInterface(V_UNKNOWN(&source), &IID_IXMLDOMDocument3, (void**)&newdoc);
2141 if(hr == S_OK)
2143 if(newdoc)
2145 domdoc *newDoc = impl_from_IXMLDOMDocument3( newdoc );
2147 xmldoc = xmlCopyDoc(get_doc(newDoc), 1);
2148 xmldoc->_private = create_priv();
2149 hr = attach_xmldoc(This, xmldoc);
2151 if(SUCCEEDED(hr))
2152 *isSuccessful = VARIANT_TRUE;
2154 return hr;
2158 hr = IUnknown_QueryInterface(V_UNKNOWN(&source), &IID_IStream, (void**)&stream);
2159 if (FAILED(hr))
2160 hr = IUnknown_QueryInterface(V_UNKNOWN(&source), &IID_ISequentialStream, (void**)&stream);
2162 if (hr == S_OK)
2164 hr = domdoc_load_from_stream(This, stream);
2165 if (hr == S_OK)
2166 *isSuccessful = VARIANT_TRUE;
2167 ISequentialStream_Release(stream);
2168 return hr;
2171 FIXME("unsupported IUnknown type (0x%08x) (%p)\n", hr, V_UNKNOWN(&source)->lpVtbl);
2172 break;
2174 default:
2175 FIXME("VT type not supported (%d)\n", V_VT(&source));
2178 if ( filename )
2180 IMoniker *mon;
2182 hr = create_moniker_from_url( filename, &mon);
2183 if ( SUCCEEDED(hr) )
2185 hr = domdoc_load_moniker( This, mon );
2186 IMoniker_Release(mon);
2189 if ( FAILED(hr) )
2190 This->error = E_FAIL;
2191 else
2193 hr = This->error = S_OK;
2194 *isSuccessful = VARIANT_TRUE;
2198 if(!filename || FAILED(hr)) {
2199 xmldoc = xmlNewDoc(NULL);
2200 xmldoc->_private = create_priv();
2201 hr = attach_xmldoc(This, xmldoc);
2202 if(SUCCEEDED(hr))
2203 hr = S_FALSE;
2206 TRACE("ret (%d)\n", hr);
2208 return hr;
2212 static HRESULT WINAPI domdoc_get_readyState(
2213 IXMLDOMDocument3 *iface,
2214 LONG *value )
2216 domdoc *This = impl_from_IXMLDOMDocument3(iface);
2217 FIXME("stub! (%p)->(%p)\n", This, value);
2219 if (!value)
2220 return E_INVALIDARG;
2222 *value = READYSTATE_COMPLETE;
2223 return S_OK;
2227 static HRESULT WINAPI domdoc_get_parseError(
2228 IXMLDOMDocument3 *iface,
2229 IXMLDOMParseError** errorObj )
2231 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2232 static const WCHAR err[] = {'e','r','r','o','r',0};
2233 BSTR error_string = NULL;
2235 FIXME("(%p)->(%p): creating a dummy parseError\n", iface, errorObj);
2237 if(This->error)
2238 error_string = SysAllocString(err);
2240 *errorObj = create_parseError(This->error, NULL, error_string, NULL, 0, 0, 0);
2241 if(!*errorObj) return E_OUTOFMEMORY;
2242 return S_OK;
2246 static HRESULT WINAPI domdoc_get_url(
2247 IXMLDOMDocument3 *iface,
2248 BSTR* urlString )
2250 domdoc *This = impl_from_IXMLDOMDocument3(iface);
2251 FIXME("(%p)->(%p)\n", This, urlString);
2252 return E_NOTIMPL;
2256 static HRESULT WINAPI domdoc_get_async(
2257 IXMLDOMDocument3 *iface,
2258 VARIANT_BOOL* isAsync )
2260 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2262 TRACE("(%p)->(%p: %d)\n", This, isAsync, This->async);
2263 *isAsync = This->async;
2264 return S_OK;
2268 static HRESULT WINAPI domdoc_put_async(
2269 IXMLDOMDocument3 *iface,
2270 VARIANT_BOOL isAsync )
2272 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2274 TRACE("(%p)->(%d)\n", This, isAsync);
2275 This->async = isAsync;
2276 return S_OK;
2280 static HRESULT WINAPI domdoc_abort(
2281 IXMLDOMDocument3 *iface )
2283 domdoc *This = impl_from_IXMLDOMDocument3(iface);
2284 FIXME("%p\n", This);
2285 return E_NOTIMPL;
2288 /* don't rely on data to be in BSTR format, treat it as WCHAR string */
2289 static HRESULT WINAPI domdoc_loadXML(
2290 IXMLDOMDocument3 *iface,
2291 BSTR data,
2292 VARIANT_BOOL* isSuccessful )
2294 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2295 xmlDocPtr xmldoc = NULL;
2296 HRESULT hr = S_FALSE, hr2;
2298 TRACE("(%p)->(%s %p)\n", This, debugstr_w(data), isSuccessful );
2300 assert ( &This->node );
2302 if ( isSuccessful )
2304 *isSuccessful = VARIANT_FALSE;
2306 if (data)
2308 WCHAR *ptr = data;
2310 /* skip leading spaces if needed */
2311 if (This->properties->version == MSXML_DEFAULT || This->properties->version == MSXML26)
2312 while (*ptr && isspaceW(*ptr)) ptr++;
2314 xmldoc = doparse(This, (char*)ptr, strlenW(ptr)*sizeof(WCHAR), XML_CHAR_ENCODING_UTF16LE);
2315 if ( !xmldoc )
2317 This->error = E_FAIL;
2318 TRACE("failed to parse document\n");
2320 else
2322 hr = This->error = S_OK;
2323 *isSuccessful = VARIANT_TRUE;
2324 TRACE("parsed document %p\n", xmldoc);
2329 if(!xmldoc)
2330 xmldoc = xmlNewDoc(NULL);
2331 xmldoc->_private = create_priv();
2332 hr2 = attach_xmldoc(This, xmldoc);
2333 if( FAILED(hr2) )
2334 hr = hr2;
2336 return hr;
2339 static int XMLCALL domdoc_save_writecallback(void *ctx, const char *buffer, int len)
2341 DWORD written = -1;
2343 if(!WriteFile(ctx, buffer, len, &written, NULL))
2345 WARN("write error\n");
2346 return -1;
2348 else
2349 return written;
2352 static int XMLCALL domdoc_save_closecallback(void *ctx)
2354 return CloseHandle(ctx) ? 0 : -1;
2357 static int XMLCALL domdoc_stream_save_writecallback(void *ctx, const char *buffer, int len)
2359 ULONG written = 0;
2360 HRESULT hr;
2362 hr = IStream_Write((IStream*)ctx, buffer, len, &written);
2363 TRACE("0x%08x %p %d %u\n", hr, buffer, len, written);
2364 if (hr != S_OK)
2366 WARN("stream write error: 0x%08x\n", hr);
2367 return -1;
2369 else
2370 return len;
2373 static int XMLCALL domdoc_stream_save_closecallback(void *ctx)
2375 IStream_Release((IStream*)ctx);
2376 return 0;
2379 static HRESULT WINAPI domdoc_save(
2380 IXMLDOMDocument3 *iface,
2381 VARIANT destination )
2383 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2384 xmlSaveCtxtPtr ctx = NULL;
2385 xmlNodePtr xmldecl;
2386 HRESULT ret = S_OK;
2388 TRACE("(%p)->(%s)\n", This, debugstr_variant(&destination));
2390 switch (V_VT(&destination))
2392 case VT_UNKNOWN:
2394 IUnknown *pUnk = V_UNKNOWN(&destination);
2395 IXMLDOMDocument3 *document;
2396 IStream *stream;
2398 ret = IUnknown_QueryInterface(pUnk, &IID_IXMLDOMDocument3, (void**)&document);
2399 if(ret == S_OK)
2401 VARIANT_BOOL success;
2402 BSTR xml;
2404 ret = IXMLDOMDocument3_get_xml(iface, &xml);
2405 if(ret == S_OK)
2407 ret = IXMLDOMDocument3_loadXML(document, xml, &success);
2408 SysFreeString(xml);
2411 IXMLDOMDocument3_Release(document);
2412 return ret;
2415 ret = IUnknown_QueryInterface(pUnk, &IID_IStream, (void**)&stream);
2416 if(ret == S_OK)
2418 int options = get_doc(This)->standalone == -1 ? XML_SAVE_NO_DECL : 0;
2419 ctx = xmlSaveToIO(domdoc_stream_save_writecallback,
2420 domdoc_stream_save_closecallback, stream, NULL, options);
2422 if(!ctx)
2424 IStream_Release(stream);
2425 return E_FAIL;
2429 break;
2431 case VT_BSTR:
2432 case VT_BSTR | VT_BYREF:
2434 int options = get_doc(This)->standalone == -1 ? XML_SAVE_NO_DECL : 0;
2436 /* save with file path */
2437 HANDLE handle = CreateFileW( (V_VT(&destination) & VT_BYREF)? *V_BSTRREF(&destination) : V_BSTR(&destination),
2438 GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL );
2439 if( handle == INVALID_HANDLE_VALUE )
2441 WARN("failed to create file\n");
2442 return E_FAIL;
2445 /* disable top XML declaration */
2446 ctx = xmlSaveToIO(domdoc_save_writecallback, domdoc_save_closecallback,
2447 handle, NULL, options);
2448 if (!ctx)
2450 CloseHandle(handle);
2451 return E_FAIL;
2454 break;
2456 default:
2457 FIXME("Unhandled VARIANT: %s\n", debugstr_variant(&destination));
2458 return S_FALSE;
2461 xmldecl = xmldoc_unlink_xmldecl(get_doc(This));
2462 if (xmlSaveDoc(ctx, get_doc(This)) == -1) ret = S_FALSE;
2463 xmldoc_link_xmldecl(get_doc(This), xmldecl);
2465 /* will release resources through close callback */
2466 xmlSaveClose(ctx);
2468 return ret;
2471 static HRESULT WINAPI domdoc_get_validateOnParse(
2472 IXMLDOMDocument3 *iface,
2473 VARIANT_BOOL* isValidating )
2475 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2476 TRACE("(%p)->(%p: %d)\n", This, isValidating, This->validating);
2477 *isValidating = This->validating;
2478 return S_OK;
2482 static HRESULT WINAPI domdoc_put_validateOnParse(
2483 IXMLDOMDocument3 *iface,
2484 VARIANT_BOOL isValidating )
2486 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2487 TRACE("(%p)->(%d)\n", This, isValidating);
2488 This->validating = isValidating;
2489 return S_OK;
2493 static HRESULT WINAPI domdoc_get_resolveExternals(
2494 IXMLDOMDocument3 *iface,
2495 VARIANT_BOOL* isResolving )
2497 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2498 TRACE("(%p)->(%p: %d)\n", This, isResolving, This->resolving);
2499 *isResolving = This->resolving;
2500 return S_OK;
2504 static HRESULT WINAPI domdoc_put_resolveExternals(
2505 IXMLDOMDocument3 *iface,
2506 VARIANT_BOOL isResolving )
2508 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2509 TRACE("(%p)->(%d)\n", This, isResolving);
2510 This->resolving = isResolving;
2511 return S_OK;
2515 static HRESULT WINAPI domdoc_get_preserveWhiteSpace(
2516 IXMLDOMDocument3 *iface,
2517 VARIANT_BOOL* isPreserving )
2519 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2520 TRACE("(%p)->(%p: %d)\n", This, isPreserving, This->properties->preserving);
2521 *isPreserving = This->properties->preserving;
2522 return S_OK;
2526 static HRESULT WINAPI domdoc_put_preserveWhiteSpace(
2527 IXMLDOMDocument3 *iface,
2528 VARIANT_BOOL isPreserving )
2530 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2531 TRACE("(%p)->(%d)\n", This, isPreserving);
2532 This->properties->preserving = isPreserving;
2533 return S_OK;
2537 static HRESULT WINAPI domdoc_put_onreadystatechange(
2538 IXMLDOMDocument3 *iface,
2539 VARIANT event )
2541 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2543 TRACE("(%p)->(%s)\n", This, debugstr_variant(&event));
2544 return set_doc_event(This, EVENTID_READYSTATECHANGE, &event);
2548 static HRESULT WINAPI domdoc_put_onDataAvailable(IXMLDOMDocument3 *iface, VARIANT sink)
2550 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2551 FIXME("(%p)->(%s): stub\n", This, debugstr_variant(&sink));
2552 return E_NOTIMPL;
2555 static HRESULT WINAPI domdoc_put_onTransformNode(IXMLDOMDocument3 *iface, VARIANT sink )
2557 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2558 FIXME("(%p)->(%s): stub\n", This, debugstr_variant(&sink));
2559 return E_NOTIMPL;
2562 static HRESULT WINAPI domdoc_get_namespaces(
2563 IXMLDOMDocument3* iface,
2564 IXMLDOMSchemaCollection** collection )
2566 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2567 HRESULT hr;
2569 FIXME("(%p)->(%p): semi-stub\n", This, collection);
2571 if (!collection) return E_POINTER;
2573 if (!This->namespaces)
2575 hr = SchemaCache_create(This->properties->version, NULL, (void**)&This->namespaces);
2576 if (hr != S_OK) return hr;
2578 hr = cache_from_doc_ns(This->namespaces, &This->node);
2579 if (hr != S_OK)
2580 release_namespaces(This);
2583 if (This->namespaces)
2584 return IXMLDOMSchemaCollection2_QueryInterface(This->namespaces,
2585 &IID_IXMLDOMSchemaCollection, (void**)collection);
2587 return hr;
2590 static HRESULT WINAPI domdoc_get_schemas(
2591 IXMLDOMDocument3* iface,
2592 VARIANT* schema )
2594 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2595 IXMLDOMSchemaCollection2* cur_schema = This->properties->schemaCache;
2596 HRESULT hr = S_FALSE;
2598 TRACE("(%p)->(%p)\n", This, schema);
2600 V_VT(schema) = VT_NULL;
2601 /* just to reset pointer part, cause that's what application is expected to use */
2602 V_DISPATCH(schema) = NULL;
2604 if(cur_schema)
2606 hr = IXMLDOMSchemaCollection2_QueryInterface(cur_schema, &IID_IDispatch, (void**)&V_DISPATCH(schema));
2607 if(SUCCEEDED(hr))
2608 V_VT(schema) = VT_DISPATCH;
2610 return hr;
2613 static HRESULT WINAPI domdoc_putref_schemas(
2614 IXMLDOMDocument3* iface,
2615 VARIANT schema)
2617 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2618 HRESULT hr = E_FAIL;
2619 IXMLDOMSchemaCollection2* new_schema = NULL;
2621 FIXME("(%p)->(%s): semi-stub\n", This, debugstr_variant(&schema));
2622 switch(V_VT(&schema))
2624 case VT_UNKNOWN:
2625 if (V_UNKNOWN(&schema))
2627 hr = IUnknown_QueryInterface(V_UNKNOWN(&schema), &IID_IXMLDOMSchemaCollection, (void**)&new_schema);
2628 break;
2630 /* fallthrough */
2631 case VT_DISPATCH:
2632 if (V_DISPATCH(&schema))
2634 hr = IDispatch_QueryInterface(V_DISPATCH(&schema), &IID_IXMLDOMSchemaCollection, (void**)&new_schema);
2635 break;
2637 /* fallthrough */
2638 case VT_NULL:
2639 case VT_EMPTY:
2640 hr = S_OK;
2641 break;
2643 default:
2644 WARN("Can't get schema from vt %x\n", V_VT(&schema));
2647 if(SUCCEEDED(hr))
2649 IXMLDOMSchemaCollection2* old_schema = InterlockedExchangePointer((void**)&This->properties->schemaCache, new_schema);
2650 if(old_schema) IXMLDOMSchemaCollection2_Release(old_schema);
2653 return hr;
2656 static inline BOOL is_wellformed(xmlDocPtr doc)
2658 #ifdef HAVE_XMLDOC_PROPERTIES
2659 return doc->properties & XML_DOC_WELLFORMED;
2660 #else
2661 /* Not a full check, but catches the worst violations */
2662 xmlNodePtr child;
2663 int root = 0;
2665 for (child = doc->children; child != NULL; child = child->next)
2667 switch (child->type)
2669 case XML_ELEMENT_NODE:
2670 if (++root > 1)
2671 return FALSE;
2672 break;
2673 case XML_TEXT_NODE:
2674 case XML_CDATA_SECTION_NODE:
2675 return FALSE;
2676 break;
2677 default:
2678 break;
2682 return root == 1;
2683 #endif
2686 static void LIBXML2_LOG_CALLBACK validate_error(void* ctx, char const* msg, ...)
2688 va_list ap;
2689 va_start(ap, msg);
2690 LIBXML2_CALLBACK_ERR(domdoc_validateNode, msg, ap);
2691 va_end(ap);
2694 static void LIBXML2_LOG_CALLBACK validate_warning(void* ctx, char const* msg, ...)
2696 va_list ap;
2697 va_start(ap, msg);
2698 LIBXML2_CALLBACK_WARN(domdoc_validateNode, msg, ap);
2699 va_end(ap);
2702 static HRESULT WINAPI domdoc_validateNode(
2703 IXMLDOMDocument3* iface,
2704 IXMLDOMNode* node,
2705 IXMLDOMParseError** err)
2707 domdoc* This = impl_from_IXMLDOMDocument3(iface);
2708 LONG state, err_code = 0;
2709 HRESULT hr = S_OK;
2710 int validated = 0;
2712 TRACE("(%p)->(%p, %p)\n", This, node, err);
2713 IXMLDOMDocument3_get_readyState(iface, &state);
2714 if (state != READYSTATE_COMPLETE)
2716 if (err)
2717 *err = create_parseError(err_code, NULL, NULL, NULL, 0, 0, 0);
2718 return E_PENDING;
2721 if (!node)
2723 if (err)
2724 *err = create_parseError(err_code, NULL, NULL, NULL, 0, 0, 0);
2725 return E_POINTER;
2728 if (!get_node_obj(node)->node || get_node_obj(node)->node->doc != get_doc(This))
2730 if (err)
2731 *err = create_parseError(err_code, NULL, NULL, NULL, 0, 0, 0);
2732 return E_FAIL;
2735 if (!is_wellformed(get_doc(This)))
2737 ERR("doc not well-formed\n");
2738 if (err)
2739 *err = create_parseError(E_XML_NOTWF, NULL, NULL, NULL, 0, 0, 0);
2740 return S_FALSE;
2743 /* DTD validation */
2744 if (get_doc(This)->intSubset || get_doc(This)->extSubset)
2746 xmlValidCtxtPtr vctx = xmlNewValidCtxt();
2747 vctx->error = validate_error;
2748 vctx->warning = validate_warning;
2749 ++validated;
2751 if (!((node == (IXMLDOMNode*)iface)?
2752 xmlValidateDocument(vctx, get_doc(This)) :
2753 xmlValidateElement(vctx, get_doc(This), get_node_obj(node)->node)))
2755 /* TODO: get a real error code here */
2756 TRACE("DTD validation failed\n");
2757 err_code = E_XML_INVALID;
2758 hr = S_FALSE;
2760 xmlFreeValidCtxt(vctx);
2763 /* Schema validation */
2764 if (hr == S_OK && This->properties->schemaCache != NULL)
2767 hr = SchemaCache_validate_tree(This->properties->schemaCache, get_node_obj(node)->node);
2768 if (SUCCEEDED(hr))
2770 ++validated;
2771 /* TODO: get a real error code here */
2772 if (hr == S_OK)
2774 TRACE("schema validation succeeded\n");
2776 else
2778 ERR("schema validation failed\n");
2779 err_code = E_XML_INVALID;
2782 else
2784 /* not really OK, just didn't find a schema for the ns */
2785 hr = S_OK;
2789 if (!validated)
2791 ERR("no DTD or schema found\n");
2792 err_code = E_XML_NODTD;
2793 hr = S_FALSE;
2796 if (err)
2797 *err = create_parseError(err_code, NULL, NULL, NULL, 0, 0, 0);
2799 return hr;
2802 static HRESULT WINAPI domdoc_validate(
2803 IXMLDOMDocument3* iface,
2804 IXMLDOMParseError** err)
2806 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2807 TRACE("(%p)->(%p)\n", This, err);
2808 return IXMLDOMDocument3_validateNode(iface, (IXMLDOMNode*)iface, err);
2811 static HRESULT WINAPI domdoc_setProperty(
2812 IXMLDOMDocument3* iface,
2813 BSTR p,
2814 VARIANT value)
2816 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2818 TRACE("(%p)->(%s %s)\n", This, debugstr_w(p), debugstr_variant(&value));
2820 if (lstrcmpiW(p, PropertySelectionLanguageW) == 0)
2822 VARIANT varStr;
2823 HRESULT hr;
2824 BSTR bstr;
2826 V_VT(&varStr) = VT_EMPTY;
2827 if (V_VT(&value) != VT_BSTR)
2829 if (FAILED(hr = VariantChangeType(&varStr, &value, 0, VT_BSTR)))
2830 return hr;
2831 bstr = V_BSTR(&varStr);
2833 else
2834 bstr = V_BSTR(&value);
2836 hr = S_OK;
2837 if (lstrcmpiW(bstr, PropValueXPathW) == 0)
2838 This->properties->XPath = TRUE;
2839 else if (lstrcmpiW(bstr, PropValueXSLPatternW) == 0)
2840 This->properties->XPath = FALSE;
2841 else
2842 hr = E_FAIL;
2844 VariantClear(&varStr);
2845 return hr;
2847 else if (lstrcmpiW(p, PropertySelectionNamespacesW) == 0)
2849 xmlChar *nsStr = (xmlChar*)This->properties->selectNsStr;
2850 struct list *pNsList;
2851 VARIANT varStr;
2852 HRESULT hr;
2853 BSTR bstr;
2855 V_VT(&varStr) = VT_EMPTY;
2856 if (V_VT(&value) != VT_BSTR)
2858 if (FAILED(hr = VariantChangeType(&varStr, &value, 0, VT_BSTR)))
2859 return hr;
2860 bstr = V_BSTR(&varStr);
2862 else
2863 bstr = V_BSTR(&value);
2865 hr = S_OK;
2867 pNsList = &(This->properties->selectNsList);
2868 clear_selectNsList(pNsList);
2869 heap_free(nsStr);
2870 nsStr = xmlchar_from_wchar(bstr);
2872 TRACE("property value: \"%s\"\n", debugstr_w(bstr));
2874 This->properties->selectNsStr = nsStr;
2875 This->properties->selectNsStr_len = xmlStrlen(nsStr);
2876 if (bstr && *bstr)
2878 xmlChar *pTokBegin, *pTokEnd, *pTokInner;
2879 select_ns_entry* ns_entry = NULL;
2880 xmlXPathContextPtr ctx;
2882 ctx = xmlXPathNewContext(This->node.node->doc);
2883 pTokBegin = nsStr;
2885 /* skip leading spaces */
2886 while (*pTokBegin == ' ' || *pTokBegin == '\n' ||
2887 *pTokBegin == '\t' || *pTokBegin == '\r')
2888 ++pTokBegin;
2890 for (; *pTokBegin; pTokBegin = pTokEnd)
2892 if (ns_entry)
2893 memset(ns_entry, 0, sizeof(select_ns_entry));
2894 else
2895 ns_entry = heap_alloc_zero(sizeof(select_ns_entry));
2897 while (*pTokBegin == ' ')
2898 ++pTokBegin;
2899 pTokEnd = pTokBegin;
2900 while (*pTokEnd != ' ' && *pTokEnd != 0)
2901 ++pTokEnd;
2903 /* so it failed to advance which means we've got some trailing spaces */
2904 if (pTokEnd == pTokBegin) break;
2906 if (xmlStrncmp(pTokBegin, (xmlChar const*)"xmlns", 5) != 0)
2908 hr = E_FAIL;
2909 WARN("Syntax error in xmlns string: %s\n\tat token: %s\n",
2910 debugstr_w(bstr), debugstr_an((const char*)pTokBegin, pTokEnd-pTokBegin));
2911 continue;
2914 pTokBegin += 5;
2915 if (*pTokBegin == '=')
2917 /*valid for XSLPattern?*/
2918 FIXME("Setting default xmlns not supported - skipping.\n");
2919 continue;
2921 else if (*pTokBegin == ':')
2923 ns_entry->prefix = ++pTokBegin;
2924 for (pTokInner = pTokBegin; pTokInner != pTokEnd && *pTokInner != '='; ++pTokInner)
2927 if (pTokInner == pTokEnd)
2929 hr = E_FAIL;
2930 WARN("Syntax error in xmlns string: %s\n\tat token: %s\n",
2931 debugstr_w(bstr), debugstr_an((const char*)pTokBegin, pTokEnd-pTokBegin));
2932 continue;
2935 ns_entry->prefix_end = *pTokInner;
2936 *pTokInner = 0;
2937 ++pTokInner;
2939 if (pTokEnd-pTokInner > 1 &&
2940 ((*pTokInner == '\'' && *(pTokEnd-1) == '\'') ||
2941 (*pTokInner == '"' && *(pTokEnd-1) == '"')))
2943 ns_entry->href = ++pTokInner;
2944 ns_entry->href_end = *(pTokEnd-1);
2945 *(pTokEnd-1) = 0;
2946 list_add_tail(pNsList, &ns_entry->entry);
2947 /*let libxml figure out if they're valid from here ;)*/
2948 if (xmlXPathRegisterNs(ctx, ns_entry->prefix, ns_entry->href) != 0)
2950 hr = E_FAIL;
2952 ns_entry = NULL;
2953 continue;
2955 else
2957 WARN("Syntax error in xmlns string: %s\n\tat token: %s\n",
2958 debugstr_w(bstr), debugstr_an((const char*)pTokInner, pTokEnd-pTokInner));
2959 list_add_tail(pNsList, &ns_entry->entry);
2961 ns_entry = NULL;
2962 hr = E_FAIL;
2963 continue;
2966 else
2968 hr = E_FAIL;
2969 continue;
2972 heap_free(ns_entry);
2973 xmlXPathFreeContext(ctx);
2976 VariantClear(&varStr);
2977 return hr;
2979 else if (lstrcmpiW(p, PropertyProhibitDTDW) == 0 ||
2980 lstrcmpiW(p, PropertyNewParserW) == 0 ||
2981 lstrcmpiW(p, PropertyResolveExternalsW) == 0)
2983 /* Ignore */
2984 FIXME("Ignoring property %s, value %d\n", debugstr_w(p), V_BOOL(&value));
2985 return S_OK;
2988 FIXME("Unknown property %s\n", debugstr_w(p));
2989 return E_FAIL;
2992 static HRESULT WINAPI domdoc_getProperty(
2993 IXMLDOMDocument3* iface,
2994 BSTR p,
2995 VARIANT* var)
2997 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2999 TRACE("(%p)->(%s)\n", This, debugstr_w(p));
3001 if (!var)
3002 return E_INVALIDARG;
3004 if (lstrcmpiW(p, PropertySelectionLanguageW) == 0)
3006 V_VT(var) = VT_BSTR;
3007 V_BSTR(var) = This->properties->XPath ?
3008 SysAllocString(PropValueXPathW) :
3009 SysAllocString(PropValueXSLPatternW);
3010 return V_BSTR(var) ? S_OK : E_OUTOFMEMORY;
3012 else if (lstrcmpiW(p, PropertySelectionNamespacesW) == 0)
3014 int lenA, lenW;
3015 BSTR rebuiltStr, cur;
3016 const xmlChar *nsStr;
3017 struct list *pNsList;
3018 select_ns_entry* pNsEntry;
3020 V_VT(var) = VT_BSTR;
3021 nsStr = This->properties->selectNsStr;
3022 pNsList = &This->properties->selectNsList;
3023 lenA = This->properties->selectNsStr_len;
3024 lenW = MultiByteToWideChar(CP_UTF8, 0, (LPCSTR)nsStr, lenA+1, NULL, 0);
3025 rebuiltStr = heap_alloc(lenW*sizeof(WCHAR));
3026 MultiByteToWideChar(CP_UTF8, 0, (LPCSTR)nsStr, lenA+1, rebuiltStr, lenW);
3027 cur = rebuiltStr;
3028 /* this is fine because all of the chars that end tokens are ASCII*/
3029 LIST_FOR_EACH_ENTRY(pNsEntry, pNsList, select_ns_entry, entry)
3031 while (*cur != 0) ++cur;
3032 if (pNsEntry->prefix_end)
3034 *cur = pNsEntry->prefix_end;
3035 while (*cur != 0) ++cur;
3038 if (pNsEntry->href_end)
3040 *cur = pNsEntry->href_end;
3043 V_BSTR(var) = SysAllocString(rebuiltStr);
3044 heap_free(rebuiltStr);
3045 return S_OK;
3048 FIXME("Unknown property %s\n", debugstr_w(p));
3049 return E_FAIL;
3052 static HRESULT WINAPI domdoc_importNode(
3053 IXMLDOMDocument3* iface,
3054 IXMLDOMNode* node,
3055 VARIANT_BOOL deep,
3056 IXMLDOMNode** clone)
3058 domdoc *This = impl_from_IXMLDOMDocument3( iface );
3059 FIXME("(%p)->(%p %d %p): stub\n", This, node, deep, clone);
3060 return E_NOTIMPL;
3063 static const struct IXMLDOMDocument3Vtbl XMLDOMDocument3Vtbl =
3065 domdoc_QueryInterface,
3066 domdoc_AddRef,
3067 domdoc_Release,
3068 domdoc_GetTypeInfoCount,
3069 domdoc_GetTypeInfo,
3070 domdoc_GetIDsOfNames,
3071 domdoc_Invoke,
3072 domdoc_get_nodeName,
3073 domdoc_get_nodeValue,
3074 domdoc_put_nodeValue,
3075 domdoc_get_nodeType,
3076 domdoc_get_parentNode,
3077 domdoc_get_childNodes,
3078 domdoc_get_firstChild,
3079 domdoc_get_lastChild,
3080 domdoc_get_previousSibling,
3081 domdoc_get_nextSibling,
3082 domdoc_get_attributes,
3083 domdoc_insertBefore,
3084 domdoc_replaceChild,
3085 domdoc_removeChild,
3086 domdoc_appendChild,
3087 domdoc_hasChildNodes,
3088 domdoc_get_ownerDocument,
3089 domdoc_cloneNode,
3090 domdoc_get_nodeTypeString,
3091 domdoc_get_text,
3092 domdoc_put_text,
3093 domdoc_get_specified,
3094 domdoc_get_definition,
3095 domdoc_get_nodeTypedValue,
3096 domdoc_put_nodeTypedValue,
3097 domdoc_get_dataType,
3098 domdoc_put_dataType,
3099 domdoc_get_xml,
3100 domdoc_transformNode,
3101 domdoc_selectNodes,
3102 domdoc_selectSingleNode,
3103 domdoc_get_parsed,
3104 domdoc_get_namespaceURI,
3105 domdoc_get_prefix,
3106 domdoc_get_baseName,
3107 domdoc_transformNodeToObject,
3108 domdoc_get_doctype,
3109 domdoc_get_implementation,
3110 domdoc_get_documentElement,
3111 domdoc_put_documentElement,
3112 domdoc_createElement,
3113 domdoc_createDocumentFragment,
3114 domdoc_createTextNode,
3115 domdoc_createComment,
3116 domdoc_createCDATASection,
3117 domdoc_createProcessingInstruction,
3118 domdoc_createAttribute,
3119 domdoc_createEntityReference,
3120 domdoc_getElementsByTagName,
3121 domdoc_createNode,
3122 domdoc_nodeFromID,
3123 domdoc_load,
3124 domdoc_get_readyState,
3125 domdoc_get_parseError,
3126 domdoc_get_url,
3127 domdoc_get_async,
3128 domdoc_put_async,
3129 domdoc_abort,
3130 domdoc_loadXML,
3131 domdoc_save,
3132 domdoc_get_validateOnParse,
3133 domdoc_put_validateOnParse,
3134 domdoc_get_resolveExternals,
3135 domdoc_put_resolveExternals,
3136 domdoc_get_preserveWhiteSpace,
3137 domdoc_put_preserveWhiteSpace,
3138 domdoc_put_onreadystatechange,
3139 domdoc_put_onDataAvailable,
3140 domdoc_put_onTransformNode,
3141 domdoc_get_namespaces,
3142 domdoc_get_schemas,
3143 domdoc_putref_schemas,
3144 domdoc_validate,
3145 domdoc_setProperty,
3146 domdoc_getProperty,
3147 domdoc_validateNode,
3148 domdoc_importNode
3151 /* IConnectionPointContainer */
3152 static HRESULT WINAPI ConnectionPointContainer_QueryInterface(IConnectionPointContainer *iface,
3153 REFIID riid, void **ppv)
3155 domdoc *This = impl_from_IConnectionPointContainer(iface);
3156 return IXMLDOMDocument3_QueryInterface(&This->IXMLDOMDocument3_iface, riid, ppv);
3159 static ULONG WINAPI ConnectionPointContainer_AddRef(IConnectionPointContainer *iface)
3161 domdoc *This = impl_from_IConnectionPointContainer(iface);
3162 return IXMLDOMDocument3_AddRef(&This->IXMLDOMDocument3_iface);
3165 static ULONG WINAPI ConnectionPointContainer_Release(IConnectionPointContainer *iface)
3167 domdoc *This = impl_from_IConnectionPointContainer(iface);
3168 return IXMLDOMDocument3_Release(&This->IXMLDOMDocument3_iface);
3171 static HRESULT WINAPI ConnectionPointContainer_EnumConnectionPoints(IConnectionPointContainer *iface,
3172 IEnumConnectionPoints **ppEnum)
3174 domdoc *This = impl_from_IConnectionPointContainer(iface);
3175 FIXME("(%p)->(%p): stub\n", This, ppEnum);
3176 return E_NOTIMPL;
3179 static HRESULT WINAPI ConnectionPointContainer_FindConnectionPoint(IConnectionPointContainer *iface,
3180 REFIID riid, IConnectionPoint **cp)
3182 domdoc *This = impl_from_IConnectionPointContainer(iface);
3183 ConnectionPoint *iter;
3185 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), cp);
3187 *cp = NULL;
3189 for(iter = This->cp_list; iter; iter = iter->next)
3191 if (IsEqualGUID(iter->iid, riid))
3192 *cp = &iter->IConnectionPoint_iface;
3195 if (*cp)
3197 IConnectionPoint_AddRef(*cp);
3198 return S_OK;
3201 FIXME("unsupported riid %s\n", debugstr_guid(riid));
3202 return CONNECT_E_NOCONNECTION;
3206 static const struct IConnectionPointContainerVtbl ConnectionPointContainerVtbl =
3208 ConnectionPointContainer_QueryInterface,
3209 ConnectionPointContainer_AddRef,
3210 ConnectionPointContainer_Release,
3211 ConnectionPointContainer_EnumConnectionPoints,
3212 ConnectionPointContainer_FindConnectionPoint
3215 /* IConnectionPoint */
3216 static HRESULT WINAPI ConnectionPoint_QueryInterface(IConnectionPoint *iface,
3217 REFIID riid, void **ppv)
3219 ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3221 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv );
3223 *ppv = NULL;
3225 if (IsEqualGUID(&IID_IUnknown, riid) ||
3226 IsEqualGUID(&IID_IConnectionPoint, riid))
3228 *ppv = iface;
3231 if (*ppv)
3233 IConnectionPoint_AddRef(iface);
3234 return S_OK;
3237 WARN("Unsupported interface %s\n", debugstr_guid(riid));
3238 return E_NOINTERFACE;
3241 static ULONG WINAPI ConnectionPoint_AddRef(IConnectionPoint *iface)
3243 ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3244 return IConnectionPointContainer_AddRef(This->container);
3247 static ULONG WINAPI ConnectionPoint_Release(IConnectionPoint *iface)
3249 ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3250 return IConnectionPointContainer_Release(This->container);
3253 static HRESULT WINAPI ConnectionPoint_GetConnectionInterface(IConnectionPoint *iface, IID *iid)
3255 ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3257 TRACE("(%p)->(%p)\n", This, iid);
3259 if (!iid) return E_POINTER;
3261 *iid = *This->iid;
3262 return S_OK;
3265 static HRESULT WINAPI ConnectionPoint_GetConnectionPointContainer(IConnectionPoint *iface,
3266 IConnectionPointContainer **container)
3268 ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3270 TRACE("(%p)->(%p)\n", This, container);
3272 if (!container) return E_POINTER;
3274 *container = This->container;
3275 IConnectionPointContainer_AddRef(*container);
3276 return S_OK;
3279 static HRESULT WINAPI ConnectionPoint_Advise(IConnectionPoint *iface, IUnknown *unk_sink,
3280 DWORD *cookie)
3282 ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3283 IUnknown *sink;
3284 HRESULT hr;
3285 DWORD i;
3287 TRACE("(%p)->(%p %p)\n", This, unk_sink, cookie);
3289 hr = IUnknown_QueryInterface(unk_sink, This->iid, (void**)&sink);
3290 if(FAILED(hr) && !IsEqualGUID(&IID_IPropertyNotifySink, This->iid))
3291 hr = IUnknown_QueryInterface(unk_sink, &IID_IDispatch, (void**)&sink);
3292 if(FAILED(hr))
3293 return CONNECT_E_CANNOTCONNECT;
3295 if(This->sinks)
3297 for (i = 0; i < This->sinks_size; i++)
3298 if (!This->sinks[i].unk)
3299 break;
3301 if (i == This->sinks_size)
3302 This->sinks = heap_realloc(This->sinks,(++This->sinks_size)*sizeof(*This->sinks));
3304 else
3306 This->sinks = heap_alloc(sizeof(*This->sinks));
3307 This->sinks_size = 1;
3308 i = 0;
3311 This->sinks[i].unk = sink;
3312 if (cookie)
3313 *cookie = i+1;
3315 return S_OK;
3318 static HRESULT WINAPI ConnectionPoint_Unadvise(IConnectionPoint *iface, DWORD cookie)
3320 ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3322 TRACE("(%p)->(%d)\n", This, cookie);
3324 if (cookie == 0 || cookie > This->sinks_size || !This->sinks[cookie-1].unk)
3325 return CONNECT_E_NOCONNECTION;
3327 IUnknown_Release(This->sinks[cookie-1].unk);
3328 This->sinks[cookie-1].unk = NULL;
3330 return S_OK;
3333 static HRESULT WINAPI ConnectionPoint_EnumConnections(IConnectionPoint *iface,
3334 IEnumConnections **ppEnum)
3336 ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3337 FIXME("(%p)->(%p): stub\n", This, ppEnum);
3338 return E_NOTIMPL;
3341 static const IConnectionPointVtbl ConnectionPointVtbl =
3343 ConnectionPoint_QueryInterface,
3344 ConnectionPoint_AddRef,
3345 ConnectionPoint_Release,
3346 ConnectionPoint_GetConnectionInterface,
3347 ConnectionPoint_GetConnectionPointContainer,
3348 ConnectionPoint_Advise,
3349 ConnectionPoint_Unadvise,
3350 ConnectionPoint_EnumConnections
3353 static void ConnectionPoint_Init(ConnectionPoint *cp, struct domdoc *doc, REFIID riid)
3355 cp->IConnectionPoint_iface.lpVtbl = &ConnectionPointVtbl;
3356 cp->doc = doc;
3357 cp->iid = riid;
3358 cp->sinks = NULL;
3359 cp->sinks_size = 0;
3361 cp->next = doc->cp_list;
3362 doc->cp_list = cp;
3364 cp->container = &doc->IConnectionPointContainer_iface;
3367 /* domdoc implementation of IObjectWithSite */
3368 static HRESULT WINAPI
3369 domdoc_ObjectWithSite_QueryInterface( IObjectWithSite* iface, REFIID riid, void** ppvObject )
3371 domdoc *This = impl_from_IObjectWithSite(iface);
3372 return IXMLDOMDocument3_QueryInterface(&This->IXMLDOMDocument3_iface, riid, ppvObject);
3375 static ULONG WINAPI domdoc_ObjectWithSite_AddRef( IObjectWithSite* iface )
3377 domdoc *This = impl_from_IObjectWithSite(iface);
3378 return IXMLDOMDocument3_AddRef(&This->IXMLDOMDocument3_iface);
3381 static ULONG WINAPI domdoc_ObjectWithSite_Release( IObjectWithSite* iface )
3383 domdoc *This = impl_from_IObjectWithSite(iface);
3384 return IXMLDOMDocument3_Release(&This->IXMLDOMDocument3_iface);
3387 static HRESULT WINAPI domdoc_ObjectWithSite_GetSite( IObjectWithSite *iface, REFIID iid, void **ppvSite )
3389 domdoc *This = impl_from_IObjectWithSite(iface);
3391 TRACE("(%p)->(%s %p)\n", This, debugstr_guid( iid ), ppvSite );
3393 if ( !This->site )
3394 return E_FAIL;
3396 return IUnknown_QueryInterface( This->site, iid, ppvSite );
3399 static HRESULT WINAPI domdoc_ObjectWithSite_SetSite( IObjectWithSite *iface, IUnknown *punk )
3401 domdoc *This = impl_from_IObjectWithSite(iface);
3403 TRACE("(%p)->(%p)\n", iface, punk);
3405 if(!punk)
3407 if(This->site)
3409 IUnknown_Release( This->site );
3410 This->site = NULL;
3413 return S_OK;
3416 IUnknown_AddRef( punk );
3418 if(This->site)
3419 IUnknown_Release( This->site );
3421 This->site = punk;
3423 return S_OK;
3426 static const IObjectWithSiteVtbl domdocObjectSite =
3428 domdoc_ObjectWithSite_QueryInterface,
3429 domdoc_ObjectWithSite_AddRef,
3430 domdoc_ObjectWithSite_Release,
3431 domdoc_ObjectWithSite_SetSite,
3432 domdoc_ObjectWithSite_GetSite
3435 static HRESULT WINAPI domdoc_Safety_QueryInterface(IObjectSafety *iface, REFIID riid, void **ppv)
3437 domdoc *This = impl_from_IObjectSafety(iface);
3438 return IXMLDOMDocument3_QueryInterface(&This->IXMLDOMDocument3_iface, riid, ppv);
3441 static ULONG WINAPI domdoc_Safety_AddRef(IObjectSafety *iface)
3443 domdoc *This = impl_from_IObjectSafety(iface);
3444 return IXMLDOMDocument3_AddRef(&This->IXMLDOMDocument3_iface);
3447 static ULONG WINAPI domdoc_Safety_Release(IObjectSafety *iface)
3449 domdoc *This = impl_from_IObjectSafety(iface);
3450 return IXMLDOMDocument3_Release(&This->IXMLDOMDocument3_iface);
3453 #define SAFETY_SUPPORTED_OPTIONS (INTERFACESAFE_FOR_UNTRUSTED_CALLER|INTERFACESAFE_FOR_UNTRUSTED_DATA|INTERFACE_USES_SECURITY_MANAGER)
3455 static HRESULT WINAPI domdoc_Safety_GetInterfaceSafetyOptions(IObjectSafety *iface, REFIID riid,
3456 DWORD *supported, DWORD *enabled)
3458 domdoc *This = impl_from_IObjectSafety(iface);
3460 TRACE("(%p)->(%s %p %p)\n", This, debugstr_guid(riid), supported, enabled);
3462 if(!supported || !enabled) return E_POINTER;
3464 *supported = SAFETY_SUPPORTED_OPTIONS;
3465 *enabled = This->safeopt;
3467 return S_OK;
3470 static HRESULT WINAPI domdoc_Safety_SetInterfaceSafetyOptions(IObjectSafety *iface, REFIID riid,
3471 DWORD mask, DWORD enabled)
3473 domdoc *This = impl_from_IObjectSafety(iface);
3474 TRACE("(%p)->(%s %x %x)\n", This, debugstr_guid(riid), mask, enabled);
3476 if ((mask & ~SAFETY_SUPPORTED_OPTIONS) != 0)
3477 return E_FAIL;
3479 This->safeopt = (This->safeopt & ~mask) | (mask & enabled);
3481 return S_OK;
3484 #undef SAFETY_SUPPORTED_OPTIONS
3486 static const IObjectSafetyVtbl domdocObjectSafetyVtbl = {
3487 domdoc_Safety_QueryInterface,
3488 domdoc_Safety_AddRef,
3489 domdoc_Safety_Release,
3490 domdoc_Safety_GetInterfaceSafetyOptions,
3491 domdoc_Safety_SetInterfaceSafetyOptions
3494 static const tid_t domdoc_iface_tids[] = {
3495 IXMLDOMDocument3_tid,
3499 static dispex_static_data_t domdoc_dispex = {
3500 NULL,
3501 IXMLDOMDocument3_tid,
3502 NULL,
3503 domdoc_iface_tids
3506 HRESULT get_domdoc_from_xmldoc(xmlDocPtr xmldoc, IXMLDOMDocument3 **document)
3508 domdoc *doc;
3510 doc = heap_alloc( sizeof (*doc) );
3511 if( !doc )
3512 return E_OUTOFMEMORY;
3514 doc->IXMLDOMDocument3_iface.lpVtbl = &XMLDOMDocument3Vtbl;
3515 doc->IPersistStreamInit_iface.lpVtbl = &xmldoc_IPersistStreamInit_VTable;
3516 doc->IObjectWithSite_iface.lpVtbl = &domdocObjectSite;
3517 doc->IObjectSafety_iface.lpVtbl = &domdocObjectSafetyVtbl;
3518 doc->IConnectionPointContainer_iface.lpVtbl = &ConnectionPointContainerVtbl;
3519 doc->ref = 1;
3520 doc->async = VARIANT_TRUE;
3521 doc->validating = 0;
3522 doc->resolving = 0;
3523 doc->properties = properties_from_xmlDocPtr(xmldoc);
3524 doc->error = S_OK;
3525 doc->site = NULL;
3526 doc->safeopt = 0;
3527 doc->bsc = NULL;
3528 doc->cp_list = NULL;
3529 doc->namespaces = NULL;
3530 memset(doc->events, 0, sizeof(doc->events));
3532 /* events connection points */
3533 ConnectionPoint_Init(&doc->cp_dispatch, doc, &IID_IDispatch);
3534 ConnectionPoint_Init(&doc->cp_propnotif, doc, &IID_IPropertyNotifySink);
3535 ConnectionPoint_Init(&doc->cp_domdocevents, doc, &DIID_XMLDOMDocumentEvents);
3537 init_xmlnode(&doc->node, (xmlNodePtr)xmldoc, (IXMLDOMNode*)&doc->IXMLDOMDocument3_iface,
3538 &domdoc_dispex);
3540 *document = &doc->IXMLDOMDocument3_iface;
3542 TRACE("returning iface %p\n", *document);
3543 return S_OK;
3546 HRESULT DOMDocument_create(MSXML_VERSION version, IUnknown *pUnkOuter, void **ppObj)
3548 xmlDocPtr xmldoc;
3549 HRESULT hr;
3551 TRACE("(%d, %p, %p)\n", version, pUnkOuter, ppObj);
3553 xmldoc = xmlNewDoc(NULL);
3554 if(!xmldoc)
3555 return E_OUTOFMEMORY;
3557 xmldoc_init(xmldoc, version);
3559 hr = get_domdoc_from_xmldoc(xmldoc, (IXMLDOMDocument3**)ppObj);
3560 if(FAILED(hr))
3562 free_properties(properties_from_xmlDocPtr(xmldoc));
3563 heap_free(xmldoc->_private);
3564 xmlFreeDoc(xmldoc);
3565 return hr;
3568 return hr;
3571 IUnknown* create_domdoc( xmlNodePtr document )
3573 void* pObj = NULL;
3574 HRESULT hr;
3576 TRACE("(%p)\n", document);
3578 hr = get_domdoc_from_xmldoc((xmlDocPtr)document, (IXMLDOMDocument3**)&pObj);
3579 if (FAILED(hr))
3580 return NULL;
3582 return pObj;
3585 #else
3587 HRESULT DOMDocument_create(MSXML_VERSION version, IUnknown *pUnkOuter, void **ppObj)
3589 MESSAGE("This program tried to use a DOMDocument object, but\n"
3590 "libxml2 support was not present at compile time.\n");
3591 return E_NOTIMPL;
3594 #endif