ntdll/tests: Add a FILE_APPEND_DATA test.
[wine.git] / dlls / msxml3 / domdoc.c
blobb4a5b84dfce97851ade32654fc757c3ca35b33ae
1 /*
2 * DOM Document implementation
4 * Copyright 2005 Mike McCormack
5 * Copyright 2010 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 #include "windef.h"
30 #include "winbase.h"
31 #include "winuser.h"
32 #include "winnls.h"
33 #include "ole2.h"
34 #include "olectl.h"
35 #include "msxml6.h"
36 #include "wininet.h"
37 #include "winreg.h"
38 #include "shlwapi.h"
39 #include "ocidl.h"
40 #include "objsafe.h"
41 #include "dispex.h"
43 #include "wine/debug.h"
44 #include "wine/list.h"
46 #include "msxml_private.h"
48 WINE_DEFAULT_DEBUG_CHANNEL(msxml);
50 #ifdef HAVE_LIBXML2
52 #include <libxml/xpathInternals.h>
53 #include <libxml/xmlsave.h>
54 #include <libxml/SAX2.h>
55 #include <libxml/parserInternals.h>
57 /* not defined in older versions */
58 #define XML_SAVE_FORMAT 1
59 #define XML_SAVE_NO_DECL 2
60 #define XML_SAVE_NO_EMPTY 4
61 #define XML_SAVE_NO_XHTML 8
62 #define XML_SAVE_XHTML 16
63 #define XML_SAVE_AS_XML 32
64 #define XML_SAVE_AS_HTML 64
66 static const WCHAR PropertySelectionLanguageW[] = {'S','e','l','e','c','t','i','o','n','L','a','n','g','u','a','g','e',0};
67 static const WCHAR PropertySelectionNamespacesW[] = {'S','e','l','e','c','t','i','o','n','N','a','m','e','s','p','a','c','e','s',0};
68 static const WCHAR PropertyProhibitDTDW[] = {'P','r','o','h','i','b','i','t','D','T','D',0};
69 static const WCHAR PropertyNewParserW[] = {'N','e','w','P','a','r','s','e','r',0};
70 static const WCHAR PropValueXPathW[] = {'X','P','a','t','h',0};
71 static const WCHAR PropValueXSLPatternW[] = {'X','S','L','P','a','t','t','e','r','n',0};
73 /* Anything that passes the test_get_ownerDocument()
74 * tests can go here (data shared between all instances).
75 * We need to preserve this when reloading a document,
76 * and also need access to it from the libxml backend. */
77 typedef struct _domdoc_properties {
78 MSXML_VERSION version;
79 VARIANT_BOOL preserving;
80 IXMLDOMSchemaCollection2* schemaCache;
81 struct list selectNsList;
82 xmlChar const* selectNsStr;
83 LONG selectNsStr_len;
84 BOOL XPath;
85 } domdoc_properties;
87 typedef struct ConnectionPoint ConnectionPoint;
88 typedef struct domdoc domdoc;
90 struct ConnectionPoint
92 const IConnectionPointVtbl *lpVtblConnectionPoint;
93 const IID *iid;
95 ConnectionPoint *next;
96 IConnectionPointContainer *container;
97 domdoc *doc;
99 union
101 IUnknown *unk;
102 IDispatch *disp;
103 IPropertyNotifySink *propnotif;
104 } *sinks;
105 DWORD sinks_size;
108 struct domdoc
110 xmlnode node;
111 const struct IXMLDOMDocument3Vtbl *lpVtbl;
112 const struct IPersistStreamInitVtbl *lpvtblIPersistStreamInit;
113 const struct IObjectWithSiteVtbl *lpvtblIObjectWithSite;
114 const struct IObjectSafetyVtbl *lpvtblIObjectSafety;
115 const struct ISupportErrorInfoVtbl *lpvtblISupportErrorInfo;
116 const struct IConnectionPointContainerVtbl *lpVtblConnectionPointContainer;
117 LONG ref;
118 VARIANT_BOOL async;
119 VARIANT_BOOL validating;
120 VARIANT_BOOL resolving;
121 domdoc_properties* properties;
122 bsc_t *bsc;
123 HRESULT error;
125 /* IPersistStream */
126 IStream *stream;
128 /* IObjectWithSite*/
129 IUnknown *site;
131 /* IObjectSafety */
132 DWORD safeopt;
134 /* connection list */
135 ConnectionPoint *cp_list;
136 ConnectionPoint cp_domdocevents;
137 ConnectionPoint cp_propnotif;
138 ConnectionPoint cp_dispatch;
141 static inline ConnectionPoint *impl_from_IConnectionPoint(IConnectionPoint *iface)
143 return (ConnectionPoint *)((char*)iface - FIELD_OFFSET(ConnectionPoint, lpVtblConnectionPoint));
147 In native windows, the whole lifetime management of XMLDOMNodes is
148 managed automatically using reference counts. Wine emulates that by
149 maintaining a reference count to the document that is increased for
150 each IXMLDOMNode pointer passed out for this document. If all these
151 pointers are gone, the document is unreachable and gets freed, that
152 is, all nodes in the tree of the document get freed.
154 You are able to create nodes that are associated to a document (in
155 fact, in msxml's XMLDOM model, all nodes are associated to a document),
156 but not in the tree of that document, for example using the createFoo
157 functions from IXMLDOMDocument. These nodes do not get cleaned up
158 by libxml, so we have to do it ourselves.
160 To catch these nodes, a list of "orphan nodes" is introduced.
161 It contains pointers to all roots of node trees that are
162 associated with the document without being part of the document
163 tree. All nodes with parent==NULL (except for the document root nodes)
164 should be in the orphan node list of their document. All orphan nodes
165 get freed together with the document itself.
168 typedef struct _xmldoc_priv {
169 LONG refs;
170 struct list orphans;
171 domdoc_properties* properties;
172 } xmldoc_priv;
174 typedef struct _orphan_entry {
175 struct list entry;
176 xmlNode * node;
177 } orphan_entry;
179 typedef struct _select_ns_entry {
180 struct list entry;
181 xmlChar const* prefix;
182 xmlChar prefix_end;
183 xmlChar const* href;
184 xmlChar href_end;
185 } select_ns_entry;
187 static inline xmldoc_priv * priv_from_xmlDocPtr(const xmlDocPtr doc)
189 return doc->_private;
192 static inline domdoc_properties * properties_from_xmlDocPtr(xmlDocPtr doc)
194 return priv_from_xmlDocPtr(doc)->properties;
197 BOOL is_xpathmode(const xmlDocPtr doc)
199 return properties_from_xmlDocPtr(doc)->XPath;
202 void set_xpathmode(xmlDocPtr doc, BOOL xpath)
204 properties_from_xmlDocPtr(doc)->XPath = xpath;
207 int registerNamespaces(xmlXPathContextPtr ctxt)
209 int n = 0;
210 const select_ns_entry* ns = NULL;
211 const struct list* pNsList = &properties_from_xmlDocPtr(ctxt->doc)->selectNsList;
213 TRACE("(%p)\n", ctxt);
215 LIST_FOR_EACH_ENTRY( ns, pNsList, select_ns_entry, entry )
217 xmlXPathRegisterNs(ctxt, ns->prefix, ns->href);
218 ++n;
221 return n;
224 static inline void clear_selectNsList(struct list* pNsList)
226 select_ns_entry *ns, *ns2;
227 LIST_FOR_EACH_ENTRY_SAFE( ns, ns2, pNsList, select_ns_entry, entry )
229 heap_free( ns );
231 list_init(pNsList);
234 static xmldoc_priv * create_priv(void)
236 xmldoc_priv *priv;
237 priv = heap_alloc( sizeof (*priv) );
239 if (priv)
241 priv->refs = 0;
242 list_init( &priv->orphans );
243 priv->properties = NULL;
246 return priv;
249 static domdoc_properties * create_properties(const GUID *clsid)
251 domdoc_properties *properties = heap_alloc(sizeof(domdoc_properties));
253 list_init(&properties->selectNsList);
254 properties->preserving = VARIANT_FALSE;
255 properties->schemaCache = NULL;
256 properties->selectNsStr = heap_alloc_zero(sizeof(xmlChar));
257 properties->selectNsStr_len = 0;
259 /* properties that are dependent on object versions */
260 if (IsEqualCLSID(clsid, &CLSID_DOMDocument30))
262 properties->version = MSXML3;
263 properties->XPath = FALSE;
265 else if (IsEqualCLSID(clsid, &CLSID_DOMDocument40))
267 properties->version = MSXML4;
268 properties->XPath = TRUE;
270 else if (IsEqualCLSID(clsid, &CLSID_DOMDocument60))
272 properties->version = MSXML6;
273 properties->XPath = TRUE;
275 else
277 properties->version = MSXML_DEFAULT;
278 properties->XPath = FALSE;
281 return properties;
284 static domdoc_properties* copy_properties(domdoc_properties const* properties)
286 domdoc_properties* pcopy = heap_alloc(sizeof(domdoc_properties));
287 select_ns_entry const* ns = NULL;
288 select_ns_entry* new_ns = NULL;
289 int len = (properties->selectNsStr_len+1)*sizeof(xmlChar);
290 ptrdiff_t offset;
292 if (pcopy)
294 pcopy->version = properties->version;
295 pcopy->preserving = properties->preserving;
296 pcopy->schemaCache = properties->schemaCache;
297 if (pcopy->schemaCache)
298 IXMLDOMSchemaCollection2_AddRef(pcopy->schemaCache);
299 pcopy->XPath = properties->XPath;
300 pcopy->selectNsStr_len = properties->selectNsStr_len;
301 list_init( &pcopy->selectNsList );
302 pcopy->selectNsStr = heap_alloc(len);
303 memcpy((xmlChar*)pcopy->selectNsStr, properties->selectNsStr, len);
304 offset = pcopy->selectNsStr - properties->selectNsStr;
306 LIST_FOR_EACH_ENTRY( ns, (&properties->selectNsList), select_ns_entry, entry )
308 new_ns = heap_alloc(sizeof(select_ns_entry));
309 memcpy(new_ns, ns, sizeof(select_ns_entry));
310 new_ns->href += offset;
311 new_ns->prefix += offset;
312 list_add_tail(&pcopy->selectNsList, &new_ns->entry);
317 return pcopy;
320 static void free_properties(domdoc_properties* properties)
322 if (properties)
324 if (properties->schemaCache)
325 IXMLDOMSchemaCollection2_Release(properties->schemaCache);
326 clear_selectNsList(&properties->selectNsList);
327 heap_free((xmlChar*)properties->selectNsStr);
328 heap_free(properties);
332 static BOOL xmldoc_has_decl(xmlDocPtr doc)
334 return doc->children && (xmlStrEqual(doc->children->name, (xmlChar*)"xml") == 1);
337 /* links a "<?xml" node as a first child */
338 void xmldoc_link_xmldecl(xmlDocPtr doc, xmlNodePtr node)
340 assert(doc != NULL);
341 if (doc->standalone != -1) xmlAddPrevSibling( doc->children, node );
344 /* unlinks a first "<?xml" child if it was created */
345 xmlNodePtr xmldoc_unlink_xmldecl(xmlDocPtr doc)
347 xmlNodePtr node;
349 assert(doc != NULL);
351 if (doc->standalone != -1)
353 node = doc->children;
354 xmlUnlinkNode( node );
356 else
357 node = NULL;
359 return node;
362 BOOL is_preserving_whitespace(xmlNodePtr node)
364 domdoc_properties* properties = NULL;
365 /* during parsing the xmlDoc._private stuff is not there */
366 if (priv_from_xmlDocPtr(node->doc))
367 properties = properties_from_xmlDocPtr(node->doc);
368 return ((properties && properties->preserving == VARIANT_TRUE) ||
369 xmlNodeGetSpacePreserve(node) == 1);
372 static inline BOOL strn_isspace(xmlChar const* str, int len)
374 for (; str && len > 0 && *str; ++str, --len)
375 if (!isspace(*str))
376 break;
378 return len == 0;
381 static void sax_characters(void *ctx, const xmlChar *ch, int len)
383 xmlParserCtxtPtr pctx;
384 domdoc const* This;
386 pctx = (xmlParserCtxtPtr) ctx;
387 This = (domdoc const*) pctx->_private;
389 /* during domdoc_loadXML() the xmlDocPtr->_private data is not available */
390 if (!This->properties->preserving &&
391 !is_preserving_whitespace(pctx->node) &&
392 strn_isspace(ch, len))
393 return;
395 xmlSAX2Characters(ctx, ch, len);
398 static void LIBXML2_LOG_CALLBACK sax_error(void* ctx, char const* msg, ...)
400 va_list ap;
401 va_start(ap, msg);
402 LIBXML2_CALLBACK_ERR(doparse, msg, ap);
403 va_end(ap);
406 static void LIBXML2_LOG_CALLBACK sax_warning(void* ctx, char const* msg, ...)
408 va_list ap;
409 va_start(ap, msg);
410 LIBXML2_CALLBACK_WARN(doparse, msg, ap);
411 va_end(ap);
414 static void sax_serror(void* ctx, xmlErrorPtr err)
416 LIBXML2_CALLBACK_SERROR(doparse, err);
419 static xmlDocPtr doparse(domdoc* This, char *ptr, int len, xmlChar const* encoding)
421 xmlDocPtr doc = NULL;
422 xmlParserCtxtPtr pctx;
423 static xmlSAXHandler sax_handler = {
424 xmlSAX2InternalSubset, /* internalSubset */
425 xmlSAX2IsStandalone, /* isStandalone */
426 xmlSAX2HasInternalSubset, /* hasInternalSubset */
427 xmlSAX2HasExternalSubset, /* hasExternalSubset */
428 xmlSAX2ResolveEntity, /* resolveEntity */
429 xmlSAX2GetEntity, /* getEntity */
430 xmlSAX2EntityDecl, /* entityDecl */
431 xmlSAX2NotationDecl, /* notationDecl */
432 xmlSAX2AttributeDecl, /* attributeDecl */
433 xmlSAX2ElementDecl, /* elementDecl */
434 xmlSAX2UnparsedEntityDecl, /* unparsedEntityDecl */
435 xmlSAX2SetDocumentLocator, /* setDocumentLocator */
436 xmlSAX2StartDocument, /* startDocument */
437 xmlSAX2EndDocument, /* endDocument */
438 xmlSAX2StartElement, /* startElement */
439 xmlSAX2EndElement, /* endElement */
440 xmlSAX2Reference, /* reference */
441 sax_characters, /* characters */
442 sax_characters, /* ignorableWhitespace */
443 xmlSAX2ProcessingInstruction, /* processingInstruction */
444 xmlSAX2Comment, /* comment */
445 sax_warning, /* warning */
446 sax_error, /* error */
447 sax_error, /* fatalError */
448 xmlSAX2GetParameterEntity, /* getParameterEntity */
449 xmlSAX2CDataBlock, /* cdataBlock */
450 xmlSAX2ExternalSubset, /* externalSubset */
451 0, /* initialized */
452 NULL, /* _private */
453 xmlSAX2StartElementNs, /* startElementNs */
454 xmlSAX2EndElementNs, /* endElementNs */
455 sax_serror /* serror */
457 xmlInitParser();
459 pctx = xmlCreateMemoryParserCtxt(ptr, len);
460 if (!pctx)
462 ERR("Failed to create parser context\n");
463 return NULL;
466 if (pctx->sax) xmlFree(pctx->sax);
467 pctx->sax = &sax_handler;
468 pctx->_private = This;
469 pctx->recovery = 0;
470 pctx->encoding = xmlStrdup(encoding);
471 xmlParseDocument(pctx);
473 if (pctx->wellFormed)
475 doc = pctx->myDoc;
477 else
479 xmlFreeDoc(pctx->myDoc);
480 pctx->myDoc = NULL;
482 pctx->sax = NULL;
483 xmlFreeParserCtxt(pctx);
485 /* TODO: put this in one of the SAX callbacks */
486 /* create first child as a <?xml...?> */
487 if (doc && doc->standalone != -1)
489 xmlNodePtr node;
490 char buff[30];
491 xmlChar *xmlbuff = (xmlChar*)buff;
493 node = xmlNewDocPI( doc, (xmlChar*)"xml", NULL );
495 /* version attribute can't be omitted */
496 sprintf(buff, "version=\"%s\"", doc->version ? (char*)doc->version : "1.0");
497 xmlNodeAddContent( node, xmlbuff );
499 if (doc->encoding)
501 sprintf(buff, " encoding=\"%s\"", doc->encoding);
502 xmlNodeAddContent( node, xmlbuff );
505 if (doc->standalone != -2)
507 sprintf(buff, " standalone=\"%s\"", doc->standalone == 0 ? "no" : "yes");
508 xmlNodeAddContent( node, xmlbuff );
511 xmldoc_link_xmldecl( doc, node );
514 return doc;
517 void xmldoc_init(xmlDocPtr doc, const GUID *clsid)
519 doc->_private = create_priv();
520 priv_from_xmlDocPtr(doc)->properties = create_properties(clsid);
523 LONG xmldoc_add_ref(xmlDocPtr doc)
525 LONG ref = InterlockedIncrement(&priv_from_xmlDocPtr(doc)->refs);
526 TRACE("(%p)->(%d)\n", doc, ref);
527 return ref;
530 LONG xmldoc_release(xmlDocPtr doc)
532 xmldoc_priv *priv = priv_from_xmlDocPtr(doc);
533 LONG ref = InterlockedDecrement(&priv->refs);
534 TRACE("(%p)->(%d)\n", doc, ref);
535 if(ref == 0)
537 orphan_entry *orphan, *orphan2;
538 TRACE("freeing docptr %p\n", doc);
540 LIST_FOR_EACH_ENTRY_SAFE( orphan, orphan2, &priv->orphans, orphan_entry, entry )
542 xmlFreeNode( orphan->node );
543 heap_free( orphan );
545 free_properties(priv->properties);
546 heap_free(doc->_private);
548 xmlFreeDoc(doc);
551 return ref;
554 HRESULT xmldoc_add_orphan(xmlDocPtr doc, xmlNodePtr node)
556 xmldoc_priv *priv = priv_from_xmlDocPtr(doc);
557 orphan_entry *entry;
559 entry = heap_alloc( sizeof (*entry) );
560 if(!entry)
561 return E_OUTOFMEMORY;
563 entry->node = node;
564 list_add_head( &priv->orphans, &entry->entry );
565 return S_OK;
568 HRESULT xmldoc_remove_orphan(xmlDocPtr doc, xmlNodePtr node)
570 xmldoc_priv *priv = priv_from_xmlDocPtr(doc);
571 orphan_entry *entry, *entry2;
573 LIST_FOR_EACH_ENTRY_SAFE( entry, entry2, &priv->orphans, orphan_entry, entry )
575 if( entry->node == node )
577 list_remove( &entry->entry );
578 heap_free( entry );
579 return S_OK;
583 return S_FALSE;
586 static inline xmlDocPtr get_doc( domdoc *This )
588 return (xmlDocPtr)This->node.node;
591 static HRESULT attach_xmldoc(domdoc *This, xmlDocPtr xml )
593 if(This->node.node)
595 priv_from_xmlDocPtr(get_doc(This))->properties = NULL;
596 if (xmldoc_release(get_doc(This)) != 0)
597 priv_from_xmlDocPtr(get_doc(This))->properties =
598 copy_properties(This->properties);
601 This->node.node = (xmlNodePtr) xml;
603 if(This->node.node)
605 xmldoc_add_ref(get_doc(This));
606 priv_from_xmlDocPtr(get_doc(This))->properties = This->properties;
609 return S_OK;
612 static inline domdoc *impl_from_IXMLDOMDocument3( IXMLDOMDocument3 *iface )
614 return (domdoc *)((char*)iface - FIELD_OFFSET(domdoc, lpVtbl));
617 static inline domdoc *impl_from_IPersistStreamInit(IPersistStreamInit *iface)
619 return (domdoc *)((char*)iface - FIELD_OFFSET(domdoc, lpvtblIPersistStreamInit));
622 static inline domdoc *impl_from_IObjectWithSite(IObjectWithSite *iface)
624 return (domdoc *)((char*)iface - FIELD_OFFSET(domdoc, lpvtblIObjectWithSite));
627 static inline domdoc *impl_from_IObjectSafety(IObjectSafety *iface)
629 return (domdoc *)((char*)iface - FIELD_OFFSET(domdoc, lpvtblIObjectSafety));
632 static inline domdoc *impl_from_ISupportErrorInfo(ISupportErrorInfo *iface)
634 return (domdoc *)((char*)iface - FIELD_OFFSET(domdoc, lpvtblISupportErrorInfo));
637 static inline domdoc *impl_from_IConnectionPointContainer(IConnectionPointContainer *iface)
639 return (domdoc *)((char*)iface - FIELD_OFFSET(domdoc, lpVtblConnectionPointContainer));
642 /************************************************************************
643 * domdoc implementation of IPersistStream.
645 static HRESULT WINAPI domdoc_IPersistStreamInit_QueryInterface(
646 IPersistStreamInit *iface, REFIID riid, void **ppvObj)
648 domdoc* This = impl_from_IPersistStreamInit(iface);
649 return IXMLDOMDocument3_QueryInterface((IXMLDOMDocument3*)&This->lpVtbl, riid, ppvObj);
652 static ULONG WINAPI domdoc_IPersistStreamInit_AddRef(
653 IPersistStreamInit *iface)
655 domdoc* This = impl_from_IPersistStreamInit(iface);
656 return IXMLDOMDocument3_AddRef((IXMLDOMDocument3*)&This->lpVtbl);
659 static ULONG WINAPI domdoc_IPersistStreamInit_Release(
660 IPersistStreamInit *iface)
662 domdoc* This = impl_from_IPersistStreamInit(iface);
663 return IXMLDOMDocument3_Release((IXMLDOMDocument3*)&This->lpVtbl);
666 static HRESULT WINAPI domdoc_IPersistStreamInit_GetClassID(
667 IPersistStreamInit *iface, CLSID *classid)
669 domdoc* This = impl_from_IPersistStreamInit(iface);
670 TRACE("(%p)->(%p)\n", This, classid);
672 if(!classid)
673 return E_POINTER;
675 *classid = *DOMDocument_version(This->properties->version);
677 return S_OK;
680 static HRESULT WINAPI domdoc_IPersistStreamInit_IsDirty(
681 IPersistStreamInit *iface)
683 domdoc *This = impl_from_IPersistStreamInit(iface);
684 FIXME("(%p): stub!\n", This);
685 return S_FALSE;
688 static HRESULT WINAPI domdoc_IPersistStreamInit_Load(
689 IPersistStreamInit *iface, LPSTREAM pStm)
691 domdoc *This = impl_from_IPersistStreamInit(iface);
692 HRESULT hr;
693 HGLOBAL hglobal;
694 DWORD read, written, len;
695 BYTE buf[4096];
696 char *ptr;
697 xmlDocPtr xmldoc = NULL;
699 TRACE("(%p)->(%p)\n", This, pStm);
701 if (!pStm)
702 return E_INVALIDARG;
704 hr = CreateStreamOnHGlobal(NULL, TRUE, &This->stream);
705 if (FAILED(hr))
706 return hr;
710 IStream_Read(pStm, buf, sizeof(buf), &read);
711 hr = IStream_Write(This->stream, buf, read, &written);
712 } while(SUCCEEDED(hr) && written != 0 && read != 0);
714 if (FAILED(hr))
716 ERR("Failed to copy stream\n");
717 return hr;
720 hr = GetHGlobalFromStream(This->stream, &hglobal);
721 if (FAILED(hr))
722 return hr;
724 len = GlobalSize(hglobal);
725 ptr = GlobalLock(hglobal);
726 if (len != 0)
727 xmldoc = doparse(This, ptr, len, NULL);
728 GlobalUnlock(hglobal);
730 if (!xmldoc)
732 ERR("Failed to parse xml\n");
733 return E_FAIL;
736 xmldoc->_private = create_priv();
738 return attach_xmldoc(This, xmldoc);
741 static HRESULT WINAPI domdoc_IPersistStreamInit_Save(
742 IPersistStreamInit *iface, IStream *stream, BOOL clr_dirty)
744 domdoc *This = impl_from_IPersistStreamInit(iface);
745 BSTR xmlString;
746 HRESULT hr;
748 TRACE("(%p)->(%p %d)\n", This, stream, clr_dirty);
750 hr = IXMLDOMDocument3_get_xml( (IXMLDOMDocument3*)&This->lpVtbl, &xmlString );
751 if(hr == S_OK)
753 DWORD len = SysStringLen(xmlString) * sizeof(WCHAR);
755 hr = IStream_Write( stream, xmlString, len, NULL );
756 SysFreeString(xmlString);
759 TRACE("ret 0x%08x\n", hr);
761 return hr;
764 static HRESULT WINAPI domdoc_IPersistStreamInit_GetSizeMax(
765 IPersistStreamInit *iface, ULARGE_INTEGER *pcbSize)
767 domdoc *This = impl_from_IPersistStreamInit(iface);
768 TRACE("(%p)->(%p): stub!\n", This, pcbSize);
769 return E_NOTIMPL;
772 static HRESULT WINAPI domdoc_IPersistStreamInit_InitNew(
773 IPersistStreamInit *iface)
775 domdoc *This = impl_from_IPersistStreamInit(iface);
776 TRACE("(%p)\n", This);
777 return S_OK;
780 static const IPersistStreamInitVtbl xmldoc_IPersistStreamInit_VTable =
782 domdoc_IPersistStreamInit_QueryInterface,
783 domdoc_IPersistStreamInit_AddRef,
784 domdoc_IPersistStreamInit_Release,
785 domdoc_IPersistStreamInit_GetClassID,
786 domdoc_IPersistStreamInit_IsDirty,
787 domdoc_IPersistStreamInit_Load,
788 domdoc_IPersistStreamInit_Save,
789 domdoc_IPersistStreamInit_GetSizeMax,
790 domdoc_IPersistStreamInit_InitNew
793 /* ISupportErrorInfo interface */
794 static HRESULT WINAPI support_error_QueryInterface(
795 ISupportErrorInfo *iface,
796 REFIID riid, void** ppvObj )
798 domdoc *This = impl_from_ISupportErrorInfo(iface);
799 return IXMLDOMDocument3_QueryInterface((IXMLDOMDocument3 *)This, riid, ppvObj);
802 static ULONG WINAPI support_error_AddRef(
803 ISupportErrorInfo *iface )
805 domdoc *This = impl_from_ISupportErrorInfo(iface);
806 return IXMLDOMDocument3_AddRef((IXMLDOMDocument3 *)This);
809 static ULONG WINAPI support_error_Release(
810 ISupportErrorInfo *iface )
812 domdoc *This = impl_from_ISupportErrorInfo(iface);
813 return IXMLDOMDocument3_Release((IXMLDOMDocument3 *)This);
816 static HRESULT WINAPI support_error_InterfaceSupportsErrorInfo(
817 ISupportErrorInfo *iface,
818 REFIID riid )
820 FIXME("(%p)->(%s)\n", iface, debugstr_guid(riid));
821 return S_FALSE;
824 static const struct ISupportErrorInfoVtbl support_error_vtbl =
826 support_error_QueryInterface,
827 support_error_AddRef,
828 support_error_Release,
829 support_error_InterfaceSupportsErrorInfo
832 /* IXMLDOMDocument2 interface */
833 static HRESULT WINAPI domdoc_QueryInterface( IXMLDOMDocument3 *iface, REFIID riid, void** ppvObject )
835 domdoc *This = impl_from_IXMLDOMDocument3( iface );
837 TRACE("(%p)->(%s %p)\n", This, debugstr_guid( riid ), ppvObject );
839 *ppvObject = NULL;
841 if ( IsEqualGUID( riid, &IID_IUnknown ) ||
842 IsEqualGUID( riid, &IID_IDispatch ) ||
843 IsEqualGUID( riid, &IID_IXMLDOMNode ) ||
844 IsEqualGUID( riid, &IID_IXMLDOMDocument ) ||
845 IsEqualGUID( riid, &IID_IXMLDOMDocument2 )||
846 IsEqualGUID( riid, &IID_IXMLDOMDocument3 ))
848 *ppvObject = iface;
850 else if (IsEqualGUID(&IID_IPersistStream, riid) ||
851 IsEqualGUID(&IID_IPersistStreamInit, riid))
853 *ppvObject = &(This->lpvtblIPersistStreamInit);
855 else if (IsEqualGUID(&IID_IObjectWithSite, riid))
857 *ppvObject = &(This->lpvtblIObjectWithSite);
859 else if (IsEqualGUID(&IID_IObjectSafety, riid))
861 *ppvObject = &(This->lpvtblIObjectSafety);
863 else if( IsEqualGUID( riid, &IID_ISupportErrorInfo ))
865 *ppvObject = &This->lpvtblISupportErrorInfo;
867 else if(node_query_interface(&This->node, riid, ppvObject))
869 return *ppvObject ? S_OK : E_NOINTERFACE;
871 else if (IsEqualGUID( riid, &IID_IConnectionPointContainer ))
873 *ppvObject = &This->lpVtblConnectionPointContainer;
875 else if(IsEqualGUID(&IID_IRunnableObject, riid))
877 TRACE("IID_IRunnableObject not supported returning NULL\n");
878 return E_NOINTERFACE;
880 else
882 FIXME("interface %s not implemented\n", debugstr_guid(riid));
883 return E_NOINTERFACE;
886 IUnknown_AddRef((IUnknown*)*ppvObject);
888 return S_OK;
892 static ULONG WINAPI domdoc_AddRef(
893 IXMLDOMDocument3 *iface )
895 domdoc *This = impl_from_IXMLDOMDocument3( iface );
896 ULONG ref = InterlockedIncrement( &This->ref );
897 TRACE("(%p)->(%d)\n", This, ref );
898 return ref;
902 static ULONG WINAPI domdoc_Release(
903 IXMLDOMDocument3 *iface )
905 domdoc *This = impl_from_IXMLDOMDocument3( iface );
906 LONG ref = InterlockedDecrement( &This->ref );
908 TRACE("(%p)->(%d)\n", This, ref );
910 if ( ref == 0 )
912 if(This->bsc)
913 detach_bsc(This->bsc);
915 if (This->site)
916 IUnknown_Release( This->site );
917 destroy_xmlnode(&This->node);
918 if (This->stream)
919 IStream_Release(This->stream);
920 heap_free(This);
923 return ref;
926 static HRESULT WINAPI domdoc_GetTypeInfoCount( IXMLDOMDocument3 *iface, UINT* pctinfo )
928 domdoc *This = impl_from_IXMLDOMDocument3( iface );
930 TRACE("(%p)->(%p)\n", This, pctinfo);
932 *pctinfo = 1;
934 return S_OK;
937 static HRESULT WINAPI domdoc_GetTypeInfo(
938 IXMLDOMDocument3 *iface,
939 UINT iTInfo, LCID lcid, ITypeInfo** ppTInfo )
941 domdoc *This = impl_from_IXMLDOMDocument3( iface );
942 HRESULT hr;
944 TRACE("(%p)->(%u %u %p)\n", This, iTInfo, lcid, ppTInfo);
946 hr = get_typeinfo(IXMLDOMDocument2_tid, ppTInfo);
948 return hr;
951 static HRESULT WINAPI domdoc_GetIDsOfNames(
952 IXMLDOMDocument3 *iface,
953 REFIID riid,
954 LPOLESTR* rgszNames,
955 UINT cNames,
956 LCID lcid,
957 DISPID* rgDispId)
959 domdoc *This = impl_from_IXMLDOMDocument3( iface );
960 ITypeInfo *typeinfo;
961 HRESULT hr;
963 TRACE("(%p)->(%s %p %u %u %p)\n", This, debugstr_guid(riid), rgszNames, cNames,
964 lcid, rgDispId);
966 if(!rgszNames || cNames == 0 || !rgDispId)
967 return E_INVALIDARG;
969 hr = get_typeinfo(IXMLDOMDocument2_tid, &typeinfo);
970 if(SUCCEEDED(hr))
972 hr = ITypeInfo_GetIDsOfNames(typeinfo, rgszNames, cNames, rgDispId);
973 ITypeInfo_Release(typeinfo);
976 return hr;
980 static HRESULT WINAPI domdoc_Invoke(
981 IXMLDOMDocument3 *iface,
982 DISPID dispIdMember,
983 REFIID riid,
984 LCID lcid,
985 WORD wFlags,
986 DISPPARAMS* pDispParams,
987 VARIANT* pVarResult,
988 EXCEPINFO* pExcepInfo,
989 UINT* puArgErr)
991 domdoc *This = impl_from_IXMLDOMDocument3( iface );
992 ITypeInfo *typeinfo;
993 HRESULT hr;
995 TRACE("(%p)->(%d %s %d %d %p %p %p %p)\n", This, dispIdMember, debugstr_guid(riid),
996 lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
998 hr = get_typeinfo(IXMLDOMDocument2_tid, &typeinfo);
999 if(SUCCEEDED(hr))
1001 hr = ITypeInfo_Invoke(typeinfo, &(This->lpVtbl), dispIdMember, wFlags, pDispParams,
1002 pVarResult, pExcepInfo, puArgErr);
1003 ITypeInfo_Release(typeinfo);
1006 return hr;
1010 static HRESULT WINAPI domdoc_get_nodeName(
1011 IXMLDOMDocument3 *iface,
1012 BSTR* name )
1014 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1016 static const WCHAR documentW[] = {'#','d','o','c','u','m','e','n','t',0};
1018 TRACE("(%p)->(%p)\n", This, name);
1020 return return_bstr(documentW, name);
1024 static HRESULT WINAPI domdoc_get_nodeValue(
1025 IXMLDOMDocument3 *iface,
1026 VARIANT* value )
1028 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1030 TRACE("(%p)->(%p)\n", This, value);
1032 if(!value)
1033 return E_INVALIDARG;
1035 V_VT(value) = VT_NULL;
1036 V_BSTR(value) = NULL; /* tests show that we should do this */
1037 return S_FALSE;
1041 static HRESULT WINAPI domdoc_put_nodeValue(
1042 IXMLDOMDocument3 *iface,
1043 VARIANT value)
1045 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1046 TRACE("(%p)->(v%d)\n", This, V_VT(&value));
1047 return E_FAIL;
1051 static HRESULT WINAPI domdoc_get_nodeType(
1052 IXMLDOMDocument3 *iface,
1053 DOMNodeType* type )
1055 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1057 TRACE("(%p)->(%p)\n", This, type);
1059 *type = NODE_DOCUMENT;
1060 return S_OK;
1064 static HRESULT WINAPI domdoc_get_parentNode(
1065 IXMLDOMDocument3 *iface,
1066 IXMLDOMNode** parent )
1068 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1070 TRACE("(%p)->(%p)\n", This, parent);
1072 return node_get_parent(&This->node, parent);
1076 static HRESULT WINAPI domdoc_get_childNodes(
1077 IXMLDOMDocument3 *iface,
1078 IXMLDOMNodeList** childList )
1080 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1082 TRACE("(%p)->(%p)\n", This, childList);
1084 return node_get_child_nodes(&This->node, childList);
1088 static HRESULT WINAPI domdoc_get_firstChild(
1089 IXMLDOMDocument3 *iface,
1090 IXMLDOMNode** firstChild )
1092 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1094 TRACE("(%p)->(%p)\n", This, firstChild);
1096 return node_get_first_child(&This->node, firstChild);
1100 static HRESULT WINAPI domdoc_get_lastChild(
1101 IXMLDOMDocument3 *iface,
1102 IXMLDOMNode** lastChild )
1104 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1106 TRACE("(%p)->(%p)\n", This, lastChild);
1108 return node_get_last_child(&This->node, lastChild);
1112 static HRESULT WINAPI domdoc_get_previousSibling(
1113 IXMLDOMDocument3 *iface,
1114 IXMLDOMNode** previousSibling )
1116 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1118 TRACE("(%p)->(%p)\n", This, previousSibling);
1120 return return_null_node(previousSibling);
1124 static HRESULT WINAPI domdoc_get_nextSibling(
1125 IXMLDOMDocument3 *iface,
1126 IXMLDOMNode** nextSibling )
1128 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1130 TRACE("(%p)->(%p)\n", This, nextSibling);
1132 return return_null_node(nextSibling);
1136 static HRESULT WINAPI domdoc_get_attributes(
1137 IXMLDOMDocument3 *iface,
1138 IXMLDOMNamedNodeMap** attributeMap )
1140 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1142 TRACE("(%p)->(%p)\n", This, attributeMap);
1144 return return_null_ptr((void**)attributeMap);
1148 static HRESULT WINAPI domdoc_insertBefore(
1149 IXMLDOMDocument3 *iface,
1150 IXMLDOMNode* newChild,
1151 VARIANT refChild,
1152 IXMLDOMNode** outNewChild )
1154 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1156 TRACE("(%p)->(%p x%d %p)\n", This, newChild, V_VT(&refChild), outNewChild);
1158 return node_insert_before(&This->node, newChild, &refChild, outNewChild);
1162 static HRESULT WINAPI domdoc_replaceChild(
1163 IXMLDOMDocument3 *iface,
1164 IXMLDOMNode* newChild,
1165 IXMLDOMNode* oldChild,
1166 IXMLDOMNode** outOldChild)
1168 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1170 TRACE("(%p)->(%p %p %p)\n", This, newChild, oldChild, outOldChild);
1172 return node_replace_child(&This->node, newChild, oldChild, outOldChild);
1176 static HRESULT WINAPI domdoc_removeChild(
1177 IXMLDOMDocument3 *iface,
1178 IXMLDOMNode* childNode,
1179 IXMLDOMNode** oldChild)
1181 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1182 return IXMLDOMNode_removeChild( IXMLDOMNode_from_impl(&This->node), childNode, oldChild );
1186 static HRESULT WINAPI domdoc_appendChild(
1187 IXMLDOMDocument3 *iface,
1188 IXMLDOMNode* newChild,
1189 IXMLDOMNode** outNewChild)
1191 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1192 return IXMLDOMNode_appendChild( IXMLDOMNode_from_impl(&This->node), newChild, outNewChild );
1196 static HRESULT WINAPI domdoc_hasChildNodes(
1197 IXMLDOMDocument3 *iface,
1198 VARIANT_BOOL* hasChild)
1200 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1201 return IXMLDOMNode_hasChildNodes( IXMLDOMNode_from_impl(&This->node), hasChild );
1205 static HRESULT WINAPI domdoc_get_ownerDocument(
1206 IXMLDOMDocument3 *iface,
1207 IXMLDOMDocument** DOMDocument)
1209 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1210 return IXMLDOMNode_get_ownerDocument( IXMLDOMNode_from_impl(&This->node), DOMDocument );
1214 static HRESULT WINAPI domdoc_cloneNode(
1215 IXMLDOMDocument3 *iface,
1216 VARIANT_BOOL deep,
1217 IXMLDOMNode** outNode)
1219 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1220 TRACE("(%p)->(%d %p)\n", This, deep, outNode);
1221 return node_clone( &This->node, deep, outNode );
1225 static HRESULT WINAPI domdoc_get_nodeTypeString(
1226 IXMLDOMDocument3 *iface,
1227 BSTR *p)
1229 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1230 static const WCHAR documentW[] = {'d','o','c','u','m','e','n','t',0};
1232 TRACE("(%p)->(%p)\n", This, p);
1234 return return_bstr(documentW, p);
1238 static HRESULT WINAPI domdoc_get_text(
1239 IXMLDOMDocument3 *iface,
1240 BSTR* text )
1242 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1243 return IXMLDOMNode_get_text( IXMLDOMNode_from_impl(&This->node), text );
1247 static HRESULT WINAPI domdoc_put_text(
1248 IXMLDOMDocument3 *iface,
1249 BSTR text )
1251 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1252 TRACE("(%p)->(%s)\n", This, debugstr_w(text));
1253 return E_FAIL;
1257 static HRESULT WINAPI domdoc_get_specified(
1258 IXMLDOMDocument3 *iface,
1259 VARIANT_BOOL* isSpecified )
1261 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1262 FIXME("(%p)->(%p) stub!\n", This, isSpecified);
1263 *isSpecified = VARIANT_TRUE;
1264 return S_OK;
1268 static HRESULT WINAPI domdoc_get_definition(
1269 IXMLDOMDocument3 *iface,
1270 IXMLDOMNode** definitionNode )
1272 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1273 FIXME("(%p)->(%p)\n", This, definitionNode);
1274 return E_NOTIMPL;
1278 static HRESULT WINAPI domdoc_get_nodeTypedValue(
1279 IXMLDOMDocument3 *iface,
1280 VARIANT* typedValue )
1282 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1283 FIXME("(%p)->(%p)\n", This, typedValue);
1284 return return_null_var(typedValue);
1287 static HRESULT WINAPI domdoc_put_nodeTypedValue(
1288 IXMLDOMDocument3 *iface,
1289 VARIANT typedValue )
1291 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1292 FIXME("(%p)->(%s)\n", This, debugstr_variant(&typedValue));
1293 return E_NOTIMPL;
1297 static HRESULT WINAPI domdoc_get_dataType(
1298 IXMLDOMDocument3 *iface,
1299 VARIANT* typename )
1301 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1302 TRACE("(%p)->(%p)\n", This, typename);
1303 return return_null_var( typename );
1307 static HRESULT WINAPI domdoc_put_dataType(
1308 IXMLDOMDocument3 *iface,
1309 BSTR dataTypeName )
1311 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1313 FIXME("(%p)->(%s)\n", This, debugstr_w(dataTypeName));
1315 if(!dataTypeName)
1316 return E_INVALIDARG;
1318 return E_FAIL;
1321 static int XMLCALL domdoc_get_xml_writecallback(void *ctx, const char *data, int len)
1323 return xmlBufferAdd((xmlBufferPtr)ctx, (xmlChar*)data, len) == 0 ? len : 0;
1326 static HRESULT WINAPI domdoc_get_xml(
1327 IXMLDOMDocument3 *iface,
1328 BSTR* p)
1330 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1331 xmlSaveCtxtPtr ctxt;
1332 xmlBufferPtr buf;
1333 int options;
1334 long ret;
1336 TRACE("(%p)->(%p)\n", This, p);
1338 if(!p)
1339 return E_INVALIDARG;
1341 *p = NULL;
1343 buf = xmlBufferCreate();
1344 if(!buf)
1345 return E_OUTOFMEMORY;
1347 options = xmldoc_has_decl(get_doc(This)) ? XML_SAVE_NO_DECL : 0;
1348 options |= XML_SAVE_FORMAT;
1349 ctxt = xmlSaveToIO(domdoc_get_xml_writecallback, NULL, buf, "UTF-8", options);
1351 if(!ctxt)
1353 xmlBufferFree(buf);
1354 return E_OUTOFMEMORY;
1357 ret = xmlSaveDoc(ctxt, get_doc(This));
1358 /* flushes on close */
1359 xmlSaveClose(ctxt);
1361 TRACE("%ld, len=%d\n", ret, xmlBufferLength(buf));
1362 if(ret != -1 && xmlBufferLength(buf) > 0)
1364 BSTR content;
1366 content = bstr_from_xmlChar(xmlBufferContent(buf));
1367 content = EnsureCorrectEOL(content);
1369 *p = content;
1371 else
1373 *p = SysAllocStringLen(NULL, 0);
1376 xmlBufferFree(buf);
1378 return *p ? S_OK : E_OUTOFMEMORY;
1382 static HRESULT WINAPI domdoc_transformNode(
1383 IXMLDOMDocument3 *iface,
1384 IXMLDOMNode* styleSheet,
1385 BSTR* xmlString )
1387 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1388 return IXMLDOMNode_transformNode( IXMLDOMNode_from_impl(&This->node), styleSheet, xmlString );
1392 static HRESULT WINAPI domdoc_selectNodes(
1393 IXMLDOMDocument3 *iface,
1394 BSTR queryString,
1395 IXMLDOMNodeList** resultList )
1397 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1398 return IXMLDOMNode_selectNodes( IXMLDOMNode_from_impl(&This->node), queryString, resultList );
1402 static HRESULT WINAPI domdoc_selectSingleNode(
1403 IXMLDOMDocument3 *iface,
1404 BSTR queryString,
1405 IXMLDOMNode** resultNode )
1407 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1408 return IXMLDOMNode_selectSingleNode( IXMLDOMNode_from_impl(&This->node), queryString, resultNode );
1412 static HRESULT WINAPI domdoc_get_parsed(
1413 IXMLDOMDocument3 *iface,
1414 VARIANT_BOOL* isParsed )
1416 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1417 FIXME("(%p)->(%p) stub!\n", This, isParsed);
1418 *isParsed = VARIANT_TRUE;
1419 return S_OK;
1423 static HRESULT WINAPI domdoc_get_namespaceURI(
1424 IXMLDOMDocument3 *iface,
1425 BSTR* namespaceURI )
1427 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1428 TRACE("(%p)->(%p)\n", This, namespaceURI);
1429 return node_get_namespaceURI(&This->node, namespaceURI);
1433 static HRESULT WINAPI domdoc_get_prefix(
1434 IXMLDOMDocument3 *iface,
1435 BSTR* prefix )
1437 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1438 TRACE("(%p)->(%p)\n", This, prefix);
1439 return return_null_bstr( prefix );
1443 static HRESULT WINAPI domdoc_get_baseName(
1444 IXMLDOMDocument3 *iface,
1445 BSTR* name )
1447 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1448 TRACE("(%p)->(%p)\n", This, name);
1449 return return_null_bstr( name );
1453 static HRESULT WINAPI domdoc_transformNodeToObject(
1454 IXMLDOMDocument3 *iface,
1455 IXMLDOMNode* stylesheet,
1456 VARIANT outputObject)
1458 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1459 FIXME("(%p)->(%p %s)\n", This, stylesheet, debugstr_variant(&outputObject));
1460 return E_NOTIMPL;
1464 static HRESULT WINAPI domdoc_get_doctype(
1465 IXMLDOMDocument3 *iface,
1466 IXMLDOMDocumentType** documentType )
1468 domdoc *This = impl_from_IXMLDOMDocument3(iface);
1469 FIXME("(%p)\n", This);
1470 return E_NOTIMPL;
1474 static HRESULT WINAPI domdoc_get_implementation(
1475 IXMLDOMDocument3 *iface,
1476 IXMLDOMImplementation** impl )
1478 domdoc *This = impl_from_IXMLDOMDocument3(iface);
1480 TRACE("(%p)->(%p)\n", This, impl);
1482 if(!impl)
1483 return E_INVALIDARG;
1485 *impl = (IXMLDOMImplementation*)create_doc_Implementation();
1487 return S_OK;
1490 static HRESULT WINAPI domdoc_get_documentElement(
1491 IXMLDOMDocument3 *iface,
1492 IXMLDOMElement** DOMElement )
1494 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1495 IXMLDOMNode *element_node;
1496 xmlNodePtr root;
1497 HRESULT hr;
1499 TRACE("(%p)->(%p)\n", This, DOMElement);
1501 if(!DOMElement)
1502 return E_INVALIDARG;
1504 *DOMElement = NULL;
1506 root = xmlDocGetRootElement( get_doc(This) );
1507 if ( !root )
1508 return S_FALSE;
1510 element_node = create_node( root );
1511 if(!element_node) return S_FALSE;
1513 hr = IXMLDOMNode_QueryInterface(element_node, &IID_IXMLDOMElement, (void**)DOMElement);
1514 IXMLDOMNode_Release(element_node);
1516 return hr;
1520 static HRESULT WINAPI domdoc_put_documentElement(
1521 IXMLDOMDocument3 *iface,
1522 IXMLDOMElement* DOMElement )
1524 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1525 IXMLDOMNode *elementNode;
1526 xmlNodePtr oldRoot;
1527 xmlnode *xmlNode;
1528 HRESULT hr;
1530 TRACE("(%p)->(%p)\n", This, DOMElement);
1532 hr = IXMLDOMElement_QueryInterface( DOMElement, &IID_IXMLDOMNode, (void**)&elementNode );
1533 if(FAILED(hr))
1534 return hr;
1536 xmlNode = get_node_obj( elementNode );
1537 if(!xmlNode) {
1538 FIXME("elementNode is not our object\n");
1539 return E_FAIL;
1542 if(!xmlNode->node->parent)
1543 if(xmldoc_remove_orphan(xmlNode->node->doc, xmlNode->node) != S_OK)
1544 WARN("%p is not an orphan of %p\n", xmlNode->node->doc, xmlNode->node);
1546 oldRoot = xmlDocSetRootElement( get_doc(This), xmlNode->node);
1547 IXMLDOMNode_Release( elementNode );
1549 if(oldRoot)
1550 xmldoc_add_orphan(oldRoot->doc, oldRoot);
1552 return S_OK;
1556 static HRESULT WINAPI domdoc_createElement(
1557 IXMLDOMDocument3 *iface,
1558 BSTR tagname,
1559 IXMLDOMElement** element )
1561 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1562 IXMLDOMNode *node;
1563 VARIANT type;
1564 HRESULT hr;
1566 TRACE("(%p)->(%s %p)\n", This, debugstr_w(tagname), element);
1568 if (!element || !tagname) return E_INVALIDARG;
1570 V_VT(&type) = VT_I1;
1571 V_I1(&type) = NODE_ELEMENT;
1573 hr = IXMLDOMDocument3_createNode(iface, type, tagname, NULL, &node);
1574 if (hr == S_OK)
1576 IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMElement, (void**)element);
1577 IXMLDOMNode_Release(node);
1580 return hr;
1584 static HRESULT WINAPI domdoc_createDocumentFragment(
1585 IXMLDOMDocument3 *iface,
1586 IXMLDOMDocumentFragment** frag )
1588 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1589 IXMLDOMNode *node;
1590 VARIANT type;
1591 HRESULT hr;
1593 TRACE("(%p)->(%p)\n", This, frag);
1595 if (!frag) return E_INVALIDARG;
1597 *frag = NULL;
1599 V_VT(&type) = VT_I1;
1600 V_I1(&type) = NODE_DOCUMENT_FRAGMENT;
1602 hr = IXMLDOMDocument3_createNode(iface, type, NULL, NULL, &node);
1603 if (hr == S_OK)
1605 IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMDocumentFragment, (void**)frag);
1606 IXMLDOMNode_Release(node);
1609 return hr;
1613 static HRESULT WINAPI domdoc_createTextNode(
1614 IXMLDOMDocument3 *iface,
1615 BSTR data,
1616 IXMLDOMText** text )
1618 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1619 IXMLDOMNode *node;
1620 VARIANT type;
1621 HRESULT hr;
1623 TRACE("(%p)->(%s %p)\n", This, debugstr_w(data), text);
1625 if (!text) return E_INVALIDARG;
1627 *text = NULL;
1629 V_VT(&type) = VT_I1;
1630 V_I1(&type) = NODE_TEXT;
1632 hr = IXMLDOMDocument3_createNode(iface, type, NULL, NULL, &node);
1633 if (hr == S_OK)
1635 IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMText, (void**)text);
1636 IXMLDOMNode_Release(node);
1637 hr = IXMLDOMText_put_data(*text, data);
1640 return hr;
1644 static HRESULT WINAPI domdoc_createComment(
1645 IXMLDOMDocument3 *iface,
1646 BSTR data,
1647 IXMLDOMComment** comment )
1649 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1650 VARIANT type;
1651 HRESULT hr;
1652 IXMLDOMNode *node;
1654 TRACE("(%p)->(%s %p)\n", This, debugstr_w(data), comment);
1656 if (!comment) return E_INVALIDARG;
1658 *comment = NULL;
1660 V_VT(&type) = VT_I1;
1661 V_I1(&type) = NODE_COMMENT;
1663 hr = IXMLDOMDocument3_createNode(iface, type, NULL, NULL, &node);
1664 if (hr == S_OK)
1666 IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMComment, (void**)comment);
1667 IXMLDOMNode_Release(node);
1668 hr = IXMLDOMComment_put_data(*comment, data);
1671 return hr;
1675 static HRESULT WINAPI domdoc_createCDATASection(
1676 IXMLDOMDocument3 *iface,
1677 BSTR data,
1678 IXMLDOMCDATASection** cdata )
1680 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1681 IXMLDOMNode *node;
1682 VARIANT type;
1683 HRESULT hr;
1685 TRACE("(%p)->(%s %p)\n", This, debugstr_w(data), cdata);
1687 if (!cdata) return E_INVALIDARG;
1689 *cdata = NULL;
1691 V_VT(&type) = VT_I1;
1692 V_I1(&type) = NODE_CDATA_SECTION;
1694 hr = IXMLDOMDocument3_createNode(iface, type, NULL, NULL, &node);
1695 if (hr == S_OK)
1697 IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMCDATASection, (void**)cdata);
1698 IXMLDOMNode_Release(node);
1699 hr = IXMLDOMCDATASection_put_data(*cdata, data);
1702 return hr;
1706 static HRESULT WINAPI domdoc_createProcessingInstruction(
1707 IXMLDOMDocument3 *iface,
1708 BSTR target,
1709 BSTR data,
1710 IXMLDOMProcessingInstruction** pi )
1712 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1713 IXMLDOMNode *node;
1714 VARIANT type;
1715 HRESULT hr;
1717 TRACE("(%p)->(%s %s %p)\n", This, debugstr_w(target), debugstr_w(data), pi);
1719 if (!pi) return E_INVALIDARG;
1721 *pi = NULL;
1723 V_VT(&type) = VT_I1;
1724 V_I1(&type) = NODE_PROCESSING_INSTRUCTION;
1726 hr = IXMLDOMDocument3_createNode(iface, type, target, NULL, &node);
1727 if (hr == S_OK)
1729 xmlnode *node_obj;
1731 /* this is to bypass check in ::put_data() that blocks "<?xml" PIs */
1732 node_obj = get_node_obj(node);
1733 hr = node_set_content(node_obj, data);
1735 IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMProcessingInstruction, (void**)pi);
1736 IXMLDOMNode_Release(node);
1739 return hr;
1743 static HRESULT WINAPI domdoc_createAttribute(
1744 IXMLDOMDocument3 *iface,
1745 BSTR name,
1746 IXMLDOMAttribute** attribute )
1748 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1749 IXMLDOMNode *node;
1750 VARIANT type;
1751 HRESULT hr;
1753 TRACE("(%p)->(%s %p)\n", This, debugstr_w(name), attribute);
1755 if (!attribute || !name) return E_INVALIDARG;
1757 V_VT(&type) = VT_I1;
1758 V_I1(&type) = NODE_ATTRIBUTE;
1760 hr = IXMLDOMDocument3_createNode(iface, type, name, NULL, &node);
1761 if (hr == S_OK)
1763 IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMAttribute, (void**)attribute);
1764 IXMLDOMNode_Release(node);
1767 return hr;
1771 static HRESULT WINAPI domdoc_createEntityReference(
1772 IXMLDOMDocument3 *iface,
1773 BSTR name,
1774 IXMLDOMEntityReference** entityref )
1776 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1777 IXMLDOMNode *node;
1778 VARIANT type;
1779 HRESULT hr;
1781 TRACE("(%p)->(%s %p)\n", This, debugstr_w(name), entityref);
1783 if (!entityref) return E_INVALIDARG;
1785 *entityref = NULL;
1787 V_VT(&type) = VT_I1;
1788 V_I1(&type) = NODE_ENTITY_REFERENCE;
1790 hr = IXMLDOMDocument3_createNode(iface, type, name, NULL, &node);
1791 if (hr == S_OK)
1793 IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMEntityReference, (void**)entityref);
1794 IXMLDOMNode_Release(node);
1797 return hr;
1800 xmlChar* tagName_to_XPath(const BSTR tagName)
1802 xmlChar *query, *tmp;
1803 static const xmlChar mod_pre[] = "*[local-name()='";
1804 static const xmlChar mod_post[] = "']";
1805 static const xmlChar prefix[] = "descendant::";
1806 const WCHAR *tokBegin, *tokEnd;
1807 int len;
1809 query = xmlStrdup(prefix);
1811 tokBegin = tagName;
1812 while (tokBegin && *tokBegin)
1814 switch (*tokBegin)
1816 case '/':
1817 query = xmlStrcat(query, BAD_CAST "/");
1818 ++tokBegin;
1819 break;
1820 case '*':
1821 query = xmlStrcat(query, BAD_CAST "*");
1822 ++tokBegin;
1823 break;
1824 default:
1825 query = xmlStrcat(query, mod_pre);
1826 tokEnd = tokBegin;
1827 while (*tokEnd && *tokEnd != '/')
1828 ++tokEnd;
1829 len = WideCharToMultiByte(CP_UTF8, 0, tokBegin, tokEnd-tokBegin, NULL, 0, NULL, NULL);
1830 tmp = xmlMalloc(len);
1831 WideCharToMultiByte(CP_UTF8, 0, tokBegin, tokEnd-tokBegin, (char*)tmp, len, NULL, NULL);
1832 query = xmlStrncat(query, tmp, len);
1833 xmlFree(tmp);
1834 tokBegin = tokEnd;
1835 query = xmlStrcat(query, mod_post);
1839 return query;
1842 static HRESULT WINAPI domdoc_getElementsByTagName(
1843 IXMLDOMDocument3 *iface,
1844 BSTR tagName,
1845 IXMLDOMNodeList** resultList )
1847 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1848 xmlChar *query;
1849 HRESULT hr;
1850 BOOL XPath;
1852 TRACE("(%p)->(%s, %p)\n", This, debugstr_w(tagName), resultList);
1854 if (!tagName || !resultList) return E_INVALIDARG;
1856 XPath = This->properties->XPath;
1857 This->properties->XPath = TRUE;
1858 query = tagName_to_XPath(tagName);
1859 hr = queryresult_create((xmlNodePtr)get_doc(This), query, resultList);
1860 xmlFree(query);
1861 This->properties->XPath = XPath;
1863 return hr;
1866 static HRESULT get_node_type(VARIANT Type, DOMNodeType * type)
1868 VARIANT tmp;
1869 HRESULT hr;
1871 VariantInit(&tmp);
1872 hr = VariantChangeType(&tmp, &Type, 0, VT_I4);
1873 if(FAILED(hr))
1874 return E_INVALIDARG;
1876 *type = V_I4(&tmp);
1878 return S_OK;
1881 static HRESULT WINAPI domdoc_createNode(
1882 IXMLDOMDocument3 *iface,
1883 VARIANT Type,
1884 BSTR name,
1885 BSTR namespaceURI,
1886 IXMLDOMNode** node )
1888 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1889 DOMNodeType node_type;
1890 xmlNodePtr xmlnode;
1891 xmlChar *xml_name, *href;
1892 HRESULT hr;
1894 TRACE("(%p)->(%s %s %p)\n", This, debugstr_w(name), debugstr_w(namespaceURI), node);
1896 if(!node) return E_INVALIDARG;
1898 hr = get_node_type(Type, &node_type);
1899 if(FAILED(hr)) return hr;
1901 if(namespaceURI && namespaceURI[0] && node_type != NODE_ELEMENT)
1902 FIXME("nodes with namespaces currently not supported.\n");
1904 TRACE("node_type %d\n", node_type);
1906 /* exit earlier for types that need name */
1907 switch(node_type)
1909 case NODE_ELEMENT:
1910 case NODE_ATTRIBUTE:
1911 case NODE_ENTITY_REFERENCE:
1912 case NODE_PROCESSING_INSTRUCTION:
1913 if (!name || *name == 0) return E_FAIL;
1914 default:
1915 break;
1918 xml_name = xmlChar_from_wchar(name);
1919 /* prevent empty href to be allocated */
1920 href = namespaceURI ? xmlChar_from_wchar(namespaceURI) : NULL;
1922 switch(node_type)
1924 case NODE_ELEMENT:
1926 xmlChar *local, *prefix;
1928 local = xmlSplitQName2(xml_name, &prefix);
1930 xmlnode = xmlNewDocNode(get_doc(This), NULL, local ? local : xml_name, NULL);
1932 /* allow to create default namespace xmlns= */
1933 if (local || (href && *href))
1935 xmlNsPtr ns = xmlNewNs(xmlnode, href, prefix);
1936 xmlSetNs(xmlnode, ns);
1939 xmlFree(local);
1940 xmlFree(prefix);
1942 break;
1944 case NODE_ATTRIBUTE:
1945 xmlnode = (xmlNodePtr)xmlNewDocProp(get_doc(This), xml_name, NULL);
1946 break;
1947 case NODE_TEXT:
1948 xmlnode = (xmlNodePtr)xmlNewDocText(get_doc(This), NULL);
1949 break;
1950 case NODE_CDATA_SECTION:
1951 xmlnode = xmlNewCDataBlock(get_doc(This), NULL, 0);
1952 break;
1953 case NODE_ENTITY_REFERENCE:
1954 xmlnode = xmlNewReference(get_doc(This), xml_name);
1955 break;
1956 case NODE_PROCESSING_INSTRUCTION:
1957 #ifdef HAVE_XMLNEWDOCPI
1958 xmlnode = xmlNewDocPI(get_doc(This), xml_name, NULL);
1959 #else
1960 FIXME("xmlNewDocPI() not supported, use libxml2 2.6.15 or greater\n");
1961 xmlnode = NULL;
1962 #endif
1963 break;
1964 case NODE_COMMENT:
1965 xmlnode = xmlNewDocComment(get_doc(This), NULL);
1966 break;
1967 case NODE_DOCUMENT_FRAGMENT:
1968 xmlnode = xmlNewDocFragment(get_doc(This));
1969 break;
1970 /* unsupported types */
1971 case NODE_DOCUMENT:
1972 case NODE_DOCUMENT_TYPE:
1973 case NODE_ENTITY:
1974 case NODE_NOTATION:
1975 heap_free(xml_name);
1976 return E_INVALIDARG;
1977 default:
1978 FIXME("unhandled node type %d\n", node_type);
1979 xmlnode = NULL;
1980 break;
1983 *node = create_node(xmlnode);
1984 heap_free(xml_name);
1985 heap_free(href);
1987 if(*node)
1989 TRACE("created node (%d, %p, %p)\n", node_type, *node, xmlnode);
1990 xmldoc_add_orphan(xmlnode->doc, xmlnode);
1991 return S_OK;
1994 return E_FAIL;
1997 static HRESULT WINAPI domdoc_nodeFromID(
1998 IXMLDOMDocument3 *iface,
1999 BSTR idString,
2000 IXMLDOMNode** node )
2002 domdoc *This = impl_from_IXMLDOMDocument3(iface);
2003 FIXME("(%p)->(%s %p)\n", This, debugstr_w(idString), node);
2004 return E_NOTIMPL;
2007 static HRESULT domdoc_onDataAvailable(void *obj, char *ptr, DWORD len)
2009 domdoc *This = obj;
2010 xmlDocPtr xmldoc;
2012 xmldoc = doparse(This, ptr, len, NULL);
2013 if(xmldoc) {
2014 xmldoc->_private = create_priv();
2015 return attach_xmldoc(This, xmldoc);
2018 return S_OK;
2021 static HRESULT doread( domdoc *This, LPWSTR filename )
2023 bsc_t *bsc;
2024 HRESULT hr;
2026 hr = bind_url(filename, domdoc_onDataAvailable, This, &bsc);
2027 if(FAILED(hr))
2028 return hr;
2030 if(This->bsc)
2031 detach_bsc(This->bsc);
2033 This->bsc = bsc;
2034 return S_OK;
2037 static HRESULT WINAPI domdoc_load(
2038 IXMLDOMDocument3 *iface,
2039 VARIANT xmlSource,
2040 VARIANT_BOOL* isSuccessful )
2042 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2043 LPWSTR filename = NULL;
2044 HRESULT hr = S_FALSE;
2045 IXMLDOMDocument3 *pNewDoc = NULL;
2046 IStream *pStream = NULL;
2047 xmlDocPtr xmldoc;
2049 TRACE("(%p)->type %d\n", This, V_VT(&xmlSource) );
2051 *isSuccessful = VARIANT_FALSE;
2053 assert( &This->node );
2055 switch( V_VT(&xmlSource) )
2057 case VT_BSTR:
2058 filename = V_BSTR(&xmlSource);
2059 break;
2060 case VT_UNKNOWN:
2061 hr = IUnknown_QueryInterface(V_UNKNOWN(&xmlSource), &IID_IXMLDOMDocument3, (void**)&pNewDoc);
2062 if(hr == S_OK)
2064 if(pNewDoc)
2066 domdoc *newDoc = impl_from_IXMLDOMDocument3( pNewDoc );
2067 xmldoc = xmlCopyDoc(get_doc(newDoc), 1);
2068 hr = attach_xmldoc(This, xmldoc);
2070 if(SUCCEEDED(hr))
2071 *isSuccessful = VARIANT_TRUE;
2073 return hr;
2076 hr = IUnknown_QueryInterface(V_UNKNOWN(&xmlSource), &IID_IStream, (void**)&pStream);
2077 if(hr == S_OK)
2079 IPersistStream *pDocStream;
2080 hr = IUnknown_QueryInterface(iface, &IID_IPersistStream, (void**)&pDocStream);
2081 if(hr == S_OK)
2083 hr = IPersistStream_Load(pDocStream, pStream);
2084 IStream_Release(pStream);
2085 if(hr == S_OK)
2087 *isSuccessful = VARIANT_TRUE;
2089 TRACE("Using IStream to load Document\n");
2090 return S_OK;
2092 else
2094 ERR("xmldoc_IPersistStream_Load failed (%d)\n", hr);
2097 else
2099 ERR("QueryInterface IID_IPersistStream failed (%d)\n", hr);
2102 else
2104 /* ISequentialStream */
2105 FIXME("Unknown type not supported (%d) (%p)(%p)\n", hr, pNewDoc, V_UNKNOWN(&xmlSource)->lpVtbl);
2107 break;
2108 default:
2109 FIXME("VT type not supported (%d)\n", V_VT(&xmlSource));
2112 TRACE("filename (%s)\n", debugstr_w(filename));
2114 if ( filename )
2116 hr = doread( This, filename );
2118 if ( FAILED(hr) )
2119 This->error = E_FAIL;
2120 else
2122 hr = This->error = S_OK;
2123 *isSuccessful = VARIANT_TRUE;
2127 if(!filename || FAILED(hr)) {
2128 xmldoc = xmlNewDoc(NULL);
2129 xmldoc->_private = create_priv();
2130 hr = attach_xmldoc(This, xmldoc);
2131 if(SUCCEEDED(hr))
2132 hr = S_FALSE;
2135 TRACE("ret (%d)\n", hr);
2137 return hr;
2141 static HRESULT WINAPI domdoc_get_readyState(
2142 IXMLDOMDocument3 *iface,
2143 LONG *value )
2145 domdoc *This = impl_from_IXMLDOMDocument3(iface);
2146 FIXME("stub! (%p)->(%p)\n", This, value);
2148 if (!value)
2149 return E_INVALIDARG;
2151 *value = READYSTATE_COMPLETE;
2152 return S_OK;
2156 static HRESULT WINAPI domdoc_get_parseError(
2157 IXMLDOMDocument3 *iface,
2158 IXMLDOMParseError** errorObj )
2160 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2161 static const WCHAR err[] = {'e','r','r','o','r',0};
2162 BSTR error_string = NULL;
2164 FIXME("(%p)->(%p): creating a dummy parseError\n", iface, errorObj);
2166 if(This->error)
2167 error_string = SysAllocString(err);
2169 *errorObj = create_parseError(This->error, NULL, error_string, NULL, 0, 0, 0);
2170 if(!*errorObj) return E_OUTOFMEMORY;
2171 return S_OK;
2175 static HRESULT WINAPI domdoc_get_url(
2176 IXMLDOMDocument3 *iface,
2177 BSTR* urlString )
2179 domdoc *This = impl_from_IXMLDOMDocument3(iface);
2180 FIXME("(%p)->(%p)\n", This, urlString);
2181 return E_NOTIMPL;
2185 static HRESULT WINAPI domdoc_get_async(
2186 IXMLDOMDocument3 *iface,
2187 VARIANT_BOOL* isAsync )
2189 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2191 TRACE("(%p)->(%p: %d)\n", This, isAsync, This->async);
2192 *isAsync = This->async;
2193 return S_OK;
2197 static HRESULT WINAPI domdoc_put_async(
2198 IXMLDOMDocument3 *iface,
2199 VARIANT_BOOL isAsync )
2201 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2203 TRACE("(%p)->(%d)\n", This, isAsync);
2204 This->async = isAsync;
2205 return S_OK;
2209 static HRESULT WINAPI domdoc_abort(
2210 IXMLDOMDocument3 *iface )
2212 domdoc *This = impl_from_IXMLDOMDocument3(iface);
2213 FIXME("%p\n", This);
2214 return E_NOTIMPL;
2218 static BOOL bstr_to_utf8( BSTR bstr, char **pstr, int *plen )
2220 UINT len;
2221 LPSTR str;
2223 len = WideCharToMultiByte( CP_UTF8, 0, bstr, -1, NULL, 0, NULL, NULL );
2224 str = heap_alloc( len );
2225 if ( !str )
2226 return FALSE;
2227 WideCharToMultiByte( CP_UTF8, 0, bstr, -1, str, len, NULL, NULL );
2228 *plen = len;
2229 *pstr = str;
2230 return TRUE;
2233 /* don't rely on data to be in BSTR format, treat it as WCHAR string */
2234 static HRESULT WINAPI domdoc_loadXML(
2235 IXMLDOMDocument3 *iface,
2236 BSTR bstrXML,
2237 VARIANT_BOOL* isSuccessful )
2239 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2240 static const xmlChar encoding[] = "UTF-8";
2241 xmlDocPtr xmldoc = NULL;
2242 HRESULT hr = S_FALSE, hr2;
2243 char *str;
2244 int len;
2246 TRACE("(%p)->(%s %p)\n", This, debugstr_w( bstrXML ), isSuccessful );
2248 assert ( &This->node );
2250 if ( isSuccessful )
2252 *isSuccessful = VARIANT_FALSE;
2254 if ( bstrXML && bstr_to_utf8( bstrXML, &str, &len ) )
2256 xmldoc = doparse(This, str, len, encoding);
2257 heap_free( str );
2258 if ( !xmldoc )
2260 This->error = E_FAIL;
2261 TRACE("failed to parse document\n");
2263 else
2265 hr = This->error = S_OK;
2266 *isSuccessful = VARIANT_TRUE;
2267 TRACE("parsed document %p\n", xmldoc);
2271 if(!xmldoc)
2272 xmldoc = xmlNewDoc(NULL);
2274 xmldoc->_private = create_priv();
2276 hr2 = attach_xmldoc(This, xmldoc);
2277 if( FAILED(hr2) )
2278 hr = hr2;
2280 return hr;
2283 static int XMLCALL domdoc_save_writecallback(void *ctx, const char *buffer, int len)
2285 DWORD written = -1;
2287 if(!WriteFile(ctx, buffer, len, &written, NULL))
2289 WARN("write error\n");
2290 return -1;
2292 else
2293 return written;
2296 static int XMLCALL domdoc_save_closecallback(void *ctx)
2298 return CloseHandle(ctx) ? 0 : -1;
2301 static int XMLCALL domdoc_stream_save_writecallback(void *ctx, const char *buffer, int len)
2303 ULONG written = 0;
2304 HRESULT hr;
2306 hr = IStream_Write((IStream*)ctx, buffer, len, &written);
2307 if (hr != S_OK)
2309 WARN("stream write error: 0x%08x\n", hr);
2310 return -1;
2312 else
2313 return written;
2316 static int XMLCALL domdoc_stream_save_closecallback(void *ctx)
2318 IStream_Release((IStream*)ctx);
2319 return 0;
2322 static HRESULT WINAPI domdoc_save(
2323 IXMLDOMDocument3 *iface,
2324 VARIANT destination )
2326 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2327 xmlSaveCtxtPtr ctx = NULL;
2328 xmlNodePtr xmldecl;
2329 HRESULT ret = S_OK;
2331 TRACE("(%p)->(var(vt %d, %s))\n", This, V_VT(&destination),
2332 V_VT(&destination) == VT_BSTR ? debugstr_w(V_BSTR(&destination)) : NULL);
2334 if(V_VT(&destination) != VT_BSTR && V_VT(&destination) != VT_UNKNOWN)
2336 FIXME("Unhandled vt %d\n", V_VT(&destination));
2337 return S_FALSE;
2340 if(V_VT(&destination) == VT_UNKNOWN)
2342 IUnknown *pUnk = V_UNKNOWN(&destination);
2343 IXMLDOMDocument2 *document;
2344 IStream *stream;
2346 ret = IUnknown_QueryInterface(pUnk, &IID_IXMLDOMDocument3, (void**)&document);
2347 if(ret == S_OK)
2349 VARIANT_BOOL success;
2350 BSTR xml;
2352 ret = IXMLDOMDocument3_get_xml(iface, &xml);
2353 if(ret == S_OK)
2355 ret = IXMLDOMDocument3_loadXML(document, xml, &success);
2356 SysFreeString(xml);
2359 IXMLDOMDocument3_Release(document);
2360 return ret;
2363 ret = IUnknown_QueryInterface(pUnk, &IID_IStream, (void**)&stream);
2364 if(ret == S_OK)
2366 ctx = xmlSaveToIO(domdoc_stream_save_writecallback,
2367 domdoc_stream_save_closecallback, stream, NULL, XML_SAVE_NO_DECL);
2369 if(!ctx)
2371 IStream_Release(stream);
2372 return E_FAIL;
2376 else
2378 /* save with file path */
2379 HANDLE handle = CreateFileW( V_BSTR(&destination), GENERIC_WRITE, 0,
2380 NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL );
2381 if( handle == INVALID_HANDLE_VALUE )
2383 WARN("failed to create file\n");
2384 return E_FAIL;
2387 /* disable top XML declaration */
2388 ctx = xmlSaveToIO(domdoc_save_writecallback, domdoc_save_closecallback,
2389 handle, NULL, XML_SAVE_NO_DECL);
2390 if (!ctx)
2392 CloseHandle(handle);
2393 return E_FAIL;
2397 xmldecl = xmldoc_unlink_xmldecl(get_doc(This));
2398 if (xmlSaveDoc(ctx, get_doc(This)) == -1) ret = S_FALSE;
2399 xmldoc_link_xmldecl(get_doc(This), xmldecl);
2401 /* will release resources through close callback */
2402 xmlSaveClose(ctx);
2404 return ret;
2407 static HRESULT WINAPI domdoc_get_validateOnParse(
2408 IXMLDOMDocument3 *iface,
2409 VARIANT_BOOL* isValidating )
2411 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2412 TRACE("(%p)->(%p: %d)\n", This, isValidating, This->validating);
2413 *isValidating = This->validating;
2414 return S_OK;
2418 static HRESULT WINAPI domdoc_put_validateOnParse(
2419 IXMLDOMDocument3 *iface,
2420 VARIANT_BOOL isValidating )
2422 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2423 TRACE("(%p)->(%d)\n", This, isValidating);
2424 This->validating = isValidating;
2425 return S_OK;
2429 static HRESULT WINAPI domdoc_get_resolveExternals(
2430 IXMLDOMDocument3 *iface,
2431 VARIANT_BOOL* isResolving )
2433 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2434 TRACE("(%p)->(%p: %d)\n", This, isResolving, This->resolving);
2435 *isResolving = This->resolving;
2436 return S_OK;
2440 static HRESULT WINAPI domdoc_put_resolveExternals(
2441 IXMLDOMDocument3 *iface,
2442 VARIANT_BOOL isResolving )
2444 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2445 TRACE("(%p)->(%d)\n", This, isResolving);
2446 This->resolving = isResolving;
2447 return S_OK;
2451 static HRESULT WINAPI domdoc_get_preserveWhiteSpace(
2452 IXMLDOMDocument3 *iface,
2453 VARIANT_BOOL* isPreserving )
2455 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2456 TRACE("(%p)->(%p: %d)\n", This, isPreserving, This->properties->preserving);
2457 *isPreserving = This->properties->preserving;
2458 return S_OK;
2462 static HRESULT WINAPI domdoc_put_preserveWhiteSpace(
2463 IXMLDOMDocument3 *iface,
2464 VARIANT_BOOL isPreserving )
2466 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2467 TRACE("(%p)->(%d)\n", This, isPreserving);
2468 This->properties->preserving = isPreserving;
2469 return S_OK;
2473 static HRESULT WINAPI domdoc_put_onReadyStateChange(
2474 IXMLDOMDocument3 *iface,
2475 VARIANT readyStateChangeSink )
2477 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2478 FIXME("%p\n", This);
2479 return E_NOTIMPL;
2483 static HRESULT WINAPI domdoc_put_onDataAvailable(
2484 IXMLDOMDocument3 *iface,
2485 VARIANT onDataAvailableSink )
2487 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2488 FIXME("%p\n", This);
2489 return E_NOTIMPL;
2492 static HRESULT WINAPI domdoc_put_onTransformNode(
2493 IXMLDOMDocument3 *iface,
2494 VARIANT onTransformNodeSink )
2496 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2497 FIXME("%p\n", This);
2498 return E_NOTIMPL;
2501 static HRESULT WINAPI domdoc_get_namespaces(
2502 IXMLDOMDocument3* iface,
2503 IXMLDOMSchemaCollection** schemaCollection )
2505 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2506 FIXME("(%p)->(%p)\n", This, schemaCollection);
2507 return E_NOTIMPL;
2510 static HRESULT WINAPI domdoc_get_schemas(
2511 IXMLDOMDocument3* iface,
2512 VARIANT* var1 )
2514 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2515 HRESULT hr = S_FALSE;
2516 IXMLDOMSchemaCollection2* cur_schema = This->properties->schemaCache;
2518 TRACE("(%p)->(%p)\n", This, var1);
2520 VariantInit(var1); /* Test shows we don't call VariantClear here */
2521 V_VT(var1) = VT_NULL;
2523 if(cur_schema)
2525 hr = IXMLDOMSchemaCollection2_QueryInterface(cur_schema, &IID_IDispatch, (void**)&V_DISPATCH(var1));
2526 if(SUCCEEDED(hr))
2527 V_VT(var1) = VT_DISPATCH;
2529 return hr;
2532 static HRESULT WINAPI domdoc_putref_schemas(
2533 IXMLDOMDocument3* iface,
2534 VARIANT var1)
2536 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2537 HRESULT hr = E_FAIL;
2538 IXMLDOMSchemaCollection2* new_schema = NULL;
2540 FIXME("(%p): semi-stub\n", This);
2541 switch(V_VT(&var1))
2543 case VT_UNKNOWN:
2544 hr = IUnknown_QueryInterface(V_UNKNOWN(&var1), &IID_IXMLDOMSchemaCollection, (void**)&new_schema);
2545 break;
2547 case VT_DISPATCH:
2548 hr = IDispatch_QueryInterface(V_DISPATCH(&var1), &IID_IXMLDOMSchemaCollection, (void**)&new_schema);
2549 break;
2551 case VT_NULL:
2552 case VT_EMPTY:
2553 hr = S_OK;
2554 break;
2556 default:
2557 WARN("Can't get schema from vt %x\n", V_VT(&var1));
2560 if(SUCCEEDED(hr))
2562 IXMLDOMSchemaCollection2* old_schema = InterlockedExchangePointer((void**)&This->properties->schemaCache, new_schema);
2563 if(old_schema) IXMLDOMSchemaCollection2_Release(old_schema);
2566 return hr;
2569 static inline BOOL is_wellformed(xmlDocPtr doc)
2571 #ifdef HAVE_XMLDOC_PROPERTIES
2572 return doc->properties & XML_DOC_WELLFORMED;
2573 #else
2574 /* Not a full check, but catches the worst violations */
2575 xmlNodePtr child;
2576 int root = 0;
2578 for (child = doc->children; child != NULL; child = child->next)
2580 switch (child->type)
2582 case XML_ELEMENT_NODE:
2583 if (++root > 1)
2584 return FALSE;
2585 break;
2586 case XML_TEXT_NODE:
2587 case XML_CDATA_SECTION_NODE:
2588 return FALSE;
2589 break;
2590 default:
2591 break;
2595 return root == 1;
2596 #endif
2599 static void LIBXML2_LOG_CALLBACK validate_error(void* ctx, char const* msg, ...)
2601 va_list ap;
2602 va_start(ap, msg);
2603 LIBXML2_CALLBACK_ERR(domdoc_validateNode, msg, ap);
2604 va_end(ap);
2607 static void LIBXML2_LOG_CALLBACK validate_warning(void* ctx, char const* msg, ...)
2609 va_list ap;
2610 va_start(ap, msg);
2611 LIBXML2_CALLBACK_WARN(domdoc_validateNode, msg, ap);
2612 va_end(ap);
2615 static HRESULT WINAPI domdoc_validateNode(
2616 IXMLDOMDocument3* iface,
2617 IXMLDOMNode* node,
2618 IXMLDOMParseError** err)
2620 domdoc* This = impl_from_IXMLDOMDocument3(iface);
2621 LONG state, err_code = 0;
2622 HRESULT hr = S_OK;
2623 int validated = 0;
2625 TRACE("(%p)->(%p, %p)\n", This, node, err);
2626 domdoc_get_readyState(iface, &state);
2627 if (state != READYSTATE_COMPLETE)
2629 if (err)
2630 *err = create_parseError(err_code, NULL, NULL, NULL, 0, 0, 0);
2631 return E_PENDING;
2634 if (!node)
2636 if (err)
2637 *err = create_parseError(err_code, NULL, NULL, NULL, 0, 0, 0);
2638 return E_POINTER;
2641 if (!get_node_obj(node)->node || get_node_obj(node)->node->doc != get_doc(This))
2643 if (err)
2644 *err = create_parseError(err_code, NULL, NULL, NULL, 0, 0, 0);
2645 return E_FAIL;
2648 if (!is_wellformed(get_doc(This)))
2650 ERR("doc not well-formed\n");
2651 if (err)
2652 *err = create_parseError(E_XML_NOTWF, NULL, NULL, NULL, 0, 0, 0);
2653 return S_FALSE;
2656 /* DTD validation */
2657 if (get_doc(This)->intSubset || get_doc(This)->extSubset)
2659 xmlValidCtxtPtr vctx = xmlNewValidCtxt();
2660 vctx->error = validate_error;
2661 vctx->warning = validate_warning;
2662 ++validated;
2664 if (!((node == (IXMLDOMNode*)iface)?
2665 xmlValidateDocument(vctx, get_doc(This)) :
2666 xmlValidateElement(vctx, get_doc(This), get_node_obj(node)->node)))
2668 /* TODO: get a real error code here */
2669 TRACE("DTD validation failed\n");
2670 err_code = E_XML_INVALID;
2671 hr = S_FALSE;
2673 xmlFreeValidCtxt(vctx);
2676 /* Schema validation */
2677 if (hr == S_OK && This->properties->schemaCache != NULL)
2680 hr = SchemaCache_validate_tree(This->properties->schemaCache, get_node_obj(node)->node);
2681 if (!FAILED(hr))
2683 ++validated;
2684 /* TODO: get a real error code here */
2685 if (hr == S_OK)
2687 TRACE("schema validation succeeded\n");
2689 else
2691 ERR("schema validation failed\n");
2692 err_code = E_XML_INVALID;
2695 else
2697 /* not really OK, just didn't find a schema for the ns */
2698 hr = S_OK;
2702 if (!validated)
2704 ERR("no DTD or schema found\n");
2705 err_code = E_XML_NODTD;
2706 hr = S_FALSE;
2709 if (err)
2710 *err = create_parseError(err_code, NULL, NULL, NULL, 0, 0, 0);
2712 return hr;
2715 static HRESULT WINAPI domdoc_validate(
2716 IXMLDOMDocument3* iface,
2717 IXMLDOMParseError** err)
2719 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2720 TRACE("(%p)->(%p)\n", This, err);
2721 return domdoc_validateNode(iface, (IXMLDOMNode*)iface, err);
2724 static HRESULT WINAPI domdoc_setProperty(
2725 IXMLDOMDocument3* iface,
2726 BSTR p,
2727 VARIANT var)
2729 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2731 TRACE("(%p)->(%s)\n", This, debugstr_w(p));
2733 if (lstrcmpiW(p, PropertySelectionLanguageW) == 0)
2735 VARIANT varStr;
2736 HRESULT hr;
2737 BSTR bstr;
2739 V_VT(&varStr) = VT_EMPTY;
2740 if (V_VT(&var) != VT_BSTR)
2742 if (FAILED(hr = VariantChangeType(&varStr, &var, 0, VT_BSTR)))
2743 return hr;
2744 bstr = V_BSTR(&varStr);
2746 else
2747 bstr = V_BSTR(&var);
2749 hr = S_OK;
2750 if (lstrcmpiW(bstr, PropValueXPathW) == 0)
2751 This->properties->XPath = TRUE;
2752 else if (lstrcmpiW(bstr, PropValueXSLPatternW) == 0)
2753 This->properties->XPath = FALSE;
2754 else
2755 hr = E_FAIL;
2757 VariantClear(&varStr);
2758 return hr;
2760 else if (lstrcmpiW(p, PropertySelectionNamespacesW) == 0)
2762 VARIANT varStr;
2763 HRESULT hr;
2764 BSTR bstr;
2765 xmlChar *pTokBegin, *pTokEnd, *pTokInner;
2766 xmlChar *nsStr = (xmlChar*)This->properties->selectNsStr;
2767 xmlXPathContextPtr ctx;
2768 struct list *pNsList;
2769 select_ns_entry* pNsEntry = NULL;
2771 V_VT(&varStr) = VT_EMPTY;
2772 if (V_VT(&var) != VT_BSTR)
2774 if (FAILED(hr = VariantChangeType(&varStr, &var, 0, VT_BSTR)))
2775 return hr;
2776 bstr = V_BSTR(&varStr);
2778 else
2779 bstr = V_BSTR(&var);
2781 hr = S_OK;
2783 pNsList = &(This->properties->selectNsList);
2784 clear_selectNsList(pNsList);
2785 heap_free(nsStr);
2786 nsStr = xmlChar_from_wchar(bstr);
2789 TRACE("Setting SelectionNamespaces property to: %s\n", nsStr);
2791 This->properties->selectNsStr = nsStr;
2792 This->properties->selectNsStr_len = xmlStrlen(nsStr);
2793 if (bstr && *bstr)
2795 ctx = xmlXPathNewContext(This->node.node->doc);
2796 pTokBegin = nsStr;
2797 pTokEnd = nsStr;
2798 for (; *pTokBegin; pTokBegin = pTokEnd)
2800 if (pNsEntry != NULL)
2801 memset(pNsEntry, 0, sizeof(select_ns_entry));
2802 else
2803 pNsEntry = heap_alloc_zero(sizeof(select_ns_entry));
2805 while (*pTokBegin == ' ')
2806 ++pTokBegin;
2807 pTokEnd = pTokBegin;
2808 while (*pTokEnd != ' ' && *pTokEnd != 0)
2809 ++pTokEnd;
2811 if (xmlStrncmp(pTokBegin, (xmlChar const*)"xmlns", 5) != 0)
2813 hr = E_FAIL;
2814 WARN("Syntax error in xmlns string: %s\n\tat token: %s\n",
2815 wine_dbgstr_w(bstr), wine_dbgstr_an((const char*)pTokBegin, pTokEnd-pTokBegin));
2816 continue;
2819 pTokBegin += 5;
2820 if (*pTokBegin == '=')
2822 /*valid for XSLPattern?*/
2823 FIXME("Setting default xmlns not supported - skipping.\n");
2824 pTokBegin = pTokEnd;
2825 continue;
2827 else if (*pTokBegin == ':')
2829 pNsEntry->prefix = ++pTokBegin;
2830 for (pTokInner = pTokBegin; pTokInner != pTokEnd && *pTokInner != '='; ++pTokInner)
2833 if (pTokInner == pTokEnd)
2835 hr = E_FAIL;
2836 WARN("Syntax error in xmlns string: %s\n\tat token: %s\n",
2837 wine_dbgstr_w(bstr), wine_dbgstr_an((const char*)pTokBegin, pTokEnd-pTokBegin));
2838 continue;
2841 pNsEntry->prefix_end = *pTokInner;
2842 *pTokInner = 0;
2843 ++pTokInner;
2845 if (pTokEnd-pTokInner > 1 &&
2846 ((*pTokInner == '\'' && *(pTokEnd-1) == '\'') ||
2847 (*pTokInner == '"' && *(pTokEnd-1) == '"')))
2849 pNsEntry->href = ++pTokInner;
2850 pNsEntry->href_end = *(pTokEnd-1);
2851 *(pTokEnd-1) = 0;
2852 list_add_tail(pNsList, &pNsEntry->entry);
2853 /*let libxml figure out if they're valid from here ;)*/
2854 if (xmlXPathRegisterNs(ctx, pNsEntry->prefix, pNsEntry->href) != 0)
2856 hr = E_FAIL;
2858 pNsEntry = NULL;
2859 continue;
2861 else
2863 WARN("Syntax error in xmlns string: %s\n\tat token: %s\n",
2864 wine_dbgstr_w(bstr), wine_dbgstr_an((const char*)pTokInner, pTokEnd-pTokInner));
2865 list_add_tail(pNsList, &pNsEntry->entry);
2867 pNsEntry = NULL;
2868 hr = E_FAIL;
2869 continue;
2872 else
2874 hr = E_FAIL;
2875 continue;
2878 heap_free(pNsEntry);
2879 xmlXPathFreeContext(ctx);
2882 VariantClear(&varStr);
2883 return hr;
2885 else if (lstrcmpiW(p, PropertyProhibitDTDW) == 0 ||
2886 lstrcmpiW(p, PropertyNewParserW) == 0)
2888 /* Ignore */
2889 FIXME("Ignoring property %s, value %d\n", debugstr_w(p), V_BOOL(&var));
2890 return S_OK;
2893 FIXME("Unknown property %s\n", wine_dbgstr_w(p));
2894 return E_FAIL;
2897 static HRESULT WINAPI domdoc_getProperty(
2898 IXMLDOMDocument3* iface,
2899 BSTR p,
2900 VARIANT* var)
2902 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2904 TRACE("(%p)->(%p)\n", This, debugstr_w(p));
2906 if (!var)
2907 return E_INVALIDARG;
2909 if (lstrcmpiW(p, PropertySelectionLanguageW) == 0)
2911 V_VT(var) = VT_BSTR;
2912 V_BSTR(var) = This->properties->XPath ?
2913 SysAllocString(PropValueXPathW) :
2914 SysAllocString(PropValueXSLPatternW);
2915 return V_BSTR(var) ? S_OK : E_OUTOFMEMORY;
2917 else if (lstrcmpiW(p, PropertySelectionNamespacesW) == 0)
2919 int lenA, lenW;
2920 BSTR rebuiltStr, cur;
2921 const xmlChar *nsStr;
2922 struct list *pNsList;
2923 select_ns_entry* pNsEntry;
2925 V_VT(var) = VT_BSTR;
2926 nsStr = This->properties->selectNsStr;
2927 pNsList = &This->properties->selectNsList;
2928 lenA = This->properties->selectNsStr_len;
2929 lenW = MultiByteToWideChar(CP_UTF8, 0, (LPCSTR)nsStr, lenA+1, NULL, 0);
2930 rebuiltStr = heap_alloc(lenW*sizeof(WCHAR));
2931 MultiByteToWideChar(CP_UTF8, 0, (LPCSTR)nsStr, lenA+1, rebuiltStr, lenW);
2932 cur = rebuiltStr;
2933 /* this is fine because all of the chars that end tokens are ASCII*/
2934 LIST_FOR_EACH_ENTRY(pNsEntry, pNsList, select_ns_entry, entry)
2936 while (*cur != 0) ++cur;
2937 if (pNsEntry->prefix_end)
2939 *cur = pNsEntry->prefix_end;
2940 while (*cur != 0) ++cur;
2943 if (pNsEntry->href_end)
2945 *cur = pNsEntry->href_end;
2948 V_BSTR(var) = SysAllocString(rebuiltStr);
2949 heap_free(rebuiltStr);
2950 return S_OK;
2953 FIXME("Unknown property %s\n", wine_dbgstr_w(p));
2954 return E_FAIL;
2957 static HRESULT WINAPI domdoc_importNode(
2958 IXMLDOMDocument3* iface,
2959 IXMLDOMNode* node,
2960 VARIANT_BOOL deep,
2961 IXMLDOMNode** clone)
2963 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2964 FIXME("(%p)->(%p %d %p): stub\n", This, node, deep, clone);
2965 return E_NOTIMPL;
2968 static const struct IXMLDOMDocument3Vtbl domdoc_vtbl =
2970 domdoc_QueryInterface,
2971 domdoc_AddRef,
2972 domdoc_Release,
2973 domdoc_GetTypeInfoCount,
2974 domdoc_GetTypeInfo,
2975 domdoc_GetIDsOfNames,
2976 domdoc_Invoke,
2977 domdoc_get_nodeName,
2978 domdoc_get_nodeValue,
2979 domdoc_put_nodeValue,
2980 domdoc_get_nodeType,
2981 domdoc_get_parentNode,
2982 domdoc_get_childNodes,
2983 domdoc_get_firstChild,
2984 domdoc_get_lastChild,
2985 domdoc_get_previousSibling,
2986 domdoc_get_nextSibling,
2987 domdoc_get_attributes,
2988 domdoc_insertBefore,
2989 domdoc_replaceChild,
2990 domdoc_removeChild,
2991 domdoc_appendChild,
2992 domdoc_hasChildNodes,
2993 domdoc_get_ownerDocument,
2994 domdoc_cloneNode,
2995 domdoc_get_nodeTypeString,
2996 domdoc_get_text,
2997 domdoc_put_text,
2998 domdoc_get_specified,
2999 domdoc_get_definition,
3000 domdoc_get_nodeTypedValue,
3001 domdoc_put_nodeTypedValue,
3002 domdoc_get_dataType,
3003 domdoc_put_dataType,
3004 domdoc_get_xml,
3005 domdoc_transformNode,
3006 domdoc_selectNodes,
3007 domdoc_selectSingleNode,
3008 domdoc_get_parsed,
3009 domdoc_get_namespaceURI,
3010 domdoc_get_prefix,
3011 domdoc_get_baseName,
3012 domdoc_transformNodeToObject,
3013 domdoc_get_doctype,
3014 domdoc_get_implementation,
3015 domdoc_get_documentElement,
3016 domdoc_put_documentElement,
3017 domdoc_createElement,
3018 domdoc_createDocumentFragment,
3019 domdoc_createTextNode,
3020 domdoc_createComment,
3021 domdoc_createCDATASection,
3022 domdoc_createProcessingInstruction,
3023 domdoc_createAttribute,
3024 domdoc_createEntityReference,
3025 domdoc_getElementsByTagName,
3026 domdoc_createNode,
3027 domdoc_nodeFromID,
3028 domdoc_load,
3029 domdoc_get_readyState,
3030 domdoc_get_parseError,
3031 domdoc_get_url,
3032 domdoc_get_async,
3033 domdoc_put_async,
3034 domdoc_abort,
3035 domdoc_loadXML,
3036 domdoc_save,
3037 domdoc_get_validateOnParse,
3038 domdoc_put_validateOnParse,
3039 domdoc_get_resolveExternals,
3040 domdoc_put_resolveExternals,
3041 domdoc_get_preserveWhiteSpace,
3042 domdoc_put_preserveWhiteSpace,
3043 domdoc_put_onReadyStateChange,
3044 domdoc_put_onDataAvailable,
3045 domdoc_put_onTransformNode,
3046 domdoc_get_namespaces,
3047 domdoc_get_schemas,
3048 domdoc_putref_schemas,
3049 domdoc_validate,
3050 domdoc_setProperty,
3051 domdoc_getProperty,
3052 domdoc_validateNode,
3053 domdoc_importNode
3056 /* IConnectionPointContainer */
3057 static HRESULT WINAPI ConnectionPointContainer_QueryInterface(IConnectionPointContainer *iface,
3058 REFIID riid, void **ppv)
3060 domdoc *This = impl_from_IConnectionPointContainer(iface);
3061 return IXMLDOMDocument3_QueryInterface((IXMLDOMDocument3*)This, riid, ppv);
3064 static ULONG WINAPI ConnectionPointContainer_AddRef(IConnectionPointContainer *iface)
3066 domdoc *This = impl_from_IConnectionPointContainer(iface);
3067 return IXMLDOMDocument3_AddRef((IXMLDOMDocument3*)This);
3070 static ULONG WINAPI ConnectionPointContainer_Release(IConnectionPointContainer *iface)
3072 domdoc *This = impl_from_IConnectionPointContainer(iface);
3073 return IXMLDOMDocument3_Release((IXMLDOMDocument3*)This);
3076 static HRESULT WINAPI ConnectionPointContainer_EnumConnectionPoints(IConnectionPointContainer *iface,
3077 IEnumConnectionPoints **ppEnum)
3079 domdoc *This = impl_from_IConnectionPointContainer(iface);
3080 FIXME("(%p)->(%p): stub\n", This, ppEnum);
3081 return E_NOTIMPL;
3084 static HRESULT WINAPI ConnectionPointContainer_FindConnectionPoint(IConnectionPointContainer *iface,
3085 REFIID riid, IConnectionPoint **cp)
3087 domdoc *This = impl_from_IConnectionPointContainer(iface);
3088 ConnectionPoint *iter;
3090 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), cp);
3092 *cp = NULL;
3094 for(iter = This->cp_list; iter; iter = iter->next)
3096 if (IsEqualGUID(iter->iid, riid))
3097 *cp = (IConnectionPoint*)&iter->lpVtblConnectionPoint;
3100 if (*cp)
3102 IConnectionPoint_AddRef(*cp);
3103 return S_OK;
3106 FIXME("unsupported riid %s\n", debugstr_guid(riid));
3107 return CONNECT_E_NOCONNECTION;
3111 static const struct IConnectionPointContainerVtbl ConnectionPointContainerVtbl =
3113 ConnectionPointContainer_QueryInterface,
3114 ConnectionPointContainer_AddRef,
3115 ConnectionPointContainer_Release,
3116 ConnectionPointContainer_EnumConnectionPoints,
3117 ConnectionPointContainer_FindConnectionPoint
3120 /* IConnectionPoint */
3121 static HRESULT WINAPI ConnectionPoint_QueryInterface(IConnectionPoint *iface,
3122 REFIID riid, void **ppv)
3124 ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3126 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv );
3128 *ppv = NULL;
3130 if (IsEqualGUID(&IID_IUnknown, riid) ||
3131 IsEqualGUID(&IID_IConnectionPoint, riid))
3133 *ppv = iface;
3136 if (*ppv)
3138 IConnectionPoint_AddRef(iface);
3139 return S_OK;
3142 WARN("Unsupported interface %s\n", debugstr_guid(riid));
3143 return E_NOINTERFACE;
3146 static ULONG WINAPI ConnectionPoint_AddRef(IConnectionPoint *iface)
3148 ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3149 return IConnectionPointContainer_AddRef(This->container);
3152 static ULONG WINAPI ConnectionPoint_Release(IConnectionPoint *iface)
3154 ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3155 return IConnectionPointContainer_Release(This->container);
3158 static HRESULT WINAPI ConnectionPoint_GetConnectionInterface(IConnectionPoint *iface, IID *iid)
3160 ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3162 TRACE("(%p)->(%p)\n", This, iid);
3164 if (!iid) return E_POINTER;
3166 *iid = *This->iid;
3167 return S_OK;
3170 static HRESULT WINAPI ConnectionPoint_GetConnectionPointContainer(IConnectionPoint *iface,
3171 IConnectionPointContainer **container)
3173 ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3175 TRACE("(%p)->(%p)\n", This, container);
3177 if (!container) return E_POINTER;
3179 *container = This->container;
3180 IConnectionPointContainer_AddRef(*container);
3181 return S_OK;
3184 static HRESULT WINAPI ConnectionPoint_Advise(IConnectionPoint *iface, IUnknown *pUnkSink,
3185 DWORD *pdwCookie)
3187 ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3188 FIXME("(%p)->(%p %p): stub\n", This, pUnkSink, pdwCookie);
3189 return E_NOTIMPL;
3192 static HRESULT WINAPI ConnectionPoint_Unadvise(IConnectionPoint *iface, DWORD cookie)
3194 ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3196 TRACE("(%p)->(%d)\n", This, cookie);
3198 if (cookie == 0 || cookie > This->sinks_size || !This->sinks[cookie-1].unk)
3199 return CONNECT_E_NOCONNECTION;
3201 IUnknown_Release(This->sinks[cookie-1].unk);
3202 This->sinks[cookie-1].unk = NULL;
3204 return S_OK;
3207 static HRESULT WINAPI ConnectionPoint_EnumConnections(IConnectionPoint *iface,
3208 IEnumConnections **ppEnum)
3210 ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3211 FIXME("(%p)->(%p): stub\n", This, ppEnum);
3212 return E_NOTIMPL;
3215 static const IConnectionPointVtbl ConnectionPointVtbl =
3217 ConnectionPoint_QueryInterface,
3218 ConnectionPoint_AddRef,
3219 ConnectionPoint_Release,
3220 ConnectionPoint_GetConnectionInterface,
3221 ConnectionPoint_GetConnectionPointContainer,
3222 ConnectionPoint_Advise,
3223 ConnectionPoint_Unadvise,
3224 ConnectionPoint_EnumConnections
3227 void ConnectionPoint_Init(ConnectionPoint *cp, struct domdoc *doc, REFIID riid)
3229 cp->lpVtblConnectionPoint = &ConnectionPointVtbl;
3230 cp->doc = doc;
3231 cp->iid = riid;
3232 cp->sinks = NULL;
3233 cp->sinks_size = 0;
3235 cp->next = doc->cp_list;
3236 doc->cp_list = cp;
3238 cp->container = (IConnectionPointContainer*)&doc->lpVtblConnectionPointContainer;
3241 /* domdoc implementation of IObjectWithSite */
3242 static HRESULT WINAPI
3243 domdoc_ObjectWithSite_QueryInterface( IObjectWithSite* iface, REFIID riid, void** ppvObject )
3245 domdoc *This = impl_from_IObjectWithSite(iface);
3246 return IXMLDOMDocument3_QueryInterface( (IXMLDOMDocument3 *)This, riid, ppvObject );
3249 static ULONG WINAPI domdoc_ObjectWithSite_AddRef( IObjectWithSite* iface )
3251 domdoc *This = impl_from_IObjectWithSite(iface);
3252 return IXMLDOMDocument3_AddRef((IXMLDOMDocument3 *)This);
3255 static ULONG WINAPI domdoc_ObjectWithSite_Release( IObjectWithSite* iface )
3257 domdoc *This = impl_from_IObjectWithSite(iface);
3258 return IXMLDOMDocument3_Release((IXMLDOMDocument3 *)This);
3261 static HRESULT WINAPI domdoc_ObjectWithSite_GetSite( IObjectWithSite *iface, REFIID iid, void **ppvSite )
3263 domdoc *This = impl_from_IObjectWithSite(iface);
3265 TRACE("(%p)->(%s %p)\n", This, debugstr_guid( iid ), ppvSite );
3267 if ( !This->site )
3268 return E_FAIL;
3270 return IUnknown_QueryInterface( This->site, iid, ppvSite );
3273 static HRESULT WINAPI domdoc_ObjectWithSite_SetSite( IObjectWithSite *iface, IUnknown *punk )
3275 domdoc *This = impl_from_IObjectWithSite(iface);
3277 TRACE("(%p)->(%p)\n", iface, punk);
3279 if(!punk)
3281 if(This->site)
3283 IUnknown_Release( This->site );
3284 This->site = NULL;
3287 return S_OK;
3290 IUnknown_AddRef( punk );
3292 if(This->site)
3293 IUnknown_Release( This->site );
3295 This->site = punk;
3297 return S_OK;
3300 static const IObjectWithSiteVtbl domdocObjectSite =
3302 domdoc_ObjectWithSite_QueryInterface,
3303 domdoc_ObjectWithSite_AddRef,
3304 domdoc_ObjectWithSite_Release,
3305 domdoc_ObjectWithSite_SetSite,
3306 domdoc_ObjectWithSite_GetSite
3309 static HRESULT WINAPI domdoc_Safety_QueryInterface(IObjectSafety *iface, REFIID riid, void **ppv)
3311 domdoc *This = impl_from_IObjectSafety(iface);
3312 return IXMLDOMDocument3_QueryInterface( (IXMLDOMDocument3 *)This, riid, ppv );
3315 static ULONG WINAPI domdoc_Safety_AddRef(IObjectSafety *iface)
3317 domdoc *This = impl_from_IObjectSafety(iface);
3318 return IXMLDOMDocument3_AddRef((IXMLDOMDocument3 *)This);
3321 static ULONG WINAPI domdoc_Safety_Release(IObjectSafety *iface)
3323 domdoc *This = impl_from_IObjectSafety(iface);
3324 return IXMLDOMDocument3_Release((IXMLDOMDocument3 *)This);
3327 #define SAFETY_SUPPORTED_OPTIONS (INTERFACESAFE_FOR_UNTRUSTED_CALLER|INTERFACESAFE_FOR_UNTRUSTED_DATA|INTERFACE_USES_SECURITY_MANAGER)
3329 static HRESULT WINAPI domdoc_Safety_GetInterfaceSafetyOptions(IObjectSafety *iface, REFIID riid,
3330 DWORD *supported, DWORD *enabled)
3332 domdoc *This = impl_from_IObjectSafety(iface);
3334 TRACE("(%p)->(%s %p %p)\n", This, debugstr_guid(riid), supported, enabled);
3336 if(!supported || !enabled) return E_POINTER;
3338 *supported = SAFETY_SUPPORTED_OPTIONS;
3339 *enabled = This->safeopt;
3341 return S_OK;
3344 static HRESULT WINAPI domdoc_Safety_SetInterfaceSafetyOptions(IObjectSafety *iface, REFIID riid,
3345 DWORD mask, DWORD enabled)
3347 domdoc *This = impl_from_IObjectSafety(iface);
3348 TRACE("(%p)->(%s %x %x)\n", This, debugstr_guid(riid), mask, enabled);
3350 if ((mask & ~SAFETY_SUPPORTED_OPTIONS) != 0)
3351 return E_FAIL;
3353 This->safeopt = enabled & mask & SAFETY_SUPPORTED_OPTIONS;
3354 return S_OK;
3357 #undef SAFETY_SUPPORTED_OPTIONS
3359 static const IObjectSafetyVtbl domdocObjectSafetyVtbl = {
3360 domdoc_Safety_QueryInterface,
3361 domdoc_Safety_AddRef,
3362 domdoc_Safety_Release,
3363 domdoc_Safety_GetInterfaceSafetyOptions,
3364 domdoc_Safety_SetInterfaceSafetyOptions
3367 static const tid_t domdoc_iface_tids[] = {
3368 IXMLDOMNode_tid,
3369 IXMLDOMDocument_tid,
3370 IXMLDOMDocument2_tid,
3373 static dispex_static_data_t domdoc_dispex = {
3374 NULL,
3375 IXMLDOMDocument2_tid,
3376 NULL,
3377 domdoc_iface_tids
3380 HRESULT DOMDocument_create_from_xmldoc(xmlDocPtr xmldoc, IXMLDOMDocument3 **document)
3382 domdoc *doc;
3384 doc = heap_alloc( sizeof (*doc) );
3385 if( !doc )
3386 return E_OUTOFMEMORY;
3388 doc->lpVtbl = &domdoc_vtbl;
3389 doc->lpvtblIPersistStreamInit = &xmldoc_IPersistStreamInit_VTable;
3390 doc->lpvtblIObjectWithSite = &domdocObjectSite;
3391 doc->lpvtblIObjectSafety = &domdocObjectSafetyVtbl;
3392 doc->lpvtblISupportErrorInfo = &support_error_vtbl;
3393 doc->lpVtblConnectionPointContainer = &ConnectionPointContainerVtbl;
3394 doc->ref = 1;
3395 doc->async = VARIANT_TRUE;
3396 doc->validating = 0;
3397 doc->resolving = 0;
3398 doc->properties = properties_from_xmlDocPtr(xmldoc);
3399 doc->error = S_OK;
3400 doc->stream = NULL;
3401 doc->site = NULL;
3402 doc->safeopt = 0;
3403 doc->bsc = NULL;
3404 doc->cp_list = NULL;
3406 /* events connection points */
3407 ConnectionPoint_Init(&doc->cp_dispatch, doc, &IID_IDispatch);
3408 ConnectionPoint_Init(&doc->cp_propnotif, doc, &IID_IPropertyNotifySink);
3409 ConnectionPoint_Init(&doc->cp_domdocevents, doc, &DIID_XMLDOMDocumentEvents);
3411 init_xmlnode(&doc->node, (xmlNodePtr)xmldoc, (IXMLDOMNode*)&doc->lpVtbl, &domdoc_dispex);
3413 *document = (IXMLDOMDocument3*)&doc->lpVtbl;
3415 TRACE("returning iface %p\n", *document);
3416 return S_OK;
3419 HRESULT DOMDocument_create(const GUID *clsid, IUnknown *pUnkOuter, void **ppObj)
3421 xmlDocPtr xmldoc;
3422 HRESULT hr;
3424 TRACE("(%s, %p, %p)\n", debugstr_guid(clsid), pUnkOuter, ppObj);
3426 xmldoc = xmlNewDoc(NULL);
3427 if(!xmldoc)
3428 return E_OUTOFMEMORY;
3430 xmldoc->_private = create_priv();
3431 priv_from_xmlDocPtr(xmldoc)->properties = create_properties(clsid);
3433 hr = DOMDocument_create_from_xmldoc(xmldoc, (IXMLDOMDocument3**)ppObj);
3434 if(FAILED(hr))
3436 free_properties(properties_from_xmlDocPtr(xmldoc));
3437 heap_free(xmldoc->_private);
3438 xmlFreeDoc(xmldoc);
3439 return hr;
3442 return hr;
3445 IUnknown* create_domdoc( xmlNodePtr document )
3447 void* pObj = NULL;
3448 HRESULT hr;
3450 TRACE("(%p)\n", document);
3452 hr = DOMDocument_create_from_xmldoc((xmlDocPtr)document, (IXMLDOMDocument3**)&pObj);
3453 if (FAILED(hr))
3454 return NULL;
3456 return pObj;
3459 #else
3461 HRESULT DOMDocument_create(const GUID *clsid, IUnknown *pUnkOuter, void **ppObj)
3463 MESSAGE("This program tried to use a DOMDocument object, but\n"
3464 "libxml2 support was not present at compile time.\n");
3465 return E_NOTIMPL;
3468 #endif