msi/tests: Properly preserve pending file renames.
[wine/multimedia.git] / dlls / msxml3 / domdoc.c
blobd4fcc1cb4d600e3bde7fdf7965bdd46961924e7a
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"
50 #include "dispex.h"
52 #include "wine/debug.h"
53 #include "wine/list.h"
55 #include "msxml_private.h"
57 WINE_DEFAULT_DEBUG_CHANNEL(msxml);
59 #ifdef HAVE_LIBXML2
61 /* not defined in older versions */
62 #define XML_SAVE_FORMAT 1
63 #define XML_SAVE_NO_DECL 2
64 #define XML_SAVE_NO_EMPTY 4
65 #define XML_SAVE_NO_XHTML 8
66 #define XML_SAVE_XHTML 16
67 #define XML_SAVE_AS_XML 32
68 #define XML_SAVE_AS_HTML 64
70 static const WCHAR PropertySelectionLanguageW[] = {'S','e','l','e','c','t','i','o','n','L','a','n','g','u','a','g','e',0};
71 static const WCHAR PropertySelectionNamespacesW[] = {'S','e','l','e','c','t','i','o','n','N','a','m','e','s','p','a','c','e','s',0};
72 static const WCHAR PropertyProhibitDTDW[] = {'P','r','o','h','i','b','i','t','D','T','D',0};
73 static const WCHAR PropertyNewParserW[] = {'N','e','w','P','a','r','s','e','r',0};
74 static const WCHAR PropValueXPathW[] = {'X','P','a','t','h',0};
75 static const WCHAR PropValueXSLPatternW[] = {'X','S','L','P','a','t','t','e','r','n',0};
76 static const WCHAR PropertyResolveExternalsW[] = {'R','e','s','o','l','v','e','E','x','t','e','r','n','a','l','s',0};
78 /* Anything that passes the test_get_ownerDocument()
79 * tests can go here (data shared between all instances).
80 * We need to preserve this when reloading a document,
81 * and also need access to it from the libxml backend. */
82 typedef struct _domdoc_properties {
83 MSXML_VERSION version;
84 VARIANT_BOOL preserving;
85 IXMLDOMSchemaCollection2* schemaCache;
86 struct list selectNsList;
87 xmlChar const* selectNsStr;
88 LONG selectNsStr_len;
89 BOOL XPath;
90 } domdoc_properties;
92 typedef struct ConnectionPoint ConnectionPoint;
93 typedef struct domdoc domdoc;
95 struct ConnectionPoint
97 IConnectionPoint IConnectionPoint_iface;
98 const IID *iid;
100 ConnectionPoint *next;
101 IConnectionPointContainer *container;
102 domdoc *doc;
104 union
106 IUnknown *unk;
107 IDispatch *disp;
108 IPropertyNotifySink *propnotif;
109 } *sinks;
110 DWORD sinks_size;
113 typedef enum {
114 EVENTID_READYSTATECHANGE = 0,
115 EVENTID_DATAAVAILABLE,
116 EVENTID_TRANSFORMNODE,
117 EVENTID_LAST
118 } eventid_t;
120 struct domdoc
122 xmlnode node;
123 IXMLDOMDocument3 IXMLDOMDocument3_iface;
124 IPersistStreamInit IPersistStreamInit_iface;
125 IObjectWithSite IObjectWithSite_iface;
126 IObjectSafety IObjectSafety_iface;
127 ISupportErrorInfo ISupportErrorInfo_iface;
128 IConnectionPointContainer IConnectionPointContainer_iface;
129 LONG ref;
130 VARIANT_BOOL async;
131 VARIANT_BOOL validating;
132 VARIANT_BOOL resolving;
133 domdoc_properties* properties;
134 bsc_t *bsc;
135 HRESULT error;
137 /* IPersistStream */
138 IStream *stream;
140 /* IObjectWithSite*/
141 IUnknown *site;
143 /* IObjectSafety */
144 DWORD safeopt;
146 /* connection list */
147 ConnectionPoint *cp_list;
148 ConnectionPoint cp_domdocevents;
149 ConnectionPoint cp_propnotif;
150 ConnectionPoint cp_dispatch;
152 /* events */
153 IDispatch *events[EVENTID_LAST];
156 static HRESULT set_doc_event(domdoc *doc, eventid_t eid, const VARIANT *v)
158 IDispatch *disp;
160 switch (V_VT(v))
162 case VT_UNKNOWN:
163 if (V_UNKNOWN(v))
164 IUnknown_QueryInterface(V_UNKNOWN(v), &IID_IDispatch, (void**)&disp);
165 else
166 disp = NULL;
167 break;
168 case VT_DISPATCH:
169 disp = V_DISPATCH(v);
170 if (disp) IDispatch_AddRef(disp);
171 break;
172 default:
173 return DISP_E_TYPEMISMATCH;
176 if (doc->events[eid]) IDispatch_Release(doc->events[eid]);
177 doc->events[eid] = disp;
179 return S_OK;
182 static inline ConnectionPoint *impl_from_IConnectionPoint(IConnectionPoint *iface)
184 return CONTAINING_RECORD(iface, ConnectionPoint, IConnectionPoint_iface);
188 In native windows, the whole lifetime management of XMLDOMNodes is
189 managed automatically using reference counts. Wine emulates that by
190 maintaining a reference count to the document that is increased for
191 each IXMLDOMNode pointer passed out for this document. If all these
192 pointers are gone, the document is unreachable and gets freed, that
193 is, all nodes in the tree of the document get freed.
195 You are able to create nodes that are associated to a document (in
196 fact, in msxml's XMLDOM model, all nodes are associated to a document),
197 but not in the tree of that document, for example using the createFoo
198 functions from IXMLDOMDocument. These nodes do not get cleaned up
199 by libxml, so we have to do it ourselves.
201 To catch these nodes, a list of "orphan nodes" is introduced.
202 It contains pointers to all roots of node trees that are
203 associated with the document without being part of the document
204 tree. All nodes with parent==NULL (except for the document root nodes)
205 should be in the orphan node list of their document. All orphan nodes
206 get freed together with the document itself.
209 typedef struct _xmldoc_priv {
210 LONG refs;
211 struct list orphans;
212 domdoc_properties* properties;
213 } xmldoc_priv;
215 typedef struct _orphan_entry {
216 struct list entry;
217 xmlNode * node;
218 } orphan_entry;
220 typedef struct _select_ns_entry {
221 struct list entry;
222 xmlChar const* prefix;
223 xmlChar prefix_end;
224 xmlChar const* href;
225 xmlChar href_end;
226 } select_ns_entry;
228 static inline xmldoc_priv * priv_from_xmlDocPtr(const xmlDocPtr doc)
230 return doc->_private;
233 static inline domdoc_properties * properties_from_xmlDocPtr(xmlDocPtr doc)
235 return priv_from_xmlDocPtr(doc)->properties;
238 BOOL is_xpathmode(const xmlDocPtr doc)
240 return properties_from_xmlDocPtr(doc)->XPath;
243 void set_xpathmode(xmlDocPtr doc, BOOL xpath)
245 properties_from_xmlDocPtr(doc)->XPath = xpath;
248 int registerNamespaces(xmlXPathContextPtr ctxt)
250 int n = 0;
251 const select_ns_entry* ns = NULL;
252 const struct list* pNsList = &properties_from_xmlDocPtr(ctxt->doc)->selectNsList;
254 TRACE("(%p)\n", ctxt);
256 LIST_FOR_EACH_ENTRY( ns, pNsList, select_ns_entry, entry )
258 xmlXPathRegisterNs(ctxt, ns->prefix, ns->href);
259 ++n;
262 return n;
265 static inline void clear_selectNsList(struct list* pNsList)
267 select_ns_entry *ns, *ns2;
268 LIST_FOR_EACH_ENTRY_SAFE( ns, ns2, pNsList, select_ns_entry, entry )
270 heap_free( ns );
272 list_init(pNsList);
275 static xmldoc_priv * create_priv(void)
277 xmldoc_priv *priv;
278 priv = heap_alloc( sizeof (*priv) );
280 if (priv)
282 priv->refs = 0;
283 list_init( &priv->orphans );
284 priv->properties = NULL;
287 return priv;
290 static domdoc_properties * create_properties(MSXML_VERSION version)
292 domdoc_properties *properties = heap_alloc(sizeof(domdoc_properties));
294 list_init(&properties->selectNsList);
295 properties->preserving = VARIANT_FALSE;
296 properties->schemaCache = NULL;
297 properties->selectNsStr = heap_alloc_zero(sizeof(xmlChar));
298 properties->selectNsStr_len = 0;
300 /* properties that are dependent on object versions */
301 properties->version = version;
302 properties->XPath = (version == MSXML4 || version == MSXML6);
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->version = properties->version;
318 pcopy->preserving = properties->preserving;
319 pcopy->schemaCache = properties->schemaCache;
320 if (pcopy->schemaCache)
321 IXMLDOMSchemaCollection2_AddRef(pcopy->schemaCache);
322 pcopy->XPath = properties->XPath;
323 pcopy->selectNsStr_len = properties->selectNsStr_len;
324 list_init( &pcopy->selectNsList );
325 pcopy->selectNsStr = heap_alloc(len);
326 memcpy((xmlChar*)pcopy->selectNsStr, properties->selectNsStr, len);
327 offset = pcopy->selectNsStr - properties->selectNsStr;
329 LIST_FOR_EACH_ENTRY( ns, (&properties->selectNsList), select_ns_entry, entry )
331 new_ns = heap_alloc(sizeof(select_ns_entry));
332 memcpy(new_ns, ns, sizeof(select_ns_entry));
333 new_ns->href += offset;
334 new_ns->prefix += offset;
335 list_add_tail(&pcopy->selectNsList, &new_ns->entry);
340 return pcopy;
343 static void free_properties(domdoc_properties* properties)
345 if (properties)
347 if (properties->schemaCache)
348 IXMLDOMSchemaCollection2_Release(properties->schemaCache);
349 clear_selectNsList(&properties->selectNsList);
350 heap_free((xmlChar*)properties->selectNsStr);
351 heap_free(properties);
355 /* links a "<?xml" node as a first child */
356 void xmldoc_link_xmldecl(xmlDocPtr doc, xmlNodePtr node)
358 assert(doc != NULL);
359 if (doc->standalone != -1) xmlAddPrevSibling( doc->children, node );
362 /* unlinks a first "<?xml" child if it was created */
363 xmlNodePtr xmldoc_unlink_xmldecl(xmlDocPtr doc)
365 xmlNodePtr node;
367 assert(doc != NULL);
369 if (doc->standalone != -1)
371 node = doc->children;
372 xmlUnlinkNode( node );
374 else
375 node = NULL;
377 return node;
380 BOOL is_preserving_whitespace(xmlNodePtr node)
382 domdoc_properties* properties = NULL;
383 /* during parsing the xmlDoc._private stuff is not there */
384 if (priv_from_xmlDocPtr(node->doc))
385 properties = properties_from_xmlDocPtr(node->doc);
386 return ((properties && properties->preserving == VARIANT_TRUE) ||
387 xmlNodeGetSpacePreserve(node) == 1);
390 static inline BOOL strn_isspace(xmlChar const* str, int len)
392 for (; str && len > 0 && *str; ++str, --len)
393 if (!isspace(*str))
394 break;
396 return len == 0;
399 static void sax_characters(void *ctx, const xmlChar *ch, int len)
401 xmlParserCtxtPtr ctxt;
402 const domdoc *This;
404 ctxt = (xmlParserCtxtPtr) ctx;
405 This = (const domdoc*) ctxt->_private;
407 if (ctxt->node)
409 /* during domdoc_loadXML() the xmlDocPtr->_private data is not available */
410 if (!This->properties->preserving &&
411 !is_preserving_whitespace(ctxt->node) &&
412 strn_isspace(ch, len))
413 return;
416 xmlSAX2Characters(ctxt, ch, len);
419 static void LIBXML2_LOG_CALLBACK sax_error(void* ctx, char const* msg, ...)
421 va_list ap;
422 va_start(ap, msg);
423 LIBXML2_CALLBACK_ERR(doparse, msg, ap);
424 va_end(ap);
427 static void LIBXML2_LOG_CALLBACK sax_warning(void* ctx, char const* msg, ...)
429 va_list ap;
430 va_start(ap, msg);
431 LIBXML2_CALLBACK_WARN(doparse, msg, ap);
432 va_end(ap);
435 static void sax_serror(void* ctx, xmlErrorPtr err)
437 LIBXML2_CALLBACK_SERROR(doparse, err);
440 static xmlDocPtr doparse(domdoc* This, char const* ptr, int len, xmlCharEncoding encoding)
442 xmlDocPtr doc = NULL;
443 xmlParserCtxtPtr pctx;
444 static xmlSAXHandler sax_handler = {
445 xmlSAX2InternalSubset, /* internalSubset */
446 xmlSAX2IsStandalone, /* isStandalone */
447 xmlSAX2HasInternalSubset, /* hasInternalSubset */
448 xmlSAX2HasExternalSubset, /* hasExternalSubset */
449 xmlSAX2ResolveEntity, /* resolveEntity */
450 xmlSAX2GetEntity, /* getEntity */
451 xmlSAX2EntityDecl, /* entityDecl */
452 xmlSAX2NotationDecl, /* notationDecl */
453 xmlSAX2AttributeDecl, /* attributeDecl */
454 xmlSAX2ElementDecl, /* elementDecl */
455 xmlSAX2UnparsedEntityDecl, /* unparsedEntityDecl */
456 xmlSAX2SetDocumentLocator, /* setDocumentLocator */
457 xmlSAX2StartDocument, /* startDocument */
458 xmlSAX2EndDocument, /* endDocument */
459 xmlSAX2StartElement, /* startElement */
460 xmlSAX2EndElement, /* endElement */
461 xmlSAX2Reference, /* reference */
462 sax_characters, /* characters */
463 sax_characters, /* ignorableWhitespace */
464 xmlSAX2ProcessingInstruction, /* processingInstruction */
465 xmlSAX2Comment, /* comment */
466 sax_warning, /* warning */
467 sax_error, /* error */
468 sax_error, /* fatalError */
469 xmlSAX2GetParameterEntity, /* getParameterEntity */
470 xmlSAX2CDataBlock, /* cdataBlock */
471 xmlSAX2ExternalSubset, /* externalSubset */
472 0, /* initialized */
473 NULL, /* _private */
474 xmlSAX2StartElementNs, /* startElementNs */
475 xmlSAX2EndElementNs, /* endElementNs */
476 sax_serror /* serror */
478 xmlInitParser();
480 pctx = xmlCreateMemoryParserCtxt(ptr, len);
481 if (!pctx)
483 ERR("Failed to create parser context\n");
484 return NULL;
487 if (pctx->sax) xmlFree(pctx->sax);
488 pctx->sax = &sax_handler;
489 pctx->_private = This;
490 pctx->recovery = 0;
492 if (encoding != XML_CHAR_ENCODING_NONE)
493 xmlSwitchEncoding(pctx, encoding);
495 xmlParseDocument(pctx);
497 if (pctx->wellFormed)
499 doc = pctx->myDoc;
501 else
503 xmlFreeDoc(pctx->myDoc);
504 pctx->myDoc = NULL;
506 pctx->sax = NULL;
507 xmlFreeParserCtxt(pctx);
509 /* TODO: put this in one of the SAX callbacks */
510 /* create first child as a <?xml...?> */
511 if (doc && doc->standalone != -1)
513 xmlNodePtr node;
514 char buff[30];
515 xmlChar *xmlbuff = (xmlChar*)buff;
517 node = xmlNewDocPI( doc, (xmlChar*)"xml", NULL );
519 /* version attribute can't be omitted */
520 sprintf(buff, "version=\"%s\"", doc->version ? (char*)doc->version : "1.0");
521 xmlNodeAddContent( node, xmlbuff );
523 if (doc->encoding)
525 sprintf(buff, " encoding=\"%s\"", doc->encoding);
526 xmlNodeAddContent( node, xmlbuff );
529 if (doc->standalone != -2)
531 sprintf(buff, " standalone=\"%s\"", doc->standalone == 0 ? "no" : "yes");
532 xmlNodeAddContent( node, xmlbuff );
535 xmldoc_link_xmldecl( doc, node );
538 return doc;
541 void xmldoc_init(xmlDocPtr doc, MSXML_VERSION version)
543 doc->_private = create_priv();
544 priv_from_xmlDocPtr(doc)->properties = create_properties(version);
547 LONG xmldoc_add_ref(xmlDocPtr doc)
549 LONG ref = InterlockedIncrement(&priv_from_xmlDocPtr(doc)->refs);
550 TRACE("(%p)->(%d)\n", doc, ref);
551 return ref;
554 LONG xmldoc_release(xmlDocPtr doc)
556 xmldoc_priv *priv = priv_from_xmlDocPtr(doc);
557 LONG ref = InterlockedDecrement(&priv->refs);
558 TRACE("(%p)->(%d)\n", doc, ref);
559 if(ref == 0)
561 orphan_entry *orphan, *orphan2;
562 TRACE("freeing docptr %p\n", doc);
564 LIST_FOR_EACH_ENTRY_SAFE( orphan, orphan2, &priv->orphans, orphan_entry, entry )
566 xmlFreeNode( orphan->node );
567 heap_free( orphan );
569 free_properties(priv->properties);
570 heap_free(doc->_private);
572 xmlFreeDoc(doc);
575 return ref;
578 HRESULT xmldoc_add_orphan(xmlDocPtr doc, xmlNodePtr node)
580 xmldoc_priv *priv = priv_from_xmlDocPtr(doc);
581 orphan_entry *entry;
583 entry = heap_alloc( sizeof (*entry) );
584 if(!entry)
585 return E_OUTOFMEMORY;
587 entry->node = node;
588 list_add_head( &priv->orphans, &entry->entry );
589 return S_OK;
592 HRESULT xmldoc_remove_orphan(xmlDocPtr doc, xmlNodePtr node)
594 xmldoc_priv *priv = priv_from_xmlDocPtr(doc);
595 orphan_entry *entry, *entry2;
597 LIST_FOR_EACH_ENTRY_SAFE( entry, entry2, &priv->orphans, orphan_entry, entry )
599 if( entry->node == node )
601 list_remove( &entry->entry );
602 heap_free( entry );
603 return S_OK;
607 return S_FALSE;
610 static inline xmlDocPtr get_doc( domdoc *This )
612 return (xmlDocPtr)This->node.node;
615 static HRESULT attach_xmldoc(domdoc *This, xmlDocPtr xml )
617 if(This->node.node)
619 priv_from_xmlDocPtr(get_doc(This))->properties = NULL;
620 if (xmldoc_release(get_doc(This)) != 0)
621 priv_from_xmlDocPtr(get_doc(This))->properties =
622 copy_properties(This->properties);
625 This->node.node = (xmlNodePtr) xml;
627 if(This->node.node)
629 xmldoc_add_ref(get_doc(This));
630 priv_from_xmlDocPtr(get_doc(This))->properties = This->properties;
633 return S_OK;
636 static inline domdoc *impl_from_IXMLDOMDocument3( IXMLDOMDocument3 *iface )
638 return CONTAINING_RECORD(iface, domdoc, IXMLDOMDocument3_iface);
641 static inline domdoc *impl_from_IPersistStreamInit(IPersistStreamInit *iface)
643 return CONTAINING_RECORD(iface, domdoc, IPersistStreamInit_iface);
646 static inline domdoc *impl_from_IObjectWithSite(IObjectWithSite *iface)
648 return CONTAINING_RECORD(iface, domdoc, IObjectWithSite_iface);
651 static inline domdoc *impl_from_IObjectSafety(IObjectSafety *iface)
653 return CONTAINING_RECORD(iface, domdoc, IObjectSafety_iface);
656 static inline domdoc *impl_from_ISupportErrorInfo(ISupportErrorInfo *iface)
658 return CONTAINING_RECORD(iface, domdoc, ISupportErrorInfo_iface);
661 static inline domdoc *impl_from_IConnectionPointContainer(IConnectionPointContainer *iface)
663 return CONTAINING_RECORD(iface, domdoc, IConnectionPointContainer_iface);
666 /************************************************************************
667 * domdoc implementation of IPersistStream.
669 static HRESULT WINAPI domdoc_IPersistStreamInit_QueryInterface(
670 IPersistStreamInit *iface, REFIID riid, void **ppvObj)
672 domdoc* This = impl_from_IPersistStreamInit(iface);
673 return IXMLDOMDocument3_QueryInterface(&This->IXMLDOMDocument3_iface, riid, ppvObj);
676 static ULONG WINAPI domdoc_IPersistStreamInit_AddRef(
677 IPersistStreamInit *iface)
679 domdoc* This = impl_from_IPersistStreamInit(iface);
680 return IXMLDOMDocument3_AddRef(&This->IXMLDOMDocument3_iface);
683 static ULONG WINAPI domdoc_IPersistStreamInit_Release(
684 IPersistStreamInit *iface)
686 domdoc* This = impl_from_IPersistStreamInit(iface);
687 return IXMLDOMDocument3_Release(&This->IXMLDOMDocument3_iface);
690 static HRESULT WINAPI domdoc_IPersistStreamInit_GetClassID(
691 IPersistStreamInit *iface, CLSID *classid)
693 domdoc* This = impl_from_IPersistStreamInit(iface);
694 TRACE("(%p)->(%p)\n", This, classid);
696 if(!classid)
697 return E_POINTER;
699 *classid = *DOMDocument_version(This->properties->version);
701 return S_OK;
704 static HRESULT WINAPI domdoc_IPersistStreamInit_IsDirty(
705 IPersistStreamInit *iface)
707 domdoc *This = impl_from_IPersistStreamInit(iface);
708 FIXME("(%p): stub!\n", This);
709 return S_FALSE;
712 static HRESULT WINAPI domdoc_IPersistStreamInit_Load(
713 IPersistStreamInit *iface, LPSTREAM pStm)
715 domdoc *This = impl_from_IPersistStreamInit(iface);
716 HRESULT hr;
717 HGLOBAL hglobal;
718 DWORD read, written, len;
719 BYTE buf[4096];
720 char *ptr;
721 xmlDocPtr xmldoc = NULL;
723 TRACE("(%p)->(%p)\n", This, pStm);
725 if (!pStm)
726 return E_INVALIDARG;
728 hr = CreateStreamOnHGlobal(NULL, TRUE, &This->stream);
729 if (FAILED(hr))
730 return hr;
734 IStream_Read(pStm, buf, sizeof(buf), &read);
735 hr = IStream_Write(This->stream, buf, read, &written);
736 } while(SUCCEEDED(hr) && written != 0 && read != 0);
738 if (FAILED(hr))
740 ERR("Failed to copy stream\n");
741 return hr;
744 hr = GetHGlobalFromStream(This->stream, &hglobal);
745 if (FAILED(hr))
746 return hr;
748 len = GlobalSize(hglobal);
749 ptr = GlobalLock(hglobal);
750 if (len != 0)
751 xmldoc = doparse(This, ptr, len, XML_CHAR_ENCODING_NONE);
752 GlobalUnlock(hglobal);
754 if (!xmldoc)
756 ERR("Failed to parse xml\n");
757 return E_FAIL;
760 xmldoc->_private = create_priv();
762 return attach_xmldoc(This, xmldoc);
765 static HRESULT WINAPI domdoc_IPersistStreamInit_Save(
766 IPersistStreamInit *iface, IStream *stream, BOOL clr_dirty)
768 domdoc *This = impl_from_IPersistStreamInit(iface);
769 BSTR xmlString;
770 HRESULT hr;
772 TRACE("(%p)->(%p %d)\n", This, stream, clr_dirty);
774 hr = IXMLDOMDocument3_get_xml(&This->IXMLDOMDocument3_iface, &xmlString);
775 if(hr == S_OK)
777 DWORD len = SysStringLen(xmlString) * sizeof(WCHAR);
779 hr = IStream_Write( stream, xmlString, len, NULL );
780 SysFreeString(xmlString);
783 TRACE("ret 0x%08x\n", hr);
785 return hr;
788 static HRESULT WINAPI domdoc_IPersistStreamInit_GetSizeMax(
789 IPersistStreamInit *iface, ULARGE_INTEGER *pcbSize)
791 domdoc *This = impl_from_IPersistStreamInit(iface);
792 TRACE("(%p)->(%p): stub!\n", This, pcbSize);
793 return E_NOTIMPL;
796 static HRESULT WINAPI domdoc_IPersistStreamInit_InitNew(
797 IPersistStreamInit *iface)
799 domdoc *This = impl_from_IPersistStreamInit(iface);
800 TRACE("(%p)\n", This);
801 return S_OK;
804 static const IPersistStreamInitVtbl xmldoc_IPersistStreamInit_VTable =
806 domdoc_IPersistStreamInit_QueryInterface,
807 domdoc_IPersistStreamInit_AddRef,
808 domdoc_IPersistStreamInit_Release,
809 domdoc_IPersistStreamInit_GetClassID,
810 domdoc_IPersistStreamInit_IsDirty,
811 domdoc_IPersistStreamInit_Load,
812 domdoc_IPersistStreamInit_Save,
813 domdoc_IPersistStreamInit_GetSizeMax,
814 domdoc_IPersistStreamInit_InitNew
817 /* ISupportErrorInfo interface */
818 static HRESULT WINAPI support_error_QueryInterface(
819 ISupportErrorInfo *iface,
820 REFIID riid, void** ppvObj )
822 domdoc *This = impl_from_ISupportErrorInfo(iface);
823 return IXMLDOMDocument3_QueryInterface(&This->IXMLDOMDocument3_iface, riid, ppvObj);
826 static ULONG WINAPI support_error_AddRef(
827 ISupportErrorInfo *iface )
829 domdoc *This = impl_from_ISupportErrorInfo(iface);
830 return IXMLDOMDocument3_AddRef(&This->IXMLDOMDocument3_iface);
833 static ULONG WINAPI support_error_Release(
834 ISupportErrorInfo *iface )
836 domdoc *This = impl_from_ISupportErrorInfo(iface);
837 return IXMLDOMDocument3_Release(&This->IXMLDOMDocument3_iface);
840 static HRESULT WINAPI support_error_InterfaceSupportsErrorInfo(
841 ISupportErrorInfo *iface,
842 REFIID riid )
844 FIXME("(%p)->(%s)\n", iface, debugstr_guid(riid));
845 return S_FALSE;
848 static const struct ISupportErrorInfoVtbl support_error_vtbl =
850 support_error_QueryInterface,
851 support_error_AddRef,
852 support_error_Release,
853 support_error_InterfaceSupportsErrorInfo
856 /* IXMLDOMDocument2 interface */
857 static HRESULT WINAPI domdoc_QueryInterface( IXMLDOMDocument3 *iface, REFIID riid, void** ppvObject )
859 domdoc *This = impl_from_IXMLDOMDocument3( iface );
861 TRACE("(%p)->(%s %p)\n", This, debugstr_guid( riid ), ppvObject );
863 *ppvObject = NULL;
865 if ( IsEqualGUID( riid, &IID_IUnknown ) ||
866 IsEqualGUID( riid, &IID_IDispatch ) ||
867 IsEqualGUID( riid, &IID_IXMLDOMNode ) ||
868 IsEqualGUID( riid, &IID_IXMLDOMDocument ) ||
869 IsEqualGUID( riid, &IID_IXMLDOMDocument2 )||
870 IsEqualGUID( riid, &IID_IXMLDOMDocument3 ))
872 *ppvObject = iface;
874 else if (IsEqualGUID(&IID_IPersistStream, riid) ||
875 IsEqualGUID(&IID_IPersistStreamInit, riid))
877 *ppvObject = &This->IPersistStreamInit_iface;
879 else if (IsEqualGUID(&IID_IObjectWithSite, riid))
881 *ppvObject = &This->IObjectWithSite_iface;
883 else if (IsEqualGUID(&IID_IObjectSafety, riid))
885 *ppvObject = &This->IObjectSafety_iface;
887 else if( IsEqualGUID( riid, &IID_ISupportErrorInfo ))
889 *ppvObject = &This->ISupportErrorInfo_iface;
891 else if(node_query_interface(&This->node, riid, ppvObject))
893 return *ppvObject ? S_OK : E_NOINTERFACE;
895 else if (IsEqualGUID( riid, &IID_IConnectionPointContainer ))
897 *ppvObject = &This->IConnectionPointContainer_iface;
899 else
901 TRACE("interface %s not implemented\n", debugstr_guid(riid));
902 return E_NOINTERFACE;
905 IUnknown_AddRef((IUnknown*)*ppvObject);
907 return S_OK;
911 static ULONG WINAPI domdoc_AddRef(
912 IXMLDOMDocument3 *iface )
914 domdoc *This = impl_from_IXMLDOMDocument3( iface );
915 ULONG ref = InterlockedIncrement( &This->ref );
916 TRACE("(%p)->(%d)\n", This, ref );
917 return ref;
921 static ULONG WINAPI domdoc_Release(
922 IXMLDOMDocument3 *iface )
924 domdoc *This = impl_from_IXMLDOMDocument3( iface );
925 LONG ref = InterlockedDecrement( &This->ref );
927 TRACE("(%p)->(%d)\n", This, ref );
929 if ( ref == 0 )
931 int eid;
933 if(This->bsc)
934 detach_bsc(This->bsc);
936 if (This->site)
937 IUnknown_Release( This->site );
938 destroy_xmlnode(&This->node);
939 if (This->stream)
940 IStream_Release(This->stream);
942 for (eid = 0; eid < EVENTID_LAST; eid++)
943 if (This->events[eid]) IDispatch_Release(This->events[eid]);
945 heap_free(This);
948 return ref;
951 static HRESULT WINAPI domdoc_GetTypeInfoCount( IXMLDOMDocument3 *iface, UINT* pctinfo )
953 domdoc *This = impl_from_IXMLDOMDocument3( iface );
955 TRACE("(%p)->(%p)\n", This, pctinfo);
957 *pctinfo = 1;
959 return S_OK;
962 static HRESULT WINAPI domdoc_GetTypeInfo(
963 IXMLDOMDocument3 *iface,
964 UINT iTInfo, LCID lcid, ITypeInfo** ppTInfo )
966 domdoc *This = impl_from_IXMLDOMDocument3( iface );
967 HRESULT hr;
969 TRACE("(%p)->(%u %u %p)\n", This, iTInfo, lcid, ppTInfo);
971 hr = get_typeinfo(IXMLDOMDocument2_tid, ppTInfo);
973 return hr;
976 static HRESULT WINAPI domdoc_GetIDsOfNames(
977 IXMLDOMDocument3 *iface,
978 REFIID riid,
979 LPOLESTR* rgszNames,
980 UINT cNames,
981 LCID lcid,
982 DISPID* rgDispId)
984 domdoc *This = impl_from_IXMLDOMDocument3( iface );
985 ITypeInfo *typeinfo;
986 HRESULT hr;
988 TRACE("(%p)->(%s %p %u %u %p)\n", This, debugstr_guid(riid), rgszNames, cNames,
989 lcid, rgDispId);
991 if(!rgszNames || cNames == 0 || !rgDispId)
992 return E_INVALIDARG;
994 hr = get_typeinfo(IXMLDOMDocument2_tid, &typeinfo);
995 if(SUCCEEDED(hr))
997 hr = ITypeInfo_GetIDsOfNames(typeinfo, rgszNames, cNames, rgDispId);
998 ITypeInfo_Release(typeinfo);
1001 return hr;
1005 static HRESULT WINAPI domdoc_Invoke(
1006 IXMLDOMDocument3 *iface,
1007 DISPID dispIdMember,
1008 REFIID riid,
1009 LCID lcid,
1010 WORD wFlags,
1011 DISPPARAMS* pDispParams,
1012 VARIANT* pVarResult,
1013 EXCEPINFO* pExcepInfo,
1014 UINT* puArgErr)
1016 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1017 ITypeInfo *typeinfo;
1018 HRESULT hr;
1020 TRACE("(%p)->(%d %s %d %d %p %p %p %p)\n", This, dispIdMember, debugstr_guid(riid),
1021 lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
1023 hr = get_typeinfo(IXMLDOMDocument2_tid, &typeinfo);
1024 if(SUCCEEDED(hr))
1026 hr = ITypeInfo_Invoke(typeinfo, &This->IXMLDOMDocument3_iface, dispIdMember, wFlags,
1027 pDispParams, pVarResult, pExcepInfo, puArgErr);
1028 ITypeInfo_Release(typeinfo);
1031 return hr;
1035 static HRESULT WINAPI domdoc_get_nodeName(
1036 IXMLDOMDocument3 *iface,
1037 BSTR* name )
1039 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1041 static const WCHAR documentW[] = {'#','d','o','c','u','m','e','n','t',0};
1043 TRACE("(%p)->(%p)\n", This, name);
1045 return return_bstr(documentW, name);
1049 static HRESULT WINAPI domdoc_get_nodeValue(
1050 IXMLDOMDocument3 *iface,
1051 VARIANT* value )
1053 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1055 TRACE("(%p)->(%p)\n", This, value);
1057 if(!value)
1058 return E_INVALIDARG;
1060 V_VT(value) = VT_NULL;
1061 V_BSTR(value) = NULL; /* tests show that we should do this */
1062 return S_FALSE;
1066 static HRESULT WINAPI domdoc_put_nodeValue(
1067 IXMLDOMDocument3 *iface,
1068 VARIANT value)
1070 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1071 TRACE("(%p)->(v%d)\n", This, V_VT(&value));
1072 return E_FAIL;
1076 static HRESULT WINAPI domdoc_get_nodeType(
1077 IXMLDOMDocument3 *iface,
1078 DOMNodeType* type )
1080 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1082 TRACE("(%p)->(%p)\n", This, type);
1084 *type = NODE_DOCUMENT;
1085 return S_OK;
1089 static HRESULT WINAPI domdoc_get_parentNode(
1090 IXMLDOMDocument3 *iface,
1091 IXMLDOMNode** parent )
1093 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1095 TRACE("(%p)->(%p)\n", This, parent);
1097 return node_get_parent(&This->node, parent);
1101 static HRESULT WINAPI domdoc_get_childNodes(
1102 IXMLDOMDocument3 *iface,
1103 IXMLDOMNodeList** childList )
1105 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1107 TRACE("(%p)->(%p)\n", This, childList);
1109 return node_get_child_nodes(&This->node, childList);
1113 static HRESULT WINAPI domdoc_get_firstChild(
1114 IXMLDOMDocument3 *iface,
1115 IXMLDOMNode** firstChild )
1117 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1119 TRACE("(%p)->(%p)\n", This, firstChild);
1121 return node_get_first_child(&This->node, firstChild);
1125 static HRESULT WINAPI domdoc_get_lastChild(
1126 IXMLDOMDocument3 *iface,
1127 IXMLDOMNode** lastChild )
1129 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1131 TRACE("(%p)->(%p)\n", This, lastChild);
1133 return node_get_last_child(&This->node, lastChild);
1137 static HRESULT WINAPI domdoc_get_previousSibling(
1138 IXMLDOMDocument3 *iface,
1139 IXMLDOMNode** previousSibling )
1141 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1143 TRACE("(%p)->(%p)\n", This, previousSibling);
1145 return return_null_node(previousSibling);
1149 static HRESULT WINAPI domdoc_get_nextSibling(
1150 IXMLDOMDocument3 *iface,
1151 IXMLDOMNode** nextSibling )
1153 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1155 TRACE("(%p)->(%p)\n", This, nextSibling);
1157 return return_null_node(nextSibling);
1161 static HRESULT WINAPI domdoc_get_attributes(
1162 IXMLDOMDocument3 *iface,
1163 IXMLDOMNamedNodeMap** attributeMap )
1165 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1167 TRACE("(%p)->(%p)\n", This, attributeMap);
1169 return return_null_ptr((void**)attributeMap);
1173 static HRESULT WINAPI domdoc_insertBefore(
1174 IXMLDOMDocument3 *iface,
1175 IXMLDOMNode* newChild,
1176 VARIANT refChild,
1177 IXMLDOMNode** outNewChild )
1179 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1181 TRACE("(%p)->(%p x%d %p)\n", This, newChild, V_VT(&refChild), outNewChild);
1183 return node_insert_before(&This->node, newChild, &refChild, outNewChild);
1187 static HRESULT WINAPI domdoc_replaceChild(
1188 IXMLDOMDocument3 *iface,
1189 IXMLDOMNode* newChild,
1190 IXMLDOMNode* oldChild,
1191 IXMLDOMNode** outOldChild)
1193 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1195 TRACE("(%p)->(%p %p %p)\n", This, newChild, oldChild, outOldChild);
1197 return node_replace_child(&This->node, newChild, oldChild, outOldChild);
1201 static HRESULT WINAPI domdoc_removeChild(
1202 IXMLDOMDocument3 *iface,
1203 IXMLDOMNode *child,
1204 IXMLDOMNode **oldChild)
1206 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1207 TRACE("(%p)->(%p %p)\n", This, child, oldChild);
1208 return node_remove_child(&This->node, child, oldChild);
1212 static HRESULT WINAPI domdoc_appendChild(
1213 IXMLDOMDocument3 *iface,
1214 IXMLDOMNode *child,
1215 IXMLDOMNode **outChild)
1217 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1218 TRACE("(%p)->(%p %p)\n", This, child, outChild);
1219 return node_append_child(&This->node, child, outChild);
1223 static HRESULT WINAPI domdoc_hasChildNodes(
1224 IXMLDOMDocument3 *iface,
1225 VARIANT_BOOL *ret)
1227 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1228 TRACE("(%p)->(%p)\n", This, ret);
1229 return node_has_childnodes(&This->node, ret);
1233 static HRESULT WINAPI domdoc_get_ownerDocument(
1234 IXMLDOMDocument3 *iface,
1235 IXMLDOMDocument **doc)
1237 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1238 TRACE("(%p)->(%p)\n", This, doc);
1239 return node_get_owner_doc(&This->node, doc);
1243 static HRESULT WINAPI domdoc_cloneNode(
1244 IXMLDOMDocument3 *iface,
1245 VARIANT_BOOL deep,
1246 IXMLDOMNode** outNode)
1248 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1249 TRACE("(%p)->(%d %p)\n", This, deep, outNode);
1250 return node_clone( &This->node, deep, outNode );
1254 static HRESULT WINAPI domdoc_get_nodeTypeString(
1255 IXMLDOMDocument3 *iface,
1256 BSTR *p)
1258 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1259 static const WCHAR documentW[] = {'d','o','c','u','m','e','n','t',0};
1261 TRACE("(%p)->(%p)\n", This, p);
1263 return return_bstr(documentW, p);
1267 static HRESULT WINAPI domdoc_get_text(
1268 IXMLDOMDocument3 *iface,
1269 BSTR *p)
1271 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1272 TRACE("(%p)->(%p)\n", This, p);
1273 return node_get_text(&This->node, p);
1277 static HRESULT WINAPI domdoc_put_text(
1278 IXMLDOMDocument3 *iface,
1279 BSTR text )
1281 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1282 TRACE("(%p)->(%s)\n", This, debugstr_w(text));
1283 return E_FAIL;
1287 static HRESULT WINAPI domdoc_get_specified(
1288 IXMLDOMDocument3 *iface,
1289 VARIANT_BOOL* isSpecified )
1291 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1292 FIXME("(%p)->(%p) stub!\n", This, isSpecified);
1293 *isSpecified = VARIANT_TRUE;
1294 return S_OK;
1298 static HRESULT WINAPI domdoc_get_definition(
1299 IXMLDOMDocument3 *iface,
1300 IXMLDOMNode** definitionNode )
1302 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1303 FIXME("(%p)->(%p)\n", This, definitionNode);
1304 return E_NOTIMPL;
1308 static HRESULT WINAPI domdoc_get_nodeTypedValue(
1309 IXMLDOMDocument3 *iface,
1310 VARIANT* v )
1312 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1313 TRACE("(%p)->(%p)\n", This, v);
1314 return return_null_var(v);
1317 static HRESULT WINAPI domdoc_put_nodeTypedValue(
1318 IXMLDOMDocument3 *iface,
1319 VARIANT typedValue )
1321 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1322 FIXME("(%p)->(%s)\n", This, debugstr_variant(&typedValue));
1323 return E_NOTIMPL;
1327 static HRESULT WINAPI domdoc_get_dataType(
1328 IXMLDOMDocument3 *iface,
1329 VARIANT* typename )
1331 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1332 TRACE("(%p)->(%p)\n", This, typename);
1333 return return_null_var( typename );
1337 static HRESULT WINAPI domdoc_put_dataType(
1338 IXMLDOMDocument3 *iface,
1339 BSTR dataTypeName )
1341 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1343 FIXME("(%p)->(%s)\n", This, debugstr_w(dataTypeName));
1345 if(!dataTypeName)
1346 return E_INVALIDARG;
1348 return E_FAIL;
1351 static int XMLCALL domdoc_get_xml_writecallback(void *ctx, const char *data, int len)
1353 return xmlBufferAdd((xmlBufferPtr)ctx, (xmlChar*)data, len) == 0 ? len : 0;
1356 static HRESULT WINAPI domdoc_get_xml(
1357 IXMLDOMDocument3 *iface,
1358 BSTR* p)
1360 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1361 xmlSaveCtxtPtr ctxt;
1362 xmlBufferPtr buf;
1363 int options;
1364 long ret;
1366 TRACE("(%p)->(%p)\n", This, p);
1368 if(!p)
1369 return E_INVALIDARG;
1371 *p = NULL;
1373 buf = xmlBufferCreate();
1374 if(!buf)
1375 return E_OUTOFMEMORY;
1377 options = XML_SAVE_FORMAT | XML_SAVE_NO_DECL;
1378 ctxt = xmlSaveToIO(domdoc_get_xml_writecallback, NULL, buf, "UTF-8", options);
1380 if(!ctxt)
1382 xmlBufferFree(buf);
1383 return E_OUTOFMEMORY;
1386 ret = xmlSaveDoc(ctxt, get_doc(This));
1387 /* flushes on close */
1388 xmlSaveClose(ctxt);
1390 TRACE("%ld, len=%d\n", ret, xmlBufferLength(buf));
1391 if(ret != -1 && xmlBufferLength(buf) > 0)
1393 BSTR content;
1395 content = bstr_from_xmlChar(xmlBufferContent(buf));
1396 content = EnsureCorrectEOL(content);
1398 *p = content;
1400 else
1402 *p = SysAllocStringLen(NULL, 0);
1405 xmlBufferFree(buf);
1407 return *p ? S_OK : E_OUTOFMEMORY;
1411 static HRESULT WINAPI domdoc_transformNode(
1412 IXMLDOMDocument3 *iface,
1413 IXMLDOMNode *node,
1414 BSTR *p)
1416 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1417 TRACE("(%p)->(%p %p)\n", This, node, p);
1418 return node_transform_node(&This->node, node, p);
1422 static HRESULT WINAPI domdoc_selectNodes(
1423 IXMLDOMDocument3 *iface,
1424 BSTR p,
1425 IXMLDOMNodeList **outList)
1427 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1428 TRACE("(%p)->(%s %p)\n", This, debugstr_w(p), outList);
1429 return node_select_nodes(&This->node, p, outList);
1433 static HRESULT WINAPI domdoc_selectSingleNode(
1434 IXMLDOMDocument3 *iface,
1435 BSTR p,
1436 IXMLDOMNode **outNode)
1438 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1439 TRACE("(%p)->(%s %p)\n", This, debugstr_w(p), outNode);
1440 return node_select_singlenode(&This->node, p, outNode);
1444 static HRESULT WINAPI domdoc_get_parsed(
1445 IXMLDOMDocument3 *iface,
1446 VARIANT_BOOL* isParsed )
1448 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1449 FIXME("(%p)->(%p) stub!\n", This, isParsed);
1450 *isParsed = VARIANT_TRUE;
1451 return S_OK;
1455 static HRESULT WINAPI domdoc_get_namespaceURI(
1456 IXMLDOMDocument3 *iface,
1457 BSTR* namespaceURI )
1459 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1460 TRACE("(%p)->(%p)\n", This, namespaceURI);
1461 return node_get_namespaceURI(&This->node, namespaceURI);
1465 static HRESULT WINAPI domdoc_get_prefix(
1466 IXMLDOMDocument3 *iface,
1467 BSTR* prefix )
1469 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1470 TRACE("(%p)->(%p)\n", This, prefix);
1471 return return_null_bstr( prefix );
1475 static HRESULT WINAPI domdoc_get_baseName(
1476 IXMLDOMDocument3 *iface,
1477 BSTR* name )
1479 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1480 TRACE("(%p)->(%p)\n", This, name);
1481 return return_null_bstr( name );
1485 static HRESULT WINAPI domdoc_transformNodeToObject(
1486 IXMLDOMDocument3 *iface,
1487 IXMLDOMNode* stylesheet,
1488 VARIANT outputObject)
1490 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1491 FIXME("(%p)->(%p %s)\n", This, stylesheet, debugstr_variant(&outputObject));
1492 return E_NOTIMPL;
1496 static HRESULT WINAPI domdoc_get_doctype(
1497 IXMLDOMDocument3 *iface,
1498 IXMLDOMDocumentType** doctype )
1500 domdoc *This = impl_from_IXMLDOMDocument3(iface);
1501 IXMLDOMNode *node;
1502 xmlDtdPtr dtd;
1503 HRESULT hr;
1505 TRACE("(%p)->(%p)\n", This, doctype);
1507 if (!doctype) return E_INVALIDARG;
1509 *doctype = NULL;
1511 dtd = xmlGetIntSubset(get_doc(This));
1512 if (!dtd) return S_FALSE;
1514 node = create_node((xmlNodePtr)dtd);
1515 if (!node) return S_FALSE;
1517 hr = IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMDocumentType, (void**)doctype);
1518 IXMLDOMNode_Release(node);
1520 return hr;
1524 static HRESULT WINAPI domdoc_get_implementation(
1525 IXMLDOMDocument3 *iface,
1526 IXMLDOMImplementation** impl )
1528 domdoc *This = impl_from_IXMLDOMDocument3(iface);
1530 TRACE("(%p)->(%p)\n", This, impl);
1532 if(!impl)
1533 return E_INVALIDARG;
1535 *impl = (IXMLDOMImplementation*)create_doc_Implementation();
1537 return S_OK;
1540 static HRESULT WINAPI domdoc_get_documentElement(
1541 IXMLDOMDocument3 *iface,
1542 IXMLDOMElement** DOMElement )
1544 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1545 IXMLDOMNode *element_node;
1546 xmlNodePtr root;
1547 HRESULT hr;
1549 TRACE("(%p)->(%p)\n", This, DOMElement);
1551 if(!DOMElement)
1552 return E_INVALIDARG;
1554 *DOMElement = NULL;
1556 root = xmlDocGetRootElement( get_doc(This) );
1557 if ( !root )
1558 return S_FALSE;
1560 element_node = create_node( root );
1561 if(!element_node) return S_FALSE;
1563 hr = IXMLDOMNode_QueryInterface(element_node, &IID_IXMLDOMElement, (void**)DOMElement);
1564 IXMLDOMNode_Release(element_node);
1566 return hr;
1570 static HRESULT WINAPI domdoc_put_documentElement(
1571 IXMLDOMDocument3 *iface,
1572 IXMLDOMElement* DOMElement )
1574 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1575 IXMLDOMNode *elementNode;
1576 xmlNodePtr oldRoot;
1577 xmlnode *xmlNode;
1578 HRESULT hr;
1580 TRACE("(%p)->(%p)\n", This, DOMElement);
1582 hr = IXMLDOMElement_QueryInterface( DOMElement, &IID_IXMLDOMNode, (void**)&elementNode );
1583 if(FAILED(hr))
1584 return hr;
1586 xmlNode = get_node_obj( elementNode );
1587 if(!xmlNode) return E_FAIL;
1589 if(!xmlNode->node->parent)
1590 if(xmldoc_remove_orphan(xmlNode->node->doc, xmlNode->node) != S_OK)
1591 WARN("%p is not an orphan of %p\n", xmlNode->node->doc, xmlNode->node);
1593 oldRoot = xmlDocSetRootElement( get_doc(This), xmlNode->node);
1594 IXMLDOMNode_Release( elementNode );
1596 if(oldRoot)
1597 xmldoc_add_orphan(oldRoot->doc, oldRoot);
1599 return S_OK;
1603 static HRESULT WINAPI domdoc_createElement(
1604 IXMLDOMDocument3 *iface,
1605 BSTR tagname,
1606 IXMLDOMElement** element )
1608 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1609 IXMLDOMNode *node;
1610 VARIANT type;
1611 HRESULT hr;
1613 TRACE("(%p)->(%s %p)\n", This, debugstr_w(tagname), element);
1615 if (!element || !tagname) return E_INVALIDARG;
1617 V_VT(&type) = VT_I1;
1618 V_I1(&type) = NODE_ELEMENT;
1620 hr = IXMLDOMDocument3_createNode(iface, type, tagname, NULL, &node);
1621 if (hr == S_OK)
1623 IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMElement, (void**)element);
1624 IXMLDOMNode_Release(node);
1627 return hr;
1631 static HRESULT WINAPI domdoc_createDocumentFragment(
1632 IXMLDOMDocument3 *iface,
1633 IXMLDOMDocumentFragment** frag )
1635 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1636 IXMLDOMNode *node;
1637 VARIANT type;
1638 HRESULT hr;
1640 TRACE("(%p)->(%p)\n", This, frag);
1642 if (!frag) return E_INVALIDARG;
1644 *frag = NULL;
1646 V_VT(&type) = VT_I1;
1647 V_I1(&type) = NODE_DOCUMENT_FRAGMENT;
1649 hr = IXMLDOMDocument3_createNode(iface, type, NULL, NULL, &node);
1650 if (hr == S_OK)
1652 IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMDocumentFragment, (void**)frag);
1653 IXMLDOMNode_Release(node);
1656 return hr;
1660 static HRESULT WINAPI domdoc_createTextNode(
1661 IXMLDOMDocument3 *iface,
1662 BSTR data,
1663 IXMLDOMText** text )
1665 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1666 IXMLDOMNode *node;
1667 VARIANT type;
1668 HRESULT hr;
1670 TRACE("(%p)->(%s %p)\n", This, debugstr_w(data), text);
1672 if (!text) return E_INVALIDARG;
1674 *text = NULL;
1676 V_VT(&type) = VT_I1;
1677 V_I1(&type) = NODE_TEXT;
1679 hr = IXMLDOMDocument3_createNode(iface, type, NULL, NULL, &node);
1680 if (hr == S_OK)
1682 IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMText, (void**)text);
1683 IXMLDOMNode_Release(node);
1684 hr = IXMLDOMText_put_data(*text, data);
1687 return hr;
1691 static HRESULT WINAPI domdoc_createComment(
1692 IXMLDOMDocument3 *iface,
1693 BSTR data,
1694 IXMLDOMComment** comment )
1696 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1697 VARIANT type;
1698 HRESULT hr;
1699 IXMLDOMNode *node;
1701 TRACE("(%p)->(%s %p)\n", This, debugstr_w(data), comment);
1703 if (!comment) return E_INVALIDARG;
1705 *comment = NULL;
1707 V_VT(&type) = VT_I1;
1708 V_I1(&type) = NODE_COMMENT;
1710 hr = IXMLDOMDocument3_createNode(iface, type, NULL, NULL, &node);
1711 if (hr == S_OK)
1713 IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMComment, (void**)comment);
1714 IXMLDOMNode_Release(node);
1715 hr = IXMLDOMComment_put_data(*comment, data);
1718 return hr;
1722 static HRESULT WINAPI domdoc_createCDATASection(
1723 IXMLDOMDocument3 *iface,
1724 BSTR data,
1725 IXMLDOMCDATASection** cdata )
1727 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1728 IXMLDOMNode *node;
1729 VARIANT type;
1730 HRESULT hr;
1732 TRACE("(%p)->(%s %p)\n", This, debugstr_w(data), cdata);
1734 if (!cdata) return E_INVALIDARG;
1736 *cdata = NULL;
1738 V_VT(&type) = VT_I1;
1739 V_I1(&type) = NODE_CDATA_SECTION;
1741 hr = IXMLDOMDocument3_createNode(iface, type, NULL, NULL, &node);
1742 if (hr == S_OK)
1744 IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMCDATASection, (void**)cdata);
1745 IXMLDOMNode_Release(node);
1746 hr = IXMLDOMCDATASection_put_data(*cdata, data);
1749 return hr;
1753 static HRESULT WINAPI domdoc_createProcessingInstruction(
1754 IXMLDOMDocument3 *iface,
1755 BSTR target,
1756 BSTR data,
1757 IXMLDOMProcessingInstruction** pi )
1759 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1760 IXMLDOMNode *node;
1761 VARIANT type;
1762 HRESULT hr;
1764 TRACE("(%p)->(%s %s %p)\n", This, debugstr_w(target), debugstr_w(data), pi);
1766 if (!pi) return E_INVALIDARG;
1768 *pi = NULL;
1770 V_VT(&type) = VT_I1;
1771 V_I1(&type) = NODE_PROCESSING_INSTRUCTION;
1773 hr = IXMLDOMDocument3_createNode(iface, type, target, NULL, &node);
1774 if (hr == S_OK)
1776 xmlnode *node_obj;
1778 /* this is to bypass check in ::put_data() that blocks "<?xml" PIs */
1779 node_obj = get_node_obj(node);
1780 hr = node_set_content(node_obj, data);
1782 IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMProcessingInstruction, (void**)pi);
1783 IXMLDOMNode_Release(node);
1786 return hr;
1790 static HRESULT WINAPI domdoc_createAttribute(
1791 IXMLDOMDocument3 *iface,
1792 BSTR name,
1793 IXMLDOMAttribute** attribute )
1795 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1796 IXMLDOMNode *node;
1797 VARIANT type;
1798 HRESULT hr;
1800 TRACE("(%p)->(%s %p)\n", This, debugstr_w(name), attribute);
1802 if (!attribute || !name) return E_INVALIDARG;
1804 V_VT(&type) = VT_I1;
1805 V_I1(&type) = NODE_ATTRIBUTE;
1807 hr = IXMLDOMDocument3_createNode(iface, type, name, NULL, &node);
1808 if (hr == S_OK)
1810 IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMAttribute, (void**)attribute);
1811 IXMLDOMNode_Release(node);
1814 return hr;
1818 static HRESULT WINAPI domdoc_createEntityReference(
1819 IXMLDOMDocument3 *iface,
1820 BSTR name,
1821 IXMLDOMEntityReference** entityref )
1823 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1824 IXMLDOMNode *node;
1825 VARIANT type;
1826 HRESULT hr;
1828 TRACE("(%p)->(%s %p)\n", This, debugstr_w(name), entityref);
1830 if (!entityref) return E_INVALIDARG;
1832 *entityref = NULL;
1834 V_VT(&type) = VT_I1;
1835 V_I1(&type) = NODE_ENTITY_REFERENCE;
1837 hr = IXMLDOMDocument3_createNode(iface, type, name, NULL, &node);
1838 if (hr == S_OK)
1840 IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMEntityReference, (void**)entityref);
1841 IXMLDOMNode_Release(node);
1844 return hr;
1847 xmlChar* tagName_to_XPath(const BSTR tagName)
1849 xmlChar *query, *tmp;
1850 static const xmlChar mod_pre[] = "*[local-name()='";
1851 static const xmlChar mod_post[] = "']";
1852 static const xmlChar prefix[] = "descendant::";
1853 const WCHAR *tokBegin, *tokEnd;
1854 int len;
1856 query = xmlStrdup(prefix);
1858 tokBegin = tagName;
1859 while (tokBegin && *tokBegin)
1861 switch (*tokBegin)
1863 case '/':
1864 query = xmlStrcat(query, BAD_CAST "/");
1865 ++tokBegin;
1866 break;
1867 case '*':
1868 query = xmlStrcat(query, BAD_CAST "*");
1869 ++tokBegin;
1870 break;
1871 default:
1872 query = xmlStrcat(query, mod_pre);
1873 tokEnd = tokBegin;
1874 while (*tokEnd && *tokEnd != '/')
1875 ++tokEnd;
1876 len = WideCharToMultiByte(CP_UTF8, 0, tokBegin, tokEnd-tokBegin, NULL, 0, NULL, NULL);
1877 tmp = xmlMalloc(len);
1878 WideCharToMultiByte(CP_UTF8, 0, tokBegin, tokEnd-tokBegin, (char*)tmp, len, NULL, NULL);
1879 query = xmlStrncat(query, tmp, len);
1880 xmlFree(tmp);
1881 tokBegin = tokEnd;
1882 query = xmlStrcat(query, mod_post);
1886 return query;
1889 static HRESULT WINAPI domdoc_getElementsByTagName(
1890 IXMLDOMDocument3 *iface,
1891 BSTR tagName,
1892 IXMLDOMNodeList** resultList )
1894 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1895 xmlChar *query;
1896 HRESULT hr;
1897 BOOL XPath;
1899 TRACE("(%p)->(%s, %p)\n", This, debugstr_w(tagName), resultList);
1901 if (!tagName || !resultList) return E_INVALIDARG;
1903 XPath = This->properties->XPath;
1904 This->properties->XPath = TRUE;
1905 query = tagName_to_XPath(tagName);
1906 hr = create_selection((xmlNodePtr)get_doc(This), query, resultList);
1907 xmlFree(query);
1908 This->properties->XPath = XPath;
1910 return hr;
1913 static HRESULT get_node_type(VARIANT Type, DOMNodeType * type)
1915 VARIANT tmp;
1916 HRESULT hr;
1918 VariantInit(&tmp);
1919 hr = VariantChangeType(&tmp, &Type, 0, VT_I4);
1920 if(FAILED(hr))
1921 return E_INVALIDARG;
1923 *type = V_I4(&tmp);
1925 return S_OK;
1928 static HRESULT WINAPI domdoc_createNode(
1929 IXMLDOMDocument3 *iface,
1930 VARIANT Type,
1931 BSTR name,
1932 BSTR namespaceURI,
1933 IXMLDOMNode** node )
1935 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1936 DOMNodeType node_type;
1937 xmlNodePtr xmlnode;
1938 xmlChar *xml_name, *href;
1939 HRESULT hr;
1941 TRACE("(%p)->(%s %s %p)\n", This, debugstr_w(name), debugstr_w(namespaceURI), node);
1943 if(!node) return E_INVALIDARG;
1945 hr = get_node_type(Type, &node_type);
1946 if(FAILED(hr)) return hr;
1948 if(namespaceURI && namespaceURI[0] && node_type != NODE_ELEMENT)
1949 FIXME("nodes with namespaces currently not supported.\n");
1951 TRACE("node_type %d\n", node_type);
1953 /* exit earlier for types that need name */
1954 switch(node_type)
1956 case NODE_ELEMENT:
1957 case NODE_ATTRIBUTE:
1958 case NODE_ENTITY_REFERENCE:
1959 case NODE_PROCESSING_INSTRUCTION:
1960 if (!name || *name == 0) return E_FAIL;
1961 default:
1962 break;
1965 xml_name = xmlchar_from_wchar(name);
1966 /* prevent empty href to be allocated */
1967 href = namespaceURI ? xmlchar_from_wchar(namespaceURI) : NULL;
1969 switch(node_type)
1971 case NODE_ELEMENT:
1973 xmlChar *local, *prefix;
1975 local = xmlSplitQName2(xml_name, &prefix);
1977 xmlnode = xmlNewDocNode(get_doc(This), NULL, local ? local : xml_name, NULL);
1979 /* allow to create default namespace xmlns= */
1980 if (local || (href && *href))
1982 xmlNsPtr ns = xmlNewNs(xmlnode, href, prefix);
1983 xmlSetNs(xmlnode, ns);
1986 xmlFree(local);
1987 xmlFree(prefix);
1989 break;
1991 case NODE_ATTRIBUTE:
1992 xmlnode = (xmlNodePtr)xmlNewDocProp(get_doc(This), xml_name, NULL);
1993 break;
1994 case NODE_TEXT:
1995 xmlnode = (xmlNodePtr)xmlNewDocText(get_doc(This), NULL);
1996 break;
1997 case NODE_CDATA_SECTION:
1998 xmlnode = xmlNewCDataBlock(get_doc(This), NULL, 0);
1999 break;
2000 case NODE_ENTITY_REFERENCE:
2001 xmlnode = xmlNewReference(get_doc(This), xml_name);
2002 break;
2003 case NODE_PROCESSING_INSTRUCTION:
2004 #ifdef HAVE_XMLNEWDOCPI
2005 xmlnode = xmlNewDocPI(get_doc(This), xml_name, NULL);
2006 #else
2007 FIXME("xmlNewDocPI() not supported, use libxml2 2.6.15 or greater\n");
2008 xmlnode = NULL;
2009 #endif
2010 break;
2011 case NODE_COMMENT:
2012 xmlnode = xmlNewDocComment(get_doc(This), NULL);
2013 break;
2014 case NODE_DOCUMENT_FRAGMENT:
2015 xmlnode = xmlNewDocFragment(get_doc(This));
2016 break;
2017 /* unsupported types */
2018 case NODE_DOCUMENT:
2019 case NODE_DOCUMENT_TYPE:
2020 case NODE_ENTITY:
2021 case NODE_NOTATION:
2022 heap_free(xml_name);
2023 return E_INVALIDARG;
2024 default:
2025 FIXME("unhandled node type %d\n", node_type);
2026 xmlnode = NULL;
2027 break;
2030 *node = create_node(xmlnode);
2031 heap_free(xml_name);
2032 heap_free(href);
2034 if(*node)
2036 TRACE("created node (%d, %p, %p)\n", node_type, *node, xmlnode);
2037 xmldoc_add_orphan(xmlnode->doc, xmlnode);
2038 return S_OK;
2041 return E_FAIL;
2044 static HRESULT WINAPI domdoc_nodeFromID(
2045 IXMLDOMDocument3 *iface,
2046 BSTR idString,
2047 IXMLDOMNode** node )
2049 domdoc *This = impl_from_IXMLDOMDocument3(iface);
2050 FIXME("(%p)->(%s %p)\n", This, debugstr_w(idString), node);
2051 return E_NOTIMPL;
2054 static HRESULT domdoc_onDataAvailable(void *obj, char *ptr, DWORD len)
2056 domdoc *This = obj;
2057 xmlDocPtr xmldoc;
2059 xmldoc = doparse(This, ptr, len, XML_CHAR_ENCODING_NONE);
2060 if(xmldoc) {
2061 xmldoc->_private = create_priv();
2062 return attach_xmldoc(This, xmldoc);
2065 return S_OK;
2068 static HRESULT doread( domdoc *This, LPWSTR filename )
2070 bsc_t *bsc;
2071 HRESULT hr;
2073 hr = bind_url(filename, domdoc_onDataAvailable, This, &bsc);
2074 if(FAILED(hr))
2075 return hr;
2077 if(This->bsc)
2078 detach_bsc(This->bsc);
2080 This->bsc = bsc;
2081 return S_OK;
2084 static HRESULT WINAPI domdoc_load(
2085 IXMLDOMDocument3 *iface,
2086 VARIANT source,
2087 VARIANT_BOOL* isSuccessful )
2089 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2090 LPWSTR filename = NULL;
2091 HRESULT hr = S_FALSE;
2092 IXMLDOMDocument3 *pNewDoc = NULL;
2093 IStream *pStream = NULL;
2094 xmlDocPtr xmldoc;
2096 TRACE("(%p)->(%s)\n", This, debugstr_variant(&source));
2098 if (!isSuccessful)
2099 return E_POINTER;
2100 *isSuccessful = VARIANT_FALSE;
2102 assert( &This->node );
2104 switch( V_VT(&source) )
2106 case VT_BSTR:
2107 filename = V_BSTR(&source);
2108 break;
2109 case VT_BSTR|VT_BYREF:
2110 if (!V_BSTRREF(&source)) return E_INVALIDARG;
2111 filename = *V_BSTRREF(&source);
2112 break;
2113 case VT_ARRAY|VT_UI1:
2115 SAFEARRAY *psa = V_ARRAY(&source);
2116 char *str;
2117 LONG len;
2118 UINT dim = SafeArrayGetDim(psa);
2120 switch (dim)
2122 case 0:
2123 ERR("SAFEARRAY == NULL\n");
2124 hr = This->error = E_INVALIDARG;
2125 break;
2126 case 1:
2127 /* Only takes UTF-8 strings.
2128 * NOT NULL-terminated. */
2129 SafeArrayAccessData(psa, (void**)&str);
2130 SafeArrayGetUBound(psa, 1, &len);
2132 if ((xmldoc = doparse(This, str, ++len, XML_CHAR_ENCODING_UTF8)))
2134 hr = This->error = S_OK;
2135 *isSuccessful = VARIANT_TRUE;
2136 TRACE("parsed document %p\n", xmldoc);
2138 else
2140 This->error = E_FAIL;
2141 TRACE("failed to parse document\n");
2144 SafeArrayUnaccessData(psa);
2146 if(xmldoc)
2148 xmldoc->_private = create_priv();
2149 return attach_xmldoc(This, xmldoc);
2151 break;
2152 default:
2153 FIXME("unhandled SAFEARRAY dim: %d\n", dim);
2154 hr = This->error = E_NOTIMPL;
2157 break;
2158 case VT_UNKNOWN:
2159 hr = IUnknown_QueryInterface(V_UNKNOWN(&source), &IID_IXMLDOMDocument3, (void**)&pNewDoc);
2160 if(hr == S_OK)
2162 if(pNewDoc)
2164 domdoc *newDoc = impl_from_IXMLDOMDocument3( pNewDoc );
2165 xmldoc = xmlCopyDoc(get_doc(newDoc), 1);
2166 hr = attach_xmldoc(This, xmldoc);
2168 if(SUCCEEDED(hr))
2169 *isSuccessful = VARIANT_TRUE;
2171 return hr;
2174 hr = IUnknown_QueryInterface(V_UNKNOWN(&source), &IID_IStream, (void**)&pStream);
2175 if(hr == S_OK)
2177 IPersistStream *pDocStream;
2178 hr = IUnknown_QueryInterface(iface, &IID_IPersistStream, (void**)&pDocStream);
2179 if(hr == S_OK)
2181 hr = IPersistStream_Load(pDocStream, pStream);
2182 IStream_Release(pStream);
2183 if(hr == S_OK)
2185 *isSuccessful = VARIANT_TRUE;
2187 TRACE("Using IStream to load Document\n");
2188 return S_OK;
2190 else
2192 ERR("xmldoc_IPersistStream_Load failed (%d)\n", hr);
2195 else
2197 ERR("QueryInterface IID_IPersistStream failed (%d)\n", hr);
2200 else
2202 /* ISequentialStream */
2203 FIXME("Unknown type not supported (%d) (%p)(%p)\n", hr, pNewDoc, V_UNKNOWN(&source)->lpVtbl);
2205 break;
2206 default:
2207 FIXME("VT type not supported (%d)\n", V_VT(&source));
2210 if ( filename )
2212 hr = doread( This, filename );
2214 if ( FAILED(hr) )
2215 This->error = E_FAIL;
2216 else
2218 hr = This->error = S_OK;
2219 *isSuccessful = VARIANT_TRUE;
2223 if(!filename || FAILED(hr)) {
2224 xmldoc = xmlNewDoc(NULL);
2225 xmldoc->_private = create_priv();
2226 hr = attach_xmldoc(This, xmldoc);
2227 if(SUCCEEDED(hr))
2228 hr = S_FALSE;
2231 TRACE("ret (%d)\n", hr);
2233 return hr;
2237 static HRESULT WINAPI domdoc_get_readyState(
2238 IXMLDOMDocument3 *iface,
2239 LONG *value )
2241 domdoc *This = impl_from_IXMLDOMDocument3(iface);
2242 FIXME("stub! (%p)->(%p)\n", This, value);
2244 if (!value)
2245 return E_INVALIDARG;
2247 *value = READYSTATE_COMPLETE;
2248 return S_OK;
2252 static HRESULT WINAPI domdoc_get_parseError(
2253 IXMLDOMDocument3 *iface,
2254 IXMLDOMParseError** errorObj )
2256 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2257 static const WCHAR err[] = {'e','r','r','o','r',0};
2258 BSTR error_string = NULL;
2260 FIXME("(%p)->(%p): creating a dummy parseError\n", iface, errorObj);
2262 if(This->error)
2263 error_string = SysAllocString(err);
2265 *errorObj = create_parseError(This->error, NULL, error_string, NULL, 0, 0, 0);
2266 if(!*errorObj) return E_OUTOFMEMORY;
2267 return S_OK;
2271 static HRESULT WINAPI domdoc_get_url(
2272 IXMLDOMDocument3 *iface,
2273 BSTR* urlString )
2275 domdoc *This = impl_from_IXMLDOMDocument3(iface);
2276 FIXME("(%p)->(%p)\n", This, urlString);
2277 return E_NOTIMPL;
2281 static HRESULT WINAPI domdoc_get_async(
2282 IXMLDOMDocument3 *iface,
2283 VARIANT_BOOL* isAsync )
2285 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2287 TRACE("(%p)->(%p: %d)\n", This, isAsync, This->async);
2288 *isAsync = This->async;
2289 return S_OK;
2293 static HRESULT WINAPI domdoc_put_async(
2294 IXMLDOMDocument3 *iface,
2295 VARIANT_BOOL isAsync )
2297 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2299 TRACE("(%p)->(%d)\n", This, isAsync);
2300 This->async = isAsync;
2301 return S_OK;
2305 static HRESULT WINAPI domdoc_abort(
2306 IXMLDOMDocument3 *iface )
2308 domdoc *This = impl_from_IXMLDOMDocument3(iface);
2309 FIXME("%p\n", This);
2310 return E_NOTIMPL;
2314 /* don't rely on data to be in BSTR format, treat it as WCHAR string */
2315 static HRESULT WINAPI domdoc_loadXML(
2316 IXMLDOMDocument3 *iface,
2317 BSTR bstrXML,
2318 VARIANT_BOOL* isSuccessful )
2320 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2321 xmlDocPtr xmldoc = NULL;
2322 HRESULT hr = S_FALSE, hr2;
2324 TRACE("(%p)->(%s %p)\n", This, debugstr_w( bstrXML ), isSuccessful );
2326 assert ( &This->node );
2328 if ( isSuccessful )
2330 *isSuccessful = VARIANT_FALSE;
2332 if ( bstrXML )
2334 xmldoc = doparse(This, (LPCSTR)bstrXML, lstrlenW(bstrXML) * sizeof(*bstrXML), XML_CHAR_ENCODING_UTF16LE);
2335 if ( !xmldoc )
2337 This->error = E_FAIL;
2338 TRACE("failed to parse document\n");
2340 else
2342 hr = This->error = S_OK;
2343 *isSuccessful = VARIANT_TRUE;
2344 TRACE("parsed document %p\n", xmldoc);
2348 if(!xmldoc)
2349 xmldoc = xmlNewDoc(NULL);
2351 xmldoc->_private = create_priv();
2353 hr2 = attach_xmldoc(This, xmldoc);
2354 if( FAILED(hr2) )
2355 hr = hr2;
2357 return hr;
2360 static int XMLCALL domdoc_save_writecallback(void *ctx, const char *buffer, int len)
2362 DWORD written = -1;
2364 if(!WriteFile(ctx, buffer, len, &written, NULL))
2366 WARN("write error\n");
2367 return -1;
2369 else
2370 return written;
2373 static int XMLCALL domdoc_save_closecallback(void *ctx)
2375 return CloseHandle(ctx) ? 0 : -1;
2378 static int XMLCALL domdoc_stream_save_writecallback(void *ctx, const char *buffer, int len)
2380 ULONG written = 0;
2381 HRESULT hr;
2383 hr = IStream_Write((IStream*)ctx, buffer, len, &written);
2384 if (hr != S_OK)
2386 WARN("stream write error: 0x%08x\n", hr);
2387 return -1;
2389 else
2390 return written;
2393 static int XMLCALL domdoc_stream_save_closecallback(void *ctx)
2395 IStream_Release((IStream*)ctx);
2396 return 0;
2399 static HRESULT WINAPI domdoc_save(
2400 IXMLDOMDocument3 *iface,
2401 VARIANT destination )
2403 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2404 xmlSaveCtxtPtr ctx = NULL;
2405 xmlNodePtr xmldecl;
2406 HRESULT ret = S_OK;
2408 TRACE("(%p)->(%s)\n", This, debugstr_variant(&destination));
2410 switch (V_VT(&destination))
2412 case VT_UNKNOWN:
2414 IUnknown *pUnk = V_UNKNOWN(&destination);
2415 IXMLDOMDocument2 *document;
2416 IStream *stream;
2418 ret = IUnknown_QueryInterface(pUnk, &IID_IXMLDOMDocument3, (void**)&document);
2419 if(ret == S_OK)
2421 VARIANT_BOOL success;
2422 BSTR xml;
2424 ret = IXMLDOMDocument3_get_xml(iface, &xml);
2425 if(ret == S_OK)
2427 ret = IXMLDOMDocument3_loadXML(document, xml, &success);
2428 SysFreeString(xml);
2431 IXMLDOMDocument3_Release(document);
2432 return ret;
2435 ret = IUnknown_QueryInterface(pUnk, &IID_IStream, (void**)&stream);
2436 if(ret == S_OK)
2438 ctx = xmlSaveToIO(domdoc_stream_save_writecallback,
2439 domdoc_stream_save_closecallback, stream, NULL, XML_SAVE_NO_DECL);
2441 if(!ctx)
2443 IStream_Release(stream);
2444 return E_FAIL;
2448 break;
2450 case VT_BSTR:
2451 case VT_BSTR | VT_BYREF:
2453 /* save with file path */
2454 HANDLE handle = CreateFileW( (V_VT(&destination) & VT_BYREF)? *V_BSTRREF(&destination) : V_BSTR(&destination),
2455 GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL );
2456 if( handle == INVALID_HANDLE_VALUE )
2458 WARN("failed to create file\n");
2459 return E_FAIL;
2462 /* disable top XML declaration */
2463 ctx = xmlSaveToIO(domdoc_save_writecallback, domdoc_save_closecallback,
2464 handle, NULL, XML_SAVE_NO_DECL);
2465 if (!ctx)
2467 CloseHandle(handle);
2468 return E_FAIL;
2471 break;
2473 default:
2474 FIXME("Unhandled VARIANT: %s\n", debugstr_variant(&destination));
2475 return S_FALSE;
2478 xmldecl = xmldoc_unlink_xmldecl(get_doc(This));
2479 if (xmlSaveDoc(ctx, get_doc(This)) == -1) ret = S_FALSE;
2480 xmldoc_link_xmldecl(get_doc(This), xmldecl);
2482 /* will release resources through close callback */
2483 xmlSaveClose(ctx);
2485 return ret;
2488 static HRESULT WINAPI domdoc_get_validateOnParse(
2489 IXMLDOMDocument3 *iface,
2490 VARIANT_BOOL* isValidating )
2492 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2493 TRACE("(%p)->(%p: %d)\n", This, isValidating, This->validating);
2494 *isValidating = This->validating;
2495 return S_OK;
2499 static HRESULT WINAPI domdoc_put_validateOnParse(
2500 IXMLDOMDocument3 *iface,
2501 VARIANT_BOOL isValidating )
2503 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2504 TRACE("(%p)->(%d)\n", This, isValidating);
2505 This->validating = isValidating;
2506 return S_OK;
2510 static HRESULT WINAPI domdoc_get_resolveExternals(
2511 IXMLDOMDocument3 *iface,
2512 VARIANT_BOOL* isResolving )
2514 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2515 TRACE("(%p)->(%p: %d)\n", This, isResolving, This->resolving);
2516 *isResolving = This->resolving;
2517 return S_OK;
2521 static HRESULT WINAPI domdoc_put_resolveExternals(
2522 IXMLDOMDocument3 *iface,
2523 VARIANT_BOOL isResolving )
2525 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2526 TRACE("(%p)->(%d)\n", This, isResolving);
2527 This->resolving = isResolving;
2528 return S_OK;
2532 static HRESULT WINAPI domdoc_get_preserveWhiteSpace(
2533 IXMLDOMDocument3 *iface,
2534 VARIANT_BOOL* isPreserving )
2536 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2537 TRACE("(%p)->(%p: %d)\n", This, isPreserving, This->properties->preserving);
2538 *isPreserving = This->properties->preserving;
2539 return S_OK;
2543 static HRESULT WINAPI domdoc_put_preserveWhiteSpace(
2544 IXMLDOMDocument3 *iface,
2545 VARIANT_BOOL isPreserving )
2547 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2548 TRACE("(%p)->(%d)\n", This, isPreserving);
2549 This->properties->preserving = isPreserving;
2550 return S_OK;
2554 static HRESULT WINAPI domdoc_put_onreadystatechange(
2555 IXMLDOMDocument3 *iface,
2556 VARIANT event )
2558 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2560 TRACE("(%p)->(%s)\n", This, debugstr_variant(&event));
2561 return set_doc_event(This, EVENTID_READYSTATECHANGE, &event);
2565 static HRESULT WINAPI domdoc_put_onDataAvailable(
2566 IXMLDOMDocument3 *iface,
2567 VARIANT onDataAvailableSink )
2569 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2570 FIXME("%p\n", This);
2571 return E_NOTIMPL;
2574 static HRESULT WINAPI domdoc_put_onTransformNode(
2575 IXMLDOMDocument3 *iface,
2576 VARIANT onTransformNodeSink )
2578 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2579 FIXME("%p\n", This);
2580 return E_NOTIMPL;
2583 static HRESULT WINAPI domdoc_get_namespaces(
2584 IXMLDOMDocument3* iface,
2585 IXMLDOMSchemaCollection** schemaCollection )
2587 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2588 FIXME("(%p)->(%p)\n", This, schemaCollection);
2589 return E_NOTIMPL;
2592 static HRESULT WINAPI domdoc_get_schemas(
2593 IXMLDOMDocument3* iface,
2594 VARIANT* var1 )
2596 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2597 HRESULT hr = S_FALSE;
2598 IXMLDOMSchemaCollection2* cur_schema = This->properties->schemaCache;
2600 TRACE("(%p)->(%p)\n", This, var1);
2602 VariantInit(var1); /* Test shows we don't call VariantClear here */
2603 V_VT(var1) = VT_NULL;
2605 if(cur_schema)
2607 hr = IXMLDOMSchemaCollection2_QueryInterface(cur_schema, &IID_IDispatch, (void**)&V_DISPATCH(var1));
2608 if(SUCCEEDED(hr))
2609 V_VT(var1) = VT_DISPATCH;
2611 return hr;
2614 static HRESULT WINAPI domdoc_putref_schemas(
2615 IXMLDOMDocument3* iface,
2616 VARIANT var1)
2618 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2619 HRESULT hr = E_FAIL;
2620 IXMLDOMSchemaCollection2* new_schema = NULL;
2622 FIXME("(%p): semi-stub\n", This);
2623 switch(V_VT(&var1))
2625 case VT_UNKNOWN:
2626 hr = IUnknown_QueryInterface(V_UNKNOWN(&var1), &IID_IXMLDOMSchemaCollection, (void**)&new_schema);
2627 break;
2629 case VT_DISPATCH:
2630 hr = IDispatch_QueryInterface(V_DISPATCH(&var1), &IID_IXMLDOMSchemaCollection, (void**)&new_schema);
2631 break;
2633 case VT_NULL:
2634 case VT_EMPTY:
2635 hr = S_OK;
2636 break;
2638 default:
2639 WARN("Can't get schema from vt %x\n", V_VT(&var1));
2642 if(SUCCEEDED(hr))
2644 IXMLDOMSchemaCollection2* old_schema = InterlockedExchangePointer((void**)&This->properties->schemaCache, new_schema);
2645 if(old_schema) IXMLDOMSchemaCollection2_Release(old_schema);
2648 return hr;
2651 static inline BOOL is_wellformed(xmlDocPtr doc)
2653 #ifdef HAVE_XMLDOC_PROPERTIES
2654 return doc->properties & XML_DOC_WELLFORMED;
2655 #else
2656 /* Not a full check, but catches the worst violations */
2657 xmlNodePtr child;
2658 int root = 0;
2660 for (child = doc->children; child != NULL; child = child->next)
2662 switch (child->type)
2664 case XML_ELEMENT_NODE:
2665 if (++root > 1)
2666 return FALSE;
2667 break;
2668 case XML_TEXT_NODE:
2669 case XML_CDATA_SECTION_NODE:
2670 return FALSE;
2671 break;
2672 default:
2673 break;
2677 return root == 1;
2678 #endif
2681 static void LIBXML2_LOG_CALLBACK validate_error(void* ctx, char const* msg, ...)
2683 va_list ap;
2684 va_start(ap, msg);
2685 LIBXML2_CALLBACK_ERR(domdoc_validateNode, msg, ap);
2686 va_end(ap);
2689 static void LIBXML2_LOG_CALLBACK validate_warning(void* ctx, char const* msg, ...)
2691 va_list ap;
2692 va_start(ap, msg);
2693 LIBXML2_CALLBACK_WARN(domdoc_validateNode, msg, ap);
2694 va_end(ap);
2697 static HRESULT WINAPI domdoc_validateNode(
2698 IXMLDOMDocument3* iface,
2699 IXMLDOMNode* node,
2700 IXMLDOMParseError** err)
2702 domdoc* This = impl_from_IXMLDOMDocument3(iface);
2703 LONG state, err_code = 0;
2704 HRESULT hr = S_OK;
2705 int validated = 0;
2707 TRACE("(%p)->(%p, %p)\n", This, node, err);
2708 domdoc_get_readyState(iface, &state);
2709 if (state != READYSTATE_COMPLETE)
2711 if (err)
2712 *err = create_parseError(err_code, NULL, NULL, NULL, 0, 0, 0);
2713 return E_PENDING;
2716 if (!node)
2718 if (err)
2719 *err = create_parseError(err_code, NULL, NULL, NULL, 0, 0, 0);
2720 return E_POINTER;
2723 if (!get_node_obj(node)->node || get_node_obj(node)->node->doc != get_doc(This))
2725 if (err)
2726 *err = create_parseError(err_code, NULL, NULL, NULL, 0, 0, 0);
2727 return E_FAIL;
2730 if (!is_wellformed(get_doc(This)))
2732 ERR("doc not well-formed\n");
2733 if (err)
2734 *err = create_parseError(E_XML_NOTWF, NULL, NULL, NULL, 0, 0, 0);
2735 return S_FALSE;
2738 /* DTD validation */
2739 if (get_doc(This)->intSubset || get_doc(This)->extSubset)
2741 xmlValidCtxtPtr vctx = xmlNewValidCtxt();
2742 vctx->error = validate_error;
2743 vctx->warning = validate_warning;
2744 ++validated;
2746 if (!((node == (IXMLDOMNode*)iface)?
2747 xmlValidateDocument(vctx, get_doc(This)) :
2748 xmlValidateElement(vctx, get_doc(This), get_node_obj(node)->node)))
2750 /* TODO: get a real error code here */
2751 TRACE("DTD validation failed\n");
2752 err_code = E_XML_INVALID;
2753 hr = S_FALSE;
2755 xmlFreeValidCtxt(vctx);
2758 /* Schema validation */
2759 if (hr == S_OK && This->properties->schemaCache != NULL)
2762 hr = SchemaCache_validate_tree(This->properties->schemaCache, get_node_obj(node)->node);
2763 if (!FAILED(hr))
2765 ++validated;
2766 /* TODO: get a real error code here */
2767 if (hr == S_OK)
2769 TRACE("schema validation succeeded\n");
2771 else
2773 ERR("schema validation failed\n");
2774 err_code = E_XML_INVALID;
2777 else
2779 /* not really OK, just didn't find a schema for the ns */
2780 hr = S_OK;
2784 if (!validated)
2786 ERR("no DTD or schema found\n");
2787 err_code = E_XML_NODTD;
2788 hr = S_FALSE;
2791 if (err)
2792 *err = create_parseError(err_code, NULL, NULL, NULL, 0, 0, 0);
2794 return hr;
2797 static HRESULT WINAPI domdoc_validate(
2798 IXMLDOMDocument3* iface,
2799 IXMLDOMParseError** err)
2801 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2802 TRACE("(%p)->(%p)\n", This, err);
2803 return domdoc_validateNode(iface, (IXMLDOMNode*)iface, err);
2806 static HRESULT WINAPI domdoc_setProperty(
2807 IXMLDOMDocument3* iface,
2808 BSTR p,
2809 VARIANT var)
2811 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2813 TRACE("(%p)->(%s)\n", This, debugstr_w(p));
2815 if (lstrcmpiW(p, PropertySelectionLanguageW) == 0)
2817 VARIANT varStr;
2818 HRESULT hr;
2819 BSTR bstr;
2821 V_VT(&varStr) = VT_EMPTY;
2822 if (V_VT(&var) != VT_BSTR)
2824 if (FAILED(hr = VariantChangeType(&varStr, &var, 0, VT_BSTR)))
2825 return hr;
2826 bstr = V_BSTR(&varStr);
2828 else
2829 bstr = V_BSTR(&var);
2831 hr = S_OK;
2832 if (lstrcmpiW(bstr, PropValueXPathW) == 0)
2833 This->properties->XPath = TRUE;
2834 else if (lstrcmpiW(bstr, PropValueXSLPatternW) == 0)
2835 This->properties->XPath = FALSE;
2836 else
2837 hr = E_FAIL;
2839 VariantClear(&varStr);
2840 return hr;
2842 else if (lstrcmpiW(p, PropertySelectionNamespacesW) == 0)
2844 VARIANT varStr;
2845 HRESULT hr;
2846 BSTR bstr;
2847 xmlChar *pTokBegin, *pTokEnd, *pTokInner;
2848 xmlChar *nsStr = (xmlChar*)This->properties->selectNsStr;
2849 xmlXPathContextPtr ctx;
2850 struct list *pNsList;
2851 select_ns_entry* pNsEntry = NULL;
2853 V_VT(&varStr) = VT_EMPTY;
2854 if (V_VT(&var) != VT_BSTR)
2856 if (FAILED(hr = VariantChangeType(&varStr, &var, 0, VT_BSTR)))
2857 return hr;
2858 bstr = V_BSTR(&varStr);
2860 else
2861 bstr = V_BSTR(&var);
2863 hr = S_OK;
2865 pNsList = &(This->properties->selectNsList);
2866 clear_selectNsList(pNsList);
2867 heap_free(nsStr);
2868 nsStr = xmlchar_from_wchar(bstr);
2870 TRACE("Setting SelectionNamespaces property to: %s\n", nsStr);
2872 This->properties->selectNsStr = nsStr;
2873 This->properties->selectNsStr_len = xmlStrlen(nsStr);
2874 if (bstr && *bstr)
2876 ctx = xmlXPathNewContext(This->node.node->doc);
2877 pTokBegin = nsStr;
2878 for (; *pTokBegin; pTokBegin = pTokEnd)
2880 if (pNsEntry != NULL)
2881 memset(pNsEntry, 0, sizeof(select_ns_entry));
2882 else
2883 pNsEntry = heap_alloc_zero(sizeof(select_ns_entry));
2885 while (*pTokBegin == ' ')
2886 ++pTokBegin;
2887 pTokEnd = pTokBegin;
2888 while (*pTokEnd != ' ' && *pTokEnd != 0)
2889 ++pTokEnd;
2891 if (xmlStrncmp(pTokBegin, (xmlChar const*)"xmlns", 5) != 0)
2893 hr = E_FAIL;
2894 WARN("Syntax error in xmlns string: %s\n\tat token: %s\n",
2895 wine_dbgstr_w(bstr), wine_dbgstr_an((const char*)pTokBegin, pTokEnd-pTokBegin));
2896 continue;
2899 pTokBegin += 5;
2900 if (*pTokBegin == '=')
2902 /*valid for XSLPattern?*/
2903 FIXME("Setting default xmlns not supported - skipping.\n");
2904 continue;
2906 else if (*pTokBegin == ':')
2908 pNsEntry->prefix = ++pTokBegin;
2909 for (pTokInner = pTokBegin; pTokInner != pTokEnd && *pTokInner != '='; ++pTokInner)
2912 if (pTokInner == pTokEnd)
2914 hr = E_FAIL;
2915 WARN("Syntax error in xmlns string: %s\n\tat token: %s\n",
2916 wine_dbgstr_w(bstr), wine_dbgstr_an((const char*)pTokBegin, pTokEnd-pTokBegin));
2917 continue;
2920 pNsEntry->prefix_end = *pTokInner;
2921 *pTokInner = 0;
2922 ++pTokInner;
2924 if (pTokEnd-pTokInner > 1 &&
2925 ((*pTokInner == '\'' && *(pTokEnd-1) == '\'') ||
2926 (*pTokInner == '"' && *(pTokEnd-1) == '"')))
2928 pNsEntry->href = ++pTokInner;
2929 pNsEntry->href_end = *(pTokEnd-1);
2930 *(pTokEnd-1) = 0;
2931 list_add_tail(pNsList, &pNsEntry->entry);
2932 /*let libxml figure out if they're valid from here ;)*/
2933 if (xmlXPathRegisterNs(ctx, pNsEntry->prefix, pNsEntry->href) != 0)
2935 hr = E_FAIL;
2937 pNsEntry = NULL;
2938 continue;
2940 else
2942 WARN("Syntax error in xmlns string: %s\n\tat token: %s\n",
2943 wine_dbgstr_w(bstr), wine_dbgstr_an((const char*)pTokInner, pTokEnd-pTokInner));
2944 list_add_tail(pNsList, &pNsEntry->entry);
2946 pNsEntry = NULL;
2947 hr = E_FAIL;
2948 continue;
2951 else
2953 hr = E_FAIL;
2954 continue;
2957 heap_free(pNsEntry);
2958 xmlXPathFreeContext(ctx);
2961 VariantClear(&varStr);
2962 return hr;
2964 else if (lstrcmpiW(p, PropertyProhibitDTDW) == 0 ||
2965 lstrcmpiW(p, PropertyNewParserW) == 0 ||
2966 lstrcmpiW(p, PropertyResolveExternalsW) == 0)
2968 /* Ignore */
2969 FIXME("Ignoring property %s, value %d\n", debugstr_w(p), V_BOOL(&var));
2970 return S_OK;
2973 FIXME("Unknown property %s\n", wine_dbgstr_w(p));
2974 return E_FAIL;
2977 static HRESULT WINAPI domdoc_getProperty(
2978 IXMLDOMDocument3* iface,
2979 BSTR p,
2980 VARIANT* var)
2982 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2984 TRACE("(%p)->(%p)\n", This, debugstr_w(p));
2986 if (!var)
2987 return E_INVALIDARG;
2989 if (lstrcmpiW(p, PropertySelectionLanguageW) == 0)
2991 V_VT(var) = VT_BSTR;
2992 V_BSTR(var) = This->properties->XPath ?
2993 SysAllocString(PropValueXPathW) :
2994 SysAllocString(PropValueXSLPatternW);
2995 return V_BSTR(var) ? S_OK : E_OUTOFMEMORY;
2997 else if (lstrcmpiW(p, PropertySelectionNamespacesW) == 0)
2999 int lenA, lenW;
3000 BSTR rebuiltStr, cur;
3001 const xmlChar *nsStr;
3002 struct list *pNsList;
3003 select_ns_entry* pNsEntry;
3005 V_VT(var) = VT_BSTR;
3006 nsStr = This->properties->selectNsStr;
3007 pNsList = &This->properties->selectNsList;
3008 lenA = This->properties->selectNsStr_len;
3009 lenW = MultiByteToWideChar(CP_UTF8, 0, (LPCSTR)nsStr, lenA+1, NULL, 0);
3010 rebuiltStr = heap_alloc(lenW*sizeof(WCHAR));
3011 MultiByteToWideChar(CP_UTF8, 0, (LPCSTR)nsStr, lenA+1, rebuiltStr, lenW);
3012 cur = rebuiltStr;
3013 /* this is fine because all of the chars that end tokens are ASCII*/
3014 LIST_FOR_EACH_ENTRY(pNsEntry, pNsList, select_ns_entry, entry)
3016 while (*cur != 0) ++cur;
3017 if (pNsEntry->prefix_end)
3019 *cur = pNsEntry->prefix_end;
3020 while (*cur != 0) ++cur;
3023 if (pNsEntry->href_end)
3025 *cur = pNsEntry->href_end;
3028 V_BSTR(var) = SysAllocString(rebuiltStr);
3029 heap_free(rebuiltStr);
3030 return S_OK;
3033 FIXME("Unknown property %s\n", wine_dbgstr_w(p));
3034 return E_FAIL;
3037 static HRESULT WINAPI domdoc_importNode(
3038 IXMLDOMDocument3* iface,
3039 IXMLDOMNode* node,
3040 VARIANT_BOOL deep,
3041 IXMLDOMNode** clone)
3043 domdoc *This = impl_from_IXMLDOMDocument3( iface );
3044 FIXME("(%p)->(%p %d %p): stub\n", This, node, deep, clone);
3045 return E_NOTIMPL;
3048 static const struct IXMLDOMDocument3Vtbl domdoc_vtbl =
3050 domdoc_QueryInterface,
3051 domdoc_AddRef,
3052 domdoc_Release,
3053 domdoc_GetTypeInfoCount,
3054 domdoc_GetTypeInfo,
3055 domdoc_GetIDsOfNames,
3056 domdoc_Invoke,
3057 domdoc_get_nodeName,
3058 domdoc_get_nodeValue,
3059 domdoc_put_nodeValue,
3060 domdoc_get_nodeType,
3061 domdoc_get_parentNode,
3062 domdoc_get_childNodes,
3063 domdoc_get_firstChild,
3064 domdoc_get_lastChild,
3065 domdoc_get_previousSibling,
3066 domdoc_get_nextSibling,
3067 domdoc_get_attributes,
3068 domdoc_insertBefore,
3069 domdoc_replaceChild,
3070 domdoc_removeChild,
3071 domdoc_appendChild,
3072 domdoc_hasChildNodes,
3073 domdoc_get_ownerDocument,
3074 domdoc_cloneNode,
3075 domdoc_get_nodeTypeString,
3076 domdoc_get_text,
3077 domdoc_put_text,
3078 domdoc_get_specified,
3079 domdoc_get_definition,
3080 domdoc_get_nodeTypedValue,
3081 domdoc_put_nodeTypedValue,
3082 domdoc_get_dataType,
3083 domdoc_put_dataType,
3084 domdoc_get_xml,
3085 domdoc_transformNode,
3086 domdoc_selectNodes,
3087 domdoc_selectSingleNode,
3088 domdoc_get_parsed,
3089 domdoc_get_namespaceURI,
3090 domdoc_get_prefix,
3091 domdoc_get_baseName,
3092 domdoc_transformNodeToObject,
3093 domdoc_get_doctype,
3094 domdoc_get_implementation,
3095 domdoc_get_documentElement,
3096 domdoc_put_documentElement,
3097 domdoc_createElement,
3098 domdoc_createDocumentFragment,
3099 domdoc_createTextNode,
3100 domdoc_createComment,
3101 domdoc_createCDATASection,
3102 domdoc_createProcessingInstruction,
3103 domdoc_createAttribute,
3104 domdoc_createEntityReference,
3105 domdoc_getElementsByTagName,
3106 domdoc_createNode,
3107 domdoc_nodeFromID,
3108 domdoc_load,
3109 domdoc_get_readyState,
3110 domdoc_get_parseError,
3111 domdoc_get_url,
3112 domdoc_get_async,
3113 domdoc_put_async,
3114 domdoc_abort,
3115 domdoc_loadXML,
3116 domdoc_save,
3117 domdoc_get_validateOnParse,
3118 domdoc_put_validateOnParse,
3119 domdoc_get_resolveExternals,
3120 domdoc_put_resolveExternals,
3121 domdoc_get_preserveWhiteSpace,
3122 domdoc_put_preserveWhiteSpace,
3123 domdoc_put_onreadystatechange,
3124 domdoc_put_onDataAvailable,
3125 domdoc_put_onTransformNode,
3126 domdoc_get_namespaces,
3127 domdoc_get_schemas,
3128 domdoc_putref_schemas,
3129 domdoc_validate,
3130 domdoc_setProperty,
3131 domdoc_getProperty,
3132 domdoc_validateNode,
3133 domdoc_importNode
3136 /* IConnectionPointContainer */
3137 static HRESULT WINAPI ConnectionPointContainer_QueryInterface(IConnectionPointContainer *iface,
3138 REFIID riid, void **ppv)
3140 domdoc *This = impl_from_IConnectionPointContainer(iface);
3141 return IXMLDOMDocument3_QueryInterface(&This->IXMLDOMDocument3_iface, riid, ppv);
3144 static ULONG WINAPI ConnectionPointContainer_AddRef(IConnectionPointContainer *iface)
3146 domdoc *This = impl_from_IConnectionPointContainer(iface);
3147 return IXMLDOMDocument3_AddRef(&This->IXMLDOMDocument3_iface);
3150 static ULONG WINAPI ConnectionPointContainer_Release(IConnectionPointContainer *iface)
3152 domdoc *This = impl_from_IConnectionPointContainer(iface);
3153 return IXMLDOMDocument3_Release(&This->IXMLDOMDocument3_iface);
3156 static HRESULT WINAPI ConnectionPointContainer_EnumConnectionPoints(IConnectionPointContainer *iface,
3157 IEnumConnectionPoints **ppEnum)
3159 domdoc *This = impl_from_IConnectionPointContainer(iface);
3160 FIXME("(%p)->(%p): stub\n", This, ppEnum);
3161 return E_NOTIMPL;
3164 static HRESULT WINAPI ConnectionPointContainer_FindConnectionPoint(IConnectionPointContainer *iface,
3165 REFIID riid, IConnectionPoint **cp)
3167 domdoc *This = impl_from_IConnectionPointContainer(iface);
3168 ConnectionPoint *iter;
3170 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), cp);
3172 *cp = NULL;
3174 for(iter = This->cp_list; iter; iter = iter->next)
3176 if (IsEqualGUID(iter->iid, riid))
3177 *cp = &iter->IConnectionPoint_iface;
3180 if (*cp)
3182 IConnectionPoint_AddRef(*cp);
3183 return S_OK;
3186 FIXME("unsupported riid %s\n", debugstr_guid(riid));
3187 return CONNECT_E_NOCONNECTION;
3191 static const struct IConnectionPointContainerVtbl ConnectionPointContainerVtbl =
3193 ConnectionPointContainer_QueryInterface,
3194 ConnectionPointContainer_AddRef,
3195 ConnectionPointContainer_Release,
3196 ConnectionPointContainer_EnumConnectionPoints,
3197 ConnectionPointContainer_FindConnectionPoint
3200 /* IConnectionPoint */
3201 static HRESULT WINAPI ConnectionPoint_QueryInterface(IConnectionPoint *iface,
3202 REFIID riid, void **ppv)
3204 ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3206 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv );
3208 *ppv = NULL;
3210 if (IsEqualGUID(&IID_IUnknown, riid) ||
3211 IsEqualGUID(&IID_IConnectionPoint, riid))
3213 *ppv = iface;
3216 if (*ppv)
3218 IConnectionPoint_AddRef(iface);
3219 return S_OK;
3222 WARN("Unsupported interface %s\n", debugstr_guid(riid));
3223 return E_NOINTERFACE;
3226 static ULONG WINAPI ConnectionPoint_AddRef(IConnectionPoint *iface)
3228 ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3229 return IConnectionPointContainer_AddRef(This->container);
3232 static ULONG WINAPI ConnectionPoint_Release(IConnectionPoint *iface)
3234 ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3235 return IConnectionPointContainer_Release(This->container);
3238 static HRESULT WINAPI ConnectionPoint_GetConnectionInterface(IConnectionPoint *iface, IID *iid)
3240 ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3242 TRACE("(%p)->(%p)\n", This, iid);
3244 if (!iid) return E_POINTER;
3246 *iid = *This->iid;
3247 return S_OK;
3250 static HRESULT WINAPI ConnectionPoint_GetConnectionPointContainer(IConnectionPoint *iface,
3251 IConnectionPointContainer **container)
3253 ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3255 TRACE("(%p)->(%p)\n", This, container);
3257 if (!container) return E_POINTER;
3259 *container = This->container;
3260 IConnectionPointContainer_AddRef(*container);
3261 return S_OK;
3264 static HRESULT WINAPI ConnectionPoint_Advise(IConnectionPoint *iface, IUnknown *pUnkSink,
3265 DWORD *pdwCookie)
3267 ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3268 FIXME("(%p)->(%p %p): stub\n", This, pUnkSink, pdwCookie);
3269 return E_NOTIMPL;
3272 static HRESULT WINAPI ConnectionPoint_Unadvise(IConnectionPoint *iface, DWORD cookie)
3274 ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3276 TRACE("(%p)->(%d)\n", This, cookie);
3278 if (cookie == 0 || cookie > This->sinks_size || !This->sinks[cookie-1].unk)
3279 return CONNECT_E_NOCONNECTION;
3281 IUnknown_Release(This->sinks[cookie-1].unk);
3282 This->sinks[cookie-1].unk = NULL;
3284 return S_OK;
3287 static HRESULT WINAPI ConnectionPoint_EnumConnections(IConnectionPoint *iface,
3288 IEnumConnections **ppEnum)
3290 ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3291 FIXME("(%p)->(%p): stub\n", This, ppEnum);
3292 return E_NOTIMPL;
3295 static const IConnectionPointVtbl ConnectionPointVtbl =
3297 ConnectionPoint_QueryInterface,
3298 ConnectionPoint_AddRef,
3299 ConnectionPoint_Release,
3300 ConnectionPoint_GetConnectionInterface,
3301 ConnectionPoint_GetConnectionPointContainer,
3302 ConnectionPoint_Advise,
3303 ConnectionPoint_Unadvise,
3304 ConnectionPoint_EnumConnections
3307 static void ConnectionPoint_Init(ConnectionPoint *cp, struct domdoc *doc, REFIID riid)
3309 cp->IConnectionPoint_iface.lpVtbl = &ConnectionPointVtbl;
3310 cp->doc = doc;
3311 cp->iid = riid;
3312 cp->sinks = NULL;
3313 cp->sinks_size = 0;
3315 cp->next = doc->cp_list;
3316 doc->cp_list = cp;
3318 cp->container = &doc->IConnectionPointContainer_iface;
3321 /* domdoc implementation of IObjectWithSite */
3322 static HRESULT WINAPI
3323 domdoc_ObjectWithSite_QueryInterface( IObjectWithSite* iface, REFIID riid, void** ppvObject )
3325 domdoc *This = impl_from_IObjectWithSite(iface);
3326 return IXMLDOMDocument3_QueryInterface(&This->IXMLDOMDocument3_iface, riid, ppvObject);
3329 static ULONG WINAPI domdoc_ObjectWithSite_AddRef( IObjectWithSite* iface )
3331 domdoc *This = impl_from_IObjectWithSite(iface);
3332 return IXMLDOMDocument3_AddRef(&This->IXMLDOMDocument3_iface);
3335 static ULONG WINAPI domdoc_ObjectWithSite_Release( IObjectWithSite* iface )
3337 domdoc *This = impl_from_IObjectWithSite(iface);
3338 return IXMLDOMDocument3_Release(&This->IXMLDOMDocument3_iface);
3341 static HRESULT WINAPI domdoc_ObjectWithSite_GetSite( IObjectWithSite *iface, REFIID iid, void **ppvSite )
3343 domdoc *This = impl_from_IObjectWithSite(iface);
3345 TRACE("(%p)->(%s %p)\n", This, debugstr_guid( iid ), ppvSite );
3347 if ( !This->site )
3348 return E_FAIL;
3350 return IUnknown_QueryInterface( This->site, iid, ppvSite );
3353 static HRESULT WINAPI domdoc_ObjectWithSite_SetSite( IObjectWithSite *iface, IUnknown *punk )
3355 domdoc *This = impl_from_IObjectWithSite(iface);
3357 TRACE("(%p)->(%p)\n", iface, punk);
3359 if(!punk)
3361 if(This->site)
3363 IUnknown_Release( This->site );
3364 This->site = NULL;
3367 return S_OK;
3370 IUnknown_AddRef( punk );
3372 if(This->site)
3373 IUnknown_Release( This->site );
3375 This->site = punk;
3377 return S_OK;
3380 static const IObjectWithSiteVtbl domdocObjectSite =
3382 domdoc_ObjectWithSite_QueryInterface,
3383 domdoc_ObjectWithSite_AddRef,
3384 domdoc_ObjectWithSite_Release,
3385 domdoc_ObjectWithSite_SetSite,
3386 domdoc_ObjectWithSite_GetSite
3389 static HRESULT WINAPI domdoc_Safety_QueryInterface(IObjectSafety *iface, REFIID riid, void **ppv)
3391 domdoc *This = impl_from_IObjectSafety(iface);
3392 return IXMLDOMDocument3_QueryInterface(&This->IXMLDOMDocument3_iface, riid, ppv);
3395 static ULONG WINAPI domdoc_Safety_AddRef(IObjectSafety *iface)
3397 domdoc *This = impl_from_IObjectSafety(iface);
3398 return IXMLDOMDocument3_AddRef(&This->IXMLDOMDocument3_iface);
3401 static ULONG WINAPI domdoc_Safety_Release(IObjectSafety *iface)
3403 domdoc *This = impl_from_IObjectSafety(iface);
3404 return IXMLDOMDocument3_Release(&This->IXMLDOMDocument3_iface);
3407 #define SAFETY_SUPPORTED_OPTIONS (INTERFACESAFE_FOR_UNTRUSTED_CALLER|INTERFACESAFE_FOR_UNTRUSTED_DATA|INTERFACE_USES_SECURITY_MANAGER)
3409 static HRESULT WINAPI domdoc_Safety_GetInterfaceSafetyOptions(IObjectSafety *iface, REFIID riid,
3410 DWORD *supported, DWORD *enabled)
3412 domdoc *This = impl_from_IObjectSafety(iface);
3414 TRACE("(%p)->(%s %p %p)\n", This, debugstr_guid(riid), supported, enabled);
3416 if(!supported || !enabled) return E_POINTER;
3418 *supported = SAFETY_SUPPORTED_OPTIONS;
3419 *enabled = This->safeopt;
3421 return S_OK;
3424 static HRESULT WINAPI domdoc_Safety_SetInterfaceSafetyOptions(IObjectSafety *iface, REFIID riid,
3425 DWORD mask, DWORD enabled)
3427 domdoc *This = impl_from_IObjectSafety(iface);
3428 TRACE("(%p)->(%s %x %x)\n", This, debugstr_guid(riid), mask, enabled);
3430 if ((mask & ~SAFETY_SUPPORTED_OPTIONS) != 0)
3431 return E_FAIL;
3433 This->safeopt = (This->safeopt & ~mask) | (mask & enabled);
3435 return S_OK;
3438 #undef SAFETY_SUPPORTED_OPTIONS
3440 static const IObjectSafetyVtbl domdocObjectSafetyVtbl = {
3441 domdoc_Safety_QueryInterface,
3442 domdoc_Safety_AddRef,
3443 domdoc_Safety_Release,
3444 domdoc_Safety_GetInterfaceSafetyOptions,
3445 domdoc_Safety_SetInterfaceSafetyOptions
3448 static const tid_t domdoc_iface_tids[] = {
3449 IXMLDOMNode_tid,
3450 IXMLDOMDocument_tid,
3451 IXMLDOMDocument2_tid,
3454 static dispex_static_data_t domdoc_dispex = {
3455 NULL,
3456 IXMLDOMDocument2_tid,
3457 NULL,
3458 domdoc_iface_tids
3461 HRESULT get_domdoc_from_xmldoc(xmlDocPtr xmldoc, IXMLDOMDocument3 **document)
3463 domdoc *doc;
3465 doc = heap_alloc( sizeof (*doc) );
3466 if( !doc )
3467 return E_OUTOFMEMORY;
3469 doc->IXMLDOMDocument3_iface.lpVtbl = &domdoc_vtbl;
3470 doc->IPersistStreamInit_iface.lpVtbl = &xmldoc_IPersistStreamInit_VTable;
3471 doc->IObjectWithSite_iface.lpVtbl = &domdocObjectSite;
3472 doc->IObjectSafety_iface.lpVtbl = &domdocObjectSafetyVtbl;
3473 doc->ISupportErrorInfo_iface.lpVtbl = &support_error_vtbl;
3474 doc->IConnectionPointContainer_iface.lpVtbl = &ConnectionPointContainerVtbl;
3475 doc->ref = 1;
3476 doc->async = VARIANT_TRUE;
3477 doc->validating = 0;
3478 doc->resolving = 0;
3479 doc->properties = properties_from_xmlDocPtr(xmldoc);
3480 doc->error = S_OK;
3481 doc->stream = NULL;
3482 doc->site = NULL;
3483 doc->safeopt = 0;
3484 doc->bsc = NULL;
3485 doc->cp_list = NULL;
3486 memset(doc->events, 0, sizeof(doc->events));
3488 /* events connection points */
3489 ConnectionPoint_Init(&doc->cp_dispatch, doc, &IID_IDispatch);
3490 ConnectionPoint_Init(&doc->cp_propnotif, doc, &IID_IPropertyNotifySink);
3491 ConnectionPoint_Init(&doc->cp_domdocevents, doc, &DIID_XMLDOMDocumentEvents);
3493 init_xmlnode(&doc->node, (xmlNodePtr)xmldoc, (IXMLDOMNode*)&doc->IXMLDOMDocument3_iface,
3494 &domdoc_dispex);
3496 *document = &doc->IXMLDOMDocument3_iface;
3498 TRACE("returning iface %p\n", *document);
3499 return S_OK;
3502 HRESULT DOMDocument_create(MSXML_VERSION version, IUnknown *pUnkOuter, void **ppObj)
3504 xmlDocPtr xmldoc;
3505 HRESULT hr;
3507 TRACE("(%d, %p, %p)\n", version, pUnkOuter, ppObj);
3509 xmldoc = xmlNewDoc(NULL);
3510 if(!xmldoc)
3511 return E_OUTOFMEMORY;
3513 xmldoc->_private = create_priv();
3514 priv_from_xmlDocPtr(xmldoc)->properties = create_properties(version);
3516 hr = get_domdoc_from_xmldoc(xmldoc, (IXMLDOMDocument3**)ppObj);
3517 if(FAILED(hr))
3519 free_properties(properties_from_xmlDocPtr(xmldoc));
3520 heap_free(xmldoc->_private);
3521 xmlFreeDoc(xmldoc);
3522 return hr;
3525 return hr;
3528 IUnknown* create_domdoc( xmlNodePtr document )
3530 void* pObj = NULL;
3531 HRESULT hr;
3533 TRACE("(%p)\n", document);
3535 hr = get_domdoc_from_xmldoc((xmlDocPtr)document, (IXMLDOMDocument3**)&pObj);
3536 if (FAILED(hr))
3537 return NULL;
3539 return pObj;
3542 #else
3544 HRESULT DOMDocument_create(MSXML_VERSION version, IUnknown *pUnkOuter, void **ppObj)
3546 MESSAGE("This program tried to use a DOMDocument object, but\n"
3547 "libxml2 support was not present at compile time.\n");
3548 return E_NOTIMPL;
3551 #endif