jscript: Don't set constructor property to each object instance, it belongs to their...
[wine/multimedia.git] / dlls / msxml3 / domdoc.c
blob0f3eb50d8fa59a1d5235696bfe0768933d62dd49
1 /*
2 * DOM Document implementation
4 * Copyright 2005 Mike McCormack
5 * Copyright 2010-2011 Adam Martinson for CodeWeavers
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
22 #define COBJMACROS
23 #define NONAMELESSUNION
25 #include "config.h"
27 #include <stdarg.h>
28 #include <assert.h>
29 #ifdef HAVE_LIBXML2
30 # include <libxml/parser.h>
31 # include <libxml/xmlerror.h>
32 # include <libxml/xpathInternals.h>
33 # include <libxml/xmlsave.h>
34 # include <libxml/SAX2.h>
35 # include <libxml/parserInternals.h>
36 #endif
38 #include "windef.h"
39 #include "winbase.h"
40 #include "winuser.h"
41 #include "winnls.h"
42 #include "ole2.h"
43 #include "olectl.h"
44 #include "msxml6.h"
45 #include "wininet.h"
46 #include "winreg.h"
47 #include "shlwapi.h"
48 #include "ocidl.h"
49 #include "objsafe.h"
51 #include "wine/debug.h"
52 #include "wine/list.h"
54 #include "msxml_private.h"
56 WINE_DEFAULT_DEBUG_CHANNEL(msxml);
58 #ifdef HAVE_LIBXML2
60 /* not defined in older versions */
61 #define XML_SAVE_FORMAT 1
62 #define XML_SAVE_NO_DECL 2
63 #define XML_SAVE_NO_EMPTY 4
64 #define XML_SAVE_NO_XHTML 8
65 #define XML_SAVE_XHTML 16
66 #define XML_SAVE_AS_XML 32
67 #define XML_SAVE_AS_HTML 64
69 static const WCHAR PropertySelectionLanguageW[] = {'S','e','l','e','c','t','i','o','n','L','a','n','g','u','a','g','e',0};
70 static const WCHAR PropertySelectionNamespacesW[] = {'S','e','l','e','c','t','i','o','n','N','a','m','e','s','p','a','c','e','s',0};
71 static const WCHAR PropertyProhibitDTDW[] = {'P','r','o','h','i','b','i','t','D','T','D',0};
72 static const WCHAR PropertyNewParserW[] = {'N','e','w','P','a','r','s','e','r',0};
73 static const WCHAR PropValueXPathW[] = {'X','P','a','t','h',0};
74 static const WCHAR PropValueXSLPatternW[] = {'X','S','L','P','a','t','t','e','r','n',0};
75 static const WCHAR PropertyResolveExternalsW[] = {'R','e','s','o','l','v','e','E','x','t','e','r','n','a','l','s',0};
77 /* Anything that passes the test_get_ownerDocument()
78 * tests can go here (data shared between all instances).
79 * We need to preserve this when reloading a document,
80 * and also need access to it from the libxml backend. */
81 typedef struct {
82 MSXML_VERSION version;
83 VARIANT_BOOL preserving;
84 IXMLDOMSchemaCollection2* schemaCache;
85 struct list selectNsList;
86 xmlChar const* selectNsStr;
87 LONG selectNsStr_len;
88 BOOL XPath;
89 } domdoc_properties;
91 typedef struct ConnectionPoint ConnectionPoint;
92 typedef struct domdoc domdoc;
94 struct ConnectionPoint
96 IConnectionPoint IConnectionPoint_iface;
97 const IID *iid;
99 ConnectionPoint *next;
100 IConnectionPointContainer *container;
101 domdoc *doc;
103 union
105 IUnknown *unk;
106 IDispatch *disp;
107 IPropertyNotifySink *propnotif;
108 } *sinks;
109 DWORD sinks_size;
112 typedef enum {
113 EVENTID_READYSTATECHANGE = 0,
114 EVENTID_DATAAVAILABLE,
115 EVENTID_TRANSFORMNODE,
116 EVENTID_LAST
117 } eventid_t;
119 struct domdoc
121 xmlnode node;
122 IXMLDOMDocument3 IXMLDOMDocument3_iface;
123 IPersistStreamInit IPersistStreamInit_iface;
124 IObjectWithSite IObjectWithSite_iface;
125 IObjectSafety IObjectSafety_iface;
126 IConnectionPointContainer IConnectionPointContainer_iface;
127 LONG ref;
128 VARIANT_BOOL async;
129 VARIANT_BOOL validating;
130 VARIANT_BOOL resolving;
131 domdoc_properties* properties;
132 bsc_t *bsc;
133 HRESULT error;
135 /* IPersistStream */
136 IStream *stream;
138 /* IObjectWithSite*/
139 IUnknown *site;
141 /* IObjectSafety */
142 DWORD safeopt;
144 /* connection list */
145 ConnectionPoint *cp_list;
146 ConnectionPoint cp_domdocevents;
147 ConnectionPoint cp_propnotif;
148 ConnectionPoint cp_dispatch;
150 /* events */
151 IDispatch *events[EVENTID_LAST];
153 IXMLDOMSchemaCollection2 *namespaces;
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 static void release_namespaces(domdoc *This)
357 if (This->namespaces)
359 IXMLDOMSchemaCollection2_Release(This->namespaces);
360 This->namespaces = NULL;
364 /* links a "<?xml" node as a first child */
365 void xmldoc_link_xmldecl(xmlDocPtr doc, xmlNodePtr node)
367 assert(doc != NULL);
368 if (doc->standalone != -1) xmlAddPrevSibling( doc->children, node );
371 /* unlinks a first "<?xml" child if it was created */
372 xmlNodePtr xmldoc_unlink_xmldecl(xmlDocPtr doc)
374 static const xmlChar xmlA[] = "xml";
375 xmlNodePtr node, first_child;
377 assert(doc != NULL);
379 /* xml declaration node could be created automatically after parsing or added
380 to a tree later */
381 first_child = doc->children;
382 if (first_child && first_child->type == XML_PI_NODE && xmlStrEqual(first_child->name, xmlA))
384 node = first_child;
385 xmlUnlinkNode( node );
387 else
388 node = NULL;
390 return node;
393 BOOL is_preserving_whitespace(xmlNodePtr node)
395 domdoc_properties* properties = NULL;
396 /* during parsing the xmlDoc._private stuff is not there */
397 if (priv_from_xmlDocPtr(node->doc))
398 properties = properties_from_xmlDocPtr(node->doc);
399 return ((properties && properties->preserving == VARIANT_TRUE) ||
400 xmlNodeGetSpacePreserve(node) == 1);
403 static inline BOOL strn_isspace(xmlChar const* str, int len)
405 for (; str && len > 0 && *str; ++str, --len)
406 if (!isspace(*str))
407 break;
409 return len == 0;
412 static void sax_characters(void *ctx, const xmlChar *ch, int len)
414 xmlParserCtxtPtr ctxt;
415 const domdoc *This;
417 ctxt = (xmlParserCtxtPtr) ctx;
418 This = (const domdoc*) ctxt->_private;
420 if (ctxt->node)
422 /* during domdoc_loadXML() the xmlDocPtr->_private data is not available */
423 if (!This->properties->preserving &&
424 !is_preserving_whitespace(ctxt->node) &&
425 strn_isspace(ch, len))
426 return;
429 xmlSAX2Characters(ctxt, ch, len);
432 static void LIBXML2_LOG_CALLBACK sax_error(void* ctx, char const* msg, ...)
434 va_list ap;
435 va_start(ap, msg);
436 LIBXML2_CALLBACK_ERR(doparse, msg, ap);
437 va_end(ap);
440 static void LIBXML2_LOG_CALLBACK sax_warning(void* ctx, char const* msg, ...)
442 va_list ap;
443 va_start(ap, msg);
444 LIBXML2_CALLBACK_WARN(doparse, msg, ap);
445 va_end(ap);
448 static void sax_serror(void* ctx, xmlErrorPtr err)
450 LIBXML2_CALLBACK_SERROR(doparse, err);
453 static xmlDocPtr doparse(domdoc* This, char const* ptr, int len, xmlCharEncoding encoding)
455 xmlDocPtr doc = NULL;
456 xmlParserCtxtPtr pctx;
457 static xmlSAXHandler sax_handler = {
458 xmlSAX2InternalSubset, /* internalSubset */
459 xmlSAX2IsStandalone, /* isStandalone */
460 xmlSAX2HasInternalSubset, /* hasInternalSubset */
461 xmlSAX2HasExternalSubset, /* hasExternalSubset */
462 xmlSAX2ResolveEntity, /* resolveEntity */
463 xmlSAX2GetEntity, /* getEntity */
464 xmlSAX2EntityDecl, /* entityDecl */
465 xmlSAX2NotationDecl, /* notationDecl */
466 xmlSAX2AttributeDecl, /* attributeDecl */
467 xmlSAX2ElementDecl, /* elementDecl */
468 xmlSAX2UnparsedEntityDecl, /* unparsedEntityDecl */
469 xmlSAX2SetDocumentLocator, /* setDocumentLocator */
470 xmlSAX2StartDocument, /* startDocument */
471 xmlSAX2EndDocument, /* endDocument */
472 xmlSAX2StartElement, /* startElement */
473 xmlSAX2EndElement, /* endElement */
474 xmlSAX2Reference, /* reference */
475 sax_characters, /* characters */
476 sax_characters, /* ignorableWhitespace */
477 xmlSAX2ProcessingInstruction, /* processingInstruction */
478 xmlSAX2Comment, /* comment */
479 sax_warning, /* warning */
480 sax_error, /* error */
481 sax_error, /* fatalError */
482 xmlSAX2GetParameterEntity, /* getParameterEntity */
483 xmlSAX2CDataBlock, /* cdataBlock */
484 xmlSAX2ExternalSubset, /* externalSubset */
485 0, /* initialized */
486 NULL, /* _private */
487 xmlSAX2StartElementNs, /* startElementNs */
488 xmlSAX2EndElementNs, /* endElementNs */
489 sax_serror /* serror */
492 pctx = xmlCreateMemoryParserCtxt(ptr, len);
493 if (!pctx)
495 ERR("Failed to create parser context\n");
496 return NULL;
499 if (pctx->sax) xmlFree(pctx->sax);
500 pctx->sax = &sax_handler;
501 pctx->_private = This;
502 pctx->recovery = 0;
504 if (encoding != XML_CHAR_ENCODING_NONE)
505 xmlSwitchEncoding(pctx, encoding);
507 xmlParseDocument(pctx);
509 if (pctx->wellFormed)
511 doc = pctx->myDoc;
513 else
515 xmlFreeDoc(pctx->myDoc);
516 pctx->myDoc = NULL;
518 pctx->sax = NULL;
519 xmlFreeParserCtxt(pctx);
521 /* TODO: put this in one of the SAX callbacks */
522 /* create first child as a <?xml...?> */
523 if (doc && doc->standalone != -1)
525 xmlNodePtr node;
526 char buff[30];
527 xmlChar *xmlbuff = (xmlChar*)buff;
529 node = xmlNewDocPI( doc, (xmlChar*)"xml", NULL );
531 /* version attribute can't be omitted */
532 sprintf(buff, "version=\"%s\"", doc->version ? (char*)doc->version : "1.0");
533 xmlNodeAddContent( node, xmlbuff );
535 if (doc->encoding)
537 sprintf(buff, " encoding=\"%s\"", doc->encoding);
538 xmlNodeAddContent( node, xmlbuff );
541 if (doc->standalone != -2)
543 sprintf(buff, " standalone=\"%s\"", doc->standalone == 0 ? "no" : "yes");
544 xmlNodeAddContent( node, xmlbuff );
547 xmldoc_link_xmldecl( doc, node );
550 return doc;
553 void xmldoc_init(xmlDocPtr doc, MSXML_VERSION version)
555 doc->_private = create_priv();
556 priv_from_xmlDocPtr(doc)->properties = create_properties(version);
559 LONG xmldoc_add_ref(xmlDocPtr doc)
561 LONG ref = InterlockedIncrement(&priv_from_xmlDocPtr(doc)->refs);
562 TRACE("(%p)->(%d)\n", doc, ref);
563 return ref;
566 LONG xmldoc_release(xmlDocPtr doc)
568 xmldoc_priv *priv = priv_from_xmlDocPtr(doc);
569 LONG ref = InterlockedDecrement(&priv->refs);
570 TRACE("(%p)->(%d)\n", doc, ref);
571 if(ref == 0)
573 orphan_entry *orphan, *orphan2;
574 TRACE("freeing docptr %p\n", doc);
576 LIST_FOR_EACH_ENTRY_SAFE( orphan, orphan2, &priv->orphans, orphan_entry, entry )
578 xmlFreeNode( orphan->node );
579 heap_free( orphan );
581 free_properties(priv->properties);
582 heap_free(doc->_private);
584 xmlFreeDoc(doc);
587 return ref;
590 HRESULT xmldoc_add_orphan(xmlDocPtr doc, xmlNodePtr node)
592 xmldoc_priv *priv = priv_from_xmlDocPtr(doc);
593 orphan_entry *entry;
595 entry = heap_alloc( sizeof (*entry) );
596 if(!entry)
597 return E_OUTOFMEMORY;
599 entry->node = node;
600 list_add_head( &priv->orphans, &entry->entry );
601 return S_OK;
604 HRESULT xmldoc_remove_orphan(xmlDocPtr doc, xmlNodePtr node)
606 xmldoc_priv *priv = priv_from_xmlDocPtr(doc);
607 orphan_entry *entry, *entry2;
609 LIST_FOR_EACH_ENTRY_SAFE( entry, entry2, &priv->orphans, orphan_entry, entry )
611 if( entry->node == node )
613 list_remove( &entry->entry );
614 heap_free( entry );
615 return S_OK;
619 return S_FALSE;
622 static inline xmlDocPtr get_doc( domdoc *This )
624 return (xmlDocPtr)This->node.node;
627 static HRESULT attach_xmldoc(domdoc *This, xmlDocPtr xml )
629 release_namespaces(This);
631 if(This->node.node)
633 priv_from_xmlDocPtr(get_doc(This))->properties = NULL;
634 if (xmldoc_release(get_doc(This)) != 0)
635 priv_from_xmlDocPtr(get_doc(This))->properties =
636 copy_properties(This->properties);
639 This->node.node = (xmlNodePtr) xml;
641 if(This->node.node)
643 xmldoc_add_ref(get_doc(This));
644 priv_from_xmlDocPtr(get_doc(This))->properties = This->properties;
647 return S_OK;
650 static inline domdoc *impl_from_IXMLDOMDocument3( IXMLDOMDocument3 *iface )
652 return CONTAINING_RECORD(iface, domdoc, IXMLDOMDocument3_iface);
655 static inline domdoc *impl_from_IPersistStreamInit(IPersistStreamInit *iface)
657 return CONTAINING_RECORD(iface, domdoc, IPersistStreamInit_iface);
660 static inline domdoc *impl_from_IObjectWithSite(IObjectWithSite *iface)
662 return CONTAINING_RECORD(iface, domdoc, IObjectWithSite_iface);
665 static inline domdoc *impl_from_IObjectSafety(IObjectSafety *iface)
667 return CONTAINING_RECORD(iface, domdoc, IObjectSafety_iface);
670 static inline domdoc *impl_from_IConnectionPointContainer(IConnectionPointContainer *iface)
672 return CONTAINING_RECORD(iface, domdoc, IConnectionPointContainer_iface);
675 /************************************************************************
676 * domdoc implementation of IPersistStream.
678 static HRESULT WINAPI PersistStreamInit_QueryInterface(
679 IPersistStreamInit *iface, REFIID riid, void **ppvObj)
681 domdoc* This = impl_from_IPersistStreamInit(iface);
682 return IXMLDOMDocument3_QueryInterface(&This->IXMLDOMDocument3_iface, riid, ppvObj);
685 static ULONG WINAPI PersistStreamInit_AddRef(
686 IPersistStreamInit *iface)
688 domdoc* This = impl_from_IPersistStreamInit(iface);
689 return IXMLDOMDocument3_AddRef(&This->IXMLDOMDocument3_iface);
692 static ULONG WINAPI PersistStreamInit_Release(
693 IPersistStreamInit *iface)
695 domdoc* This = impl_from_IPersistStreamInit(iface);
696 return IXMLDOMDocument3_Release(&This->IXMLDOMDocument3_iface);
699 static HRESULT WINAPI PersistStreamInit_GetClassID(
700 IPersistStreamInit *iface, CLSID *classid)
702 domdoc* This = impl_from_IPersistStreamInit(iface);
703 TRACE("(%p)->(%p)\n", This, classid);
705 if(!classid)
706 return E_POINTER;
708 *classid = *DOMDocument_version(This->properties->version);
710 return S_OK;
713 static HRESULT WINAPI PersistStreamInit_IsDirty(
714 IPersistStreamInit *iface)
716 domdoc *This = impl_from_IPersistStreamInit(iface);
717 FIXME("(%p): stub!\n", This);
718 return S_FALSE;
721 static HRESULT WINAPI PersistStreamInit_Load(
722 IPersistStreamInit *iface, LPSTREAM pStm)
724 domdoc *This = impl_from_IPersistStreamInit(iface);
725 HRESULT hr;
726 HGLOBAL hglobal;
727 DWORD read, written, len;
728 BYTE buf[4096];
729 char *ptr;
730 xmlDocPtr xmldoc = NULL;
732 TRACE("(%p)->(%p)\n", This, pStm);
734 if (!pStm)
735 return E_INVALIDARG;
737 hr = CreateStreamOnHGlobal(NULL, TRUE, &This->stream);
738 if (FAILED(hr))
739 return hr;
743 IStream_Read(pStm, buf, sizeof(buf), &read);
744 hr = IStream_Write(This->stream, buf, read, &written);
745 } while(SUCCEEDED(hr) && written != 0 && read != 0);
747 if (FAILED(hr))
749 ERR("Failed to copy stream\n");
750 return hr;
753 hr = GetHGlobalFromStream(This->stream, &hglobal);
754 if (FAILED(hr))
755 return hr;
757 len = GlobalSize(hglobal);
758 ptr = GlobalLock(hglobal);
759 if (len != 0)
760 xmldoc = doparse(This, ptr, len, XML_CHAR_ENCODING_NONE);
761 GlobalUnlock(hglobal);
763 if (!xmldoc)
765 ERR("Failed to parse xml\n");
766 return E_FAIL;
769 xmldoc->_private = create_priv();
771 return attach_xmldoc(This, xmldoc);
774 static HRESULT WINAPI PersistStreamInit_Save(
775 IPersistStreamInit *iface, IStream *stream, BOOL clr_dirty)
777 domdoc *This = impl_from_IPersistStreamInit(iface);
778 BSTR xmlString;
779 HRESULT hr;
781 TRACE("(%p)->(%p %d)\n", This, stream, clr_dirty);
783 hr = IXMLDOMDocument3_get_xml(&This->IXMLDOMDocument3_iface, &xmlString);
784 if(hr == S_OK)
786 DWORD len = SysStringLen(xmlString) * sizeof(WCHAR);
788 hr = IStream_Write( stream, xmlString, len, NULL );
789 SysFreeString(xmlString);
792 TRACE("ret 0x%08x\n", hr);
794 return hr;
797 static HRESULT WINAPI PersistStreamInit_GetSizeMax(
798 IPersistStreamInit *iface, ULARGE_INTEGER *pcbSize)
800 domdoc *This = impl_from_IPersistStreamInit(iface);
801 TRACE("(%p)->(%p): stub!\n", This, pcbSize);
802 return E_NOTIMPL;
805 static HRESULT WINAPI PersistStreamInit_InitNew(
806 IPersistStreamInit *iface)
808 domdoc *This = impl_from_IPersistStreamInit(iface);
809 TRACE("(%p)\n", This);
810 return S_OK;
813 static const IPersistStreamInitVtbl xmldoc_IPersistStreamInit_VTable =
815 PersistStreamInit_QueryInterface,
816 PersistStreamInit_AddRef,
817 PersistStreamInit_Release,
818 PersistStreamInit_GetClassID,
819 PersistStreamInit_IsDirty,
820 PersistStreamInit_Load,
821 PersistStreamInit_Save,
822 PersistStreamInit_GetSizeMax,
823 PersistStreamInit_InitNew
826 /* IXMLDOMDocument3 interface */
828 static const tid_t domdoc_se_tids[] = {
829 IXMLDOMNode_tid,
830 IXMLDOMDocument_tid,
831 IXMLDOMDocument2_tid,
832 IXMLDOMDocument3_tid,
836 static HRESULT WINAPI domdoc_QueryInterface( IXMLDOMDocument3 *iface, REFIID riid, void** ppvObject )
838 domdoc *This = impl_from_IXMLDOMDocument3( iface );
840 TRACE("(%p)->(%s %p)\n", This, debugstr_guid( riid ), ppvObject );
842 *ppvObject = NULL;
844 if ( IsEqualGUID( riid, &IID_IUnknown ) ||
845 IsEqualGUID( riid, &IID_IDispatch ) ||
846 IsEqualGUID( riid, &IID_IXMLDOMNode ) ||
847 IsEqualGUID( riid, &IID_IXMLDOMDocument ) ||
848 IsEqualGUID( riid, &IID_IXMLDOMDocument2 )||
849 IsEqualGUID( riid, &IID_IXMLDOMDocument3 ))
851 *ppvObject = iface;
853 else if (IsEqualGUID(&IID_IPersistStream, riid) ||
854 IsEqualGUID(&IID_IPersistStreamInit, riid))
856 *ppvObject = &This->IPersistStreamInit_iface;
858 else if (IsEqualGUID(&IID_IObjectWithSite, riid))
860 *ppvObject = &This->IObjectWithSite_iface;
862 else if (IsEqualGUID(&IID_IObjectSafety, riid))
864 *ppvObject = &This->IObjectSafety_iface;
866 else if( IsEqualGUID( riid, &IID_ISupportErrorInfo ))
868 return node_create_supporterrorinfo(domdoc_se_tids, ppvObject);
870 else if(node_query_interface(&This->node, riid, ppvObject))
872 return *ppvObject ? S_OK : E_NOINTERFACE;
874 else if (IsEqualGUID( riid, &IID_IConnectionPointContainer ))
876 *ppvObject = &This->IConnectionPointContainer_iface;
878 else
880 TRACE("interface %s not implemented\n", debugstr_guid(riid));
881 return E_NOINTERFACE;
884 IUnknown_AddRef((IUnknown*)*ppvObject);
886 return S_OK;
889 static ULONG WINAPI domdoc_AddRef( IXMLDOMDocument3 *iface )
891 domdoc *This = impl_from_IXMLDOMDocument3( iface );
892 ULONG ref = InterlockedIncrement( &This->ref );
893 TRACE("(%p)->(%d)\n", This, ref );
894 return ref;
897 static ULONG WINAPI domdoc_Release( IXMLDOMDocument3 *iface )
899 domdoc *This = impl_from_IXMLDOMDocument3( iface );
900 LONG ref = InterlockedDecrement( &This->ref );
902 TRACE("(%p)->(%d)\n", This, ref );
904 if ( ref == 0 )
906 int eid;
908 if(This->bsc)
909 detach_bsc(This->bsc);
911 if (This->site)
912 IUnknown_Release( This->site );
913 destroy_xmlnode(&This->node);
914 if (This->stream)
915 IStream_Release(This->stream);
917 for (eid = 0; eid < EVENTID_LAST; eid++)
918 if (This->events[eid]) IDispatch_Release(This->events[eid]);
920 release_namespaces(This);
921 heap_free(This);
924 return ref;
927 static HRESULT WINAPI domdoc_GetTypeInfoCount( IXMLDOMDocument3 *iface, UINT* pctinfo )
929 domdoc *This = impl_from_IXMLDOMDocument3( iface );
930 return IDispatchEx_GetTypeInfoCount(&This->node.dispex.IDispatchEx_iface, pctinfo);
933 static HRESULT WINAPI domdoc_GetTypeInfo(
934 IXMLDOMDocument3 *iface,
935 UINT iTInfo, LCID lcid, ITypeInfo** ppTInfo )
937 domdoc *This = impl_from_IXMLDOMDocument3( iface );
938 return IDispatchEx_GetTypeInfo(&This->node.dispex.IDispatchEx_iface, iTInfo, lcid, ppTInfo);
941 static HRESULT WINAPI domdoc_GetIDsOfNames(
942 IXMLDOMDocument3 *iface,
943 REFIID riid,
944 LPOLESTR* rgszNames,
945 UINT cNames,
946 LCID lcid,
947 DISPID* rgDispId)
949 domdoc *This = impl_from_IXMLDOMDocument3( iface );
950 return IDispatchEx_GetIDsOfNames(&This->node.dispex.IDispatchEx_iface,
951 riid, rgszNames, cNames, lcid, rgDispId);
954 static HRESULT WINAPI domdoc_Invoke(
955 IXMLDOMDocument3 *iface,
956 DISPID dispIdMember,
957 REFIID riid,
958 LCID lcid,
959 WORD wFlags,
960 DISPPARAMS* pDispParams,
961 VARIANT* pVarResult,
962 EXCEPINFO* pExcepInfo,
963 UINT* puArgErr)
965 domdoc *This = impl_from_IXMLDOMDocument3( iface );
966 return IDispatchEx_Invoke(&This->node.dispex.IDispatchEx_iface,
967 dispIdMember, riid, lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
970 static HRESULT WINAPI domdoc_get_nodeName(
971 IXMLDOMDocument3 *iface,
972 BSTR* name )
974 domdoc *This = impl_from_IXMLDOMDocument3( iface );
976 static const WCHAR documentW[] = {'#','d','o','c','u','m','e','n','t',0};
978 TRACE("(%p)->(%p)\n", This, name);
980 return return_bstr(documentW, name);
984 static HRESULT WINAPI domdoc_get_nodeValue(
985 IXMLDOMDocument3 *iface,
986 VARIANT* value )
988 domdoc *This = impl_from_IXMLDOMDocument3( iface );
990 TRACE("(%p)->(%p)\n", This, value);
992 if(!value)
993 return E_INVALIDARG;
995 V_VT(value) = VT_NULL;
996 V_BSTR(value) = NULL; /* tests show that we should do this */
997 return S_FALSE;
1001 static HRESULT WINAPI domdoc_put_nodeValue(
1002 IXMLDOMDocument3 *iface,
1003 VARIANT value)
1005 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1006 TRACE("(%p)->(%s)\n", This, debugstr_variant(&value));
1007 return E_FAIL;
1011 static HRESULT WINAPI domdoc_get_nodeType(
1012 IXMLDOMDocument3 *iface,
1013 DOMNodeType* type )
1015 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1017 TRACE("(%p)->(%p)\n", This, type);
1019 *type = NODE_DOCUMENT;
1020 return S_OK;
1024 static HRESULT WINAPI domdoc_get_parentNode(
1025 IXMLDOMDocument3 *iface,
1026 IXMLDOMNode** parent )
1028 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1030 TRACE("(%p)->(%p)\n", This, parent);
1032 return node_get_parent(&This->node, parent);
1036 static HRESULT WINAPI domdoc_get_childNodes(
1037 IXMLDOMDocument3 *iface,
1038 IXMLDOMNodeList** childList )
1040 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1042 TRACE("(%p)->(%p)\n", This, childList);
1044 return node_get_child_nodes(&This->node, childList);
1048 static HRESULT WINAPI domdoc_get_firstChild(
1049 IXMLDOMDocument3 *iface,
1050 IXMLDOMNode** firstChild )
1052 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1054 TRACE("(%p)->(%p)\n", This, firstChild);
1056 return node_get_first_child(&This->node, firstChild);
1060 static HRESULT WINAPI domdoc_get_lastChild(
1061 IXMLDOMDocument3 *iface,
1062 IXMLDOMNode** lastChild )
1064 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1066 TRACE("(%p)->(%p)\n", This, lastChild);
1068 return node_get_last_child(&This->node, lastChild);
1072 static HRESULT WINAPI domdoc_get_previousSibling(
1073 IXMLDOMDocument3 *iface,
1074 IXMLDOMNode** previousSibling )
1076 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1078 TRACE("(%p)->(%p)\n", This, previousSibling);
1080 return return_null_node(previousSibling);
1084 static HRESULT WINAPI domdoc_get_nextSibling(
1085 IXMLDOMDocument3 *iface,
1086 IXMLDOMNode** nextSibling )
1088 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1090 TRACE("(%p)->(%p)\n", This, nextSibling);
1092 return return_null_node(nextSibling);
1096 static HRESULT WINAPI domdoc_get_attributes(
1097 IXMLDOMDocument3 *iface,
1098 IXMLDOMNamedNodeMap** attributeMap )
1100 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1102 TRACE("(%p)->(%p)\n", This, attributeMap);
1104 return return_null_ptr((void**)attributeMap);
1108 static HRESULT WINAPI domdoc_insertBefore(
1109 IXMLDOMDocument3 *iface,
1110 IXMLDOMNode* newChild,
1111 VARIANT refChild,
1112 IXMLDOMNode** outNewChild )
1114 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1116 TRACE("(%p)->(%p %s %p)\n", This, newChild, debugstr_variant(&refChild), outNewChild);
1118 return node_insert_before(&This->node, newChild, &refChild, outNewChild);
1122 static HRESULT WINAPI domdoc_replaceChild(
1123 IXMLDOMDocument3 *iface,
1124 IXMLDOMNode* newChild,
1125 IXMLDOMNode* oldChild,
1126 IXMLDOMNode** outOldChild)
1128 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1130 TRACE("(%p)->(%p %p %p)\n", This, newChild, oldChild, outOldChild);
1132 return node_replace_child(&This->node, newChild, oldChild, outOldChild);
1136 static HRESULT WINAPI domdoc_removeChild(
1137 IXMLDOMDocument3 *iface,
1138 IXMLDOMNode *child,
1139 IXMLDOMNode **oldChild)
1141 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1142 TRACE("(%p)->(%p %p)\n", This, child, oldChild);
1143 return node_remove_child(&This->node, child, oldChild);
1147 static HRESULT WINAPI domdoc_appendChild(
1148 IXMLDOMDocument3 *iface,
1149 IXMLDOMNode *child,
1150 IXMLDOMNode **outChild)
1152 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1153 TRACE("(%p)->(%p %p)\n", This, child, outChild);
1154 return node_append_child(&This->node, child, outChild);
1158 static HRESULT WINAPI domdoc_hasChildNodes(
1159 IXMLDOMDocument3 *iface,
1160 VARIANT_BOOL *ret)
1162 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1163 TRACE("(%p)->(%p)\n", This, ret);
1164 return node_has_childnodes(&This->node, ret);
1168 static HRESULT WINAPI domdoc_get_ownerDocument(
1169 IXMLDOMDocument3 *iface,
1170 IXMLDOMDocument **doc)
1172 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1173 TRACE("(%p)->(%p)\n", This, doc);
1174 return node_get_owner_doc(&This->node, doc);
1178 static HRESULT WINAPI domdoc_cloneNode(
1179 IXMLDOMDocument3 *iface,
1180 VARIANT_BOOL deep,
1181 IXMLDOMNode** outNode)
1183 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1184 TRACE("(%p)->(%d %p)\n", This, deep, outNode);
1185 return node_clone( &This->node, deep, outNode );
1189 static HRESULT WINAPI domdoc_get_nodeTypeString(
1190 IXMLDOMDocument3 *iface,
1191 BSTR *p)
1193 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1194 static const WCHAR documentW[] = {'d','o','c','u','m','e','n','t',0};
1196 TRACE("(%p)->(%p)\n", This, p);
1198 return return_bstr(documentW, p);
1202 static HRESULT WINAPI domdoc_get_text(
1203 IXMLDOMDocument3 *iface,
1204 BSTR *p)
1206 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1207 TRACE("(%p)->(%p)\n", This, p);
1208 return node_get_text(&This->node, p);
1212 static HRESULT WINAPI domdoc_put_text(
1213 IXMLDOMDocument3 *iface,
1214 BSTR text )
1216 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1217 TRACE("(%p)->(%s)\n", This, debugstr_w(text));
1218 return E_FAIL;
1222 static HRESULT WINAPI domdoc_get_specified(
1223 IXMLDOMDocument3 *iface,
1224 VARIANT_BOOL* isSpecified )
1226 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1227 FIXME("(%p)->(%p) stub!\n", This, isSpecified);
1228 *isSpecified = VARIANT_TRUE;
1229 return S_OK;
1233 static HRESULT WINAPI domdoc_get_definition(
1234 IXMLDOMDocument3 *iface,
1235 IXMLDOMNode** definitionNode )
1237 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1238 FIXME("(%p)->(%p)\n", This, definitionNode);
1239 return E_NOTIMPL;
1243 static HRESULT WINAPI domdoc_get_nodeTypedValue(
1244 IXMLDOMDocument3 *iface,
1245 VARIANT* v )
1247 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1248 TRACE("(%p)->(%p)\n", This, v);
1249 return return_null_var(v);
1252 static HRESULT WINAPI domdoc_put_nodeTypedValue(
1253 IXMLDOMDocument3 *iface,
1254 VARIANT typedValue )
1256 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1257 FIXME("(%p)->(%s)\n", This, debugstr_variant(&typedValue));
1258 return E_NOTIMPL;
1262 static HRESULT WINAPI domdoc_get_dataType(
1263 IXMLDOMDocument3 *iface,
1264 VARIANT* typename )
1266 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1267 TRACE("(%p)->(%p)\n", This, typename);
1268 return return_null_var( typename );
1272 static HRESULT WINAPI domdoc_put_dataType(
1273 IXMLDOMDocument3 *iface,
1274 BSTR dataTypeName )
1276 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1278 FIXME("(%p)->(%s)\n", This, debugstr_w(dataTypeName));
1280 if(!dataTypeName)
1281 return E_INVALIDARG;
1283 return E_FAIL;
1286 static int XMLCALL domdoc_get_xml_writecallback(void *ctx, const char *data, int len)
1288 return xmlBufferAdd((xmlBufferPtr)ctx, (xmlChar*)data, len) == 0 ? len : 0;
1291 static HRESULT WINAPI domdoc_get_xml(
1292 IXMLDOMDocument3 *iface,
1293 BSTR* p)
1295 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1296 xmlSaveCtxtPtr ctxt;
1297 xmlBufferPtr buf;
1298 int options;
1299 long ret;
1301 TRACE("(%p)->(%p)\n", This, p);
1303 if(!p)
1304 return E_INVALIDARG;
1306 *p = NULL;
1308 buf = xmlBufferCreate();
1309 if(!buf)
1310 return E_OUTOFMEMORY;
1312 options = XML_SAVE_FORMAT | XML_SAVE_NO_DECL;
1313 ctxt = xmlSaveToIO(domdoc_get_xml_writecallback, NULL, buf, "UTF-8", options);
1315 if(!ctxt)
1317 xmlBufferFree(buf);
1318 return E_OUTOFMEMORY;
1321 ret = xmlSaveDoc(ctxt, get_doc(This));
1322 /* flushes on close */
1323 xmlSaveClose(ctxt);
1325 TRACE("%ld, len=%d\n", ret, xmlBufferLength(buf));
1326 if(ret != -1 && xmlBufferLength(buf) > 0)
1328 BSTR content;
1330 content = bstr_from_xmlChar(xmlBufferContent(buf));
1331 content = EnsureCorrectEOL(content);
1333 *p = content;
1335 else
1337 *p = SysAllocStringLen(NULL, 0);
1340 xmlBufferFree(buf);
1342 return *p ? S_OK : E_OUTOFMEMORY;
1346 static HRESULT WINAPI domdoc_transformNode(
1347 IXMLDOMDocument3 *iface,
1348 IXMLDOMNode *node,
1349 BSTR *p)
1351 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1352 TRACE("(%p)->(%p %p)\n", This, node, p);
1353 return node_transform_node(&This->node, node, p);
1357 static HRESULT WINAPI domdoc_selectNodes(
1358 IXMLDOMDocument3 *iface,
1359 BSTR p,
1360 IXMLDOMNodeList **outList)
1362 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1363 TRACE("(%p)->(%s %p)\n", This, debugstr_w(p), outList);
1364 return node_select_nodes(&This->node, p, outList);
1368 static HRESULT WINAPI domdoc_selectSingleNode(
1369 IXMLDOMDocument3 *iface,
1370 BSTR p,
1371 IXMLDOMNode **outNode)
1373 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1374 TRACE("(%p)->(%s %p)\n", This, debugstr_w(p), outNode);
1375 return node_select_singlenode(&This->node, p, outNode);
1379 static HRESULT WINAPI domdoc_get_parsed(
1380 IXMLDOMDocument3 *iface,
1381 VARIANT_BOOL* isParsed )
1383 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1384 FIXME("(%p)->(%p) stub!\n", This, isParsed);
1385 *isParsed = VARIANT_TRUE;
1386 return S_OK;
1389 static HRESULT WINAPI domdoc_get_namespaceURI(
1390 IXMLDOMDocument3 *iface,
1391 BSTR* namespaceURI )
1393 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1394 TRACE("(%p)->(%p)\n", This, namespaceURI);
1395 return return_null_bstr( namespaceURI );
1398 static HRESULT WINAPI domdoc_get_prefix(
1399 IXMLDOMDocument3 *iface,
1400 BSTR* prefix )
1402 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1403 TRACE("(%p)->(%p)\n", This, prefix);
1404 return return_null_bstr( prefix );
1408 static HRESULT WINAPI domdoc_get_baseName(
1409 IXMLDOMDocument3 *iface,
1410 BSTR* name )
1412 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1413 TRACE("(%p)->(%p)\n", This, name);
1414 return return_null_bstr( name );
1418 static HRESULT WINAPI domdoc_transformNodeToObject(
1419 IXMLDOMDocument3 *iface,
1420 IXMLDOMNode* stylesheet,
1421 VARIANT outputObject)
1423 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1424 FIXME("(%p)->(%p %s)\n", This, stylesheet, debugstr_variant(&outputObject));
1425 return E_NOTIMPL;
1429 static HRESULT WINAPI domdoc_get_doctype(
1430 IXMLDOMDocument3 *iface,
1431 IXMLDOMDocumentType** doctype )
1433 domdoc *This = impl_from_IXMLDOMDocument3(iface);
1434 IXMLDOMNode *node;
1435 xmlDtdPtr dtd;
1436 HRESULT hr;
1438 TRACE("(%p)->(%p)\n", This, doctype);
1440 if (!doctype) return E_INVALIDARG;
1442 *doctype = NULL;
1444 dtd = xmlGetIntSubset(get_doc(This));
1445 if (!dtd) return S_FALSE;
1447 node = create_node((xmlNodePtr)dtd);
1448 if (!node) return S_FALSE;
1450 hr = IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMDocumentType, (void**)doctype);
1451 IXMLDOMNode_Release(node);
1453 return hr;
1457 static HRESULT WINAPI domdoc_get_implementation(
1458 IXMLDOMDocument3 *iface,
1459 IXMLDOMImplementation** impl )
1461 domdoc *This = impl_from_IXMLDOMDocument3(iface);
1463 TRACE("(%p)->(%p)\n", This, impl);
1465 if(!impl)
1466 return E_INVALIDARG;
1468 *impl = (IXMLDOMImplementation*)create_doc_Implementation();
1470 return S_OK;
1473 static HRESULT WINAPI domdoc_get_documentElement(
1474 IXMLDOMDocument3 *iface,
1475 IXMLDOMElement** DOMElement )
1477 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1478 IXMLDOMNode *element_node;
1479 xmlNodePtr root;
1480 HRESULT hr;
1482 TRACE("(%p)->(%p)\n", This, DOMElement);
1484 if(!DOMElement)
1485 return E_INVALIDARG;
1487 *DOMElement = NULL;
1489 root = xmlDocGetRootElement( get_doc(This) );
1490 if ( !root )
1491 return S_FALSE;
1493 element_node = create_node( root );
1494 if(!element_node) return S_FALSE;
1496 hr = IXMLDOMNode_QueryInterface(element_node, &IID_IXMLDOMElement, (void**)DOMElement);
1497 IXMLDOMNode_Release(element_node);
1499 return hr;
1503 static HRESULT WINAPI domdoc_put_documentElement(
1504 IXMLDOMDocument3 *iface,
1505 IXMLDOMElement* DOMElement )
1507 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1508 IXMLDOMNode *elementNode;
1509 xmlNodePtr oldRoot;
1510 xmlnode *xmlNode;
1511 HRESULT hr;
1513 TRACE("(%p)->(%p)\n", This, DOMElement);
1515 hr = IXMLDOMElement_QueryInterface( DOMElement, &IID_IXMLDOMNode, (void**)&elementNode );
1516 if(FAILED(hr))
1517 return hr;
1519 xmlNode = get_node_obj( elementNode );
1520 if(!xmlNode) return E_FAIL;
1522 if(!xmlNode->node->parent)
1523 if(xmldoc_remove_orphan(xmlNode->node->doc, xmlNode->node) != S_OK)
1524 WARN("%p is not an orphan of %p\n", xmlNode->node->doc, xmlNode->node);
1526 oldRoot = xmlDocSetRootElement( get_doc(This), xmlNode->node);
1527 IXMLDOMNode_Release( elementNode );
1529 if(oldRoot)
1530 xmldoc_add_orphan(oldRoot->doc, oldRoot);
1532 return S_OK;
1536 static HRESULT WINAPI domdoc_createElement(
1537 IXMLDOMDocument3 *iface,
1538 BSTR tagname,
1539 IXMLDOMElement** element )
1541 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1542 IXMLDOMNode *node;
1543 VARIANT type;
1544 HRESULT hr;
1546 TRACE("(%p)->(%s %p)\n", This, debugstr_w(tagname), element);
1548 if (!element || !tagname) return E_INVALIDARG;
1550 V_VT(&type) = VT_I1;
1551 V_I1(&type) = NODE_ELEMENT;
1553 hr = IXMLDOMDocument3_createNode(iface, type, tagname, NULL, &node);
1554 if (hr == S_OK)
1556 IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMElement, (void**)element);
1557 IXMLDOMNode_Release(node);
1560 return hr;
1564 static HRESULT WINAPI domdoc_createDocumentFragment(
1565 IXMLDOMDocument3 *iface,
1566 IXMLDOMDocumentFragment** frag )
1568 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1569 IXMLDOMNode *node;
1570 VARIANT type;
1571 HRESULT hr;
1573 TRACE("(%p)->(%p)\n", This, frag);
1575 if (!frag) return E_INVALIDARG;
1577 *frag = NULL;
1579 V_VT(&type) = VT_I1;
1580 V_I1(&type) = NODE_DOCUMENT_FRAGMENT;
1582 hr = IXMLDOMDocument3_createNode(iface, type, NULL, NULL, &node);
1583 if (hr == S_OK)
1585 IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMDocumentFragment, (void**)frag);
1586 IXMLDOMNode_Release(node);
1589 return hr;
1593 static HRESULT WINAPI domdoc_createTextNode(
1594 IXMLDOMDocument3 *iface,
1595 BSTR data,
1596 IXMLDOMText** text )
1598 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1599 IXMLDOMNode *node;
1600 VARIANT type;
1601 HRESULT hr;
1603 TRACE("(%p)->(%s %p)\n", This, debugstr_w(data), text);
1605 if (!text) return E_INVALIDARG;
1607 *text = NULL;
1609 V_VT(&type) = VT_I1;
1610 V_I1(&type) = NODE_TEXT;
1612 hr = IXMLDOMDocument3_createNode(iface, type, NULL, NULL, &node);
1613 if (hr == S_OK)
1615 IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMText, (void**)text);
1616 IXMLDOMNode_Release(node);
1617 hr = IXMLDOMText_put_data(*text, data);
1620 return hr;
1624 static HRESULT WINAPI domdoc_createComment(
1625 IXMLDOMDocument3 *iface,
1626 BSTR data,
1627 IXMLDOMComment** comment )
1629 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1630 VARIANT type;
1631 HRESULT hr;
1632 IXMLDOMNode *node;
1634 TRACE("(%p)->(%s %p)\n", This, debugstr_w(data), comment);
1636 if (!comment) return E_INVALIDARG;
1638 *comment = NULL;
1640 V_VT(&type) = VT_I1;
1641 V_I1(&type) = NODE_COMMENT;
1643 hr = IXMLDOMDocument3_createNode(iface, type, NULL, NULL, &node);
1644 if (hr == S_OK)
1646 IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMComment, (void**)comment);
1647 IXMLDOMNode_Release(node);
1648 hr = IXMLDOMComment_put_data(*comment, data);
1651 return hr;
1655 static HRESULT WINAPI domdoc_createCDATASection(
1656 IXMLDOMDocument3 *iface,
1657 BSTR data,
1658 IXMLDOMCDATASection** cdata )
1660 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1661 IXMLDOMNode *node;
1662 VARIANT type;
1663 HRESULT hr;
1665 TRACE("(%p)->(%s %p)\n", This, debugstr_w(data), cdata);
1667 if (!cdata) return E_INVALIDARG;
1669 *cdata = NULL;
1671 V_VT(&type) = VT_I1;
1672 V_I1(&type) = NODE_CDATA_SECTION;
1674 hr = IXMLDOMDocument3_createNode(iface, type, NULL, NULL, &node);
1675 if (hr == S_OK)
1677 IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMCDATASection, (void**)cdata);
1678 IXMLDOMNode_Release(node);
1679 hr = IXMLDOMCDATASection_put_data(*cdata, data);
1682 return hr;
1686 static HRESULT WINAPI domdoc_createProcessingInstruction(
1687 IXMLDOMDocument3 *iface,
1688 BSTR target,
1689 BSTR data,
1690 IXMLDOMProcessingInstruction** pi )
1692 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1693 IXMLDOMNode *node;
1694 VARIANT type;
1695 HRESULT hr;
1697 TRACE("(%p)->(%s %s %p)\n", This, debugstr_w(target), debugstr_w(data), pi);
1699 if (!pi) return E_INVALIDARG;
1701 *pi = NULL;
1703 V_VT(&type) = VT_I1;
1704 V_I1(&type) = NODE_PROCESSING_INSTRUCTION;
1706 hr = IXMLDOMDocument3_createNode(iface, type, target, NULL, &node);
1707 if (hr == S_OK)
1709 xmlnode *node_obj;
1711 /* this is to bypass check in ::put_data() that blocks "<?xml" PIs */
1712 node_obj = get_node_obj(node);
1713 hr = node_set_content(node_obj, data);
1715 IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMProcessingInstruction, (void**)pi);
1716 IXMLDOMNode_Release(node);
1719 return hr;
1723 static HRESULT WINAPI domdoc_createAttribute(
1724 IXMLDOMDocument3 *iface,
1725 BSTR name,
1726 IXMLDOMAttribute** attribute )
1728 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1729 IXMLDOMNode *node;
1730 VARIANT type;
1731 HRESULT hr;
1733 TRACE("(%p)->(%s %p)\n", This, debugstr_w(name), attribute);
1735 if (!attribute || !name) return E_INVALIDARG;
1737 V_VT(&type) = VT_I1;
1738 V_I1(&type) = NODE_ATTRIBUTE;
1740 hr = IXMLDOMDocument3_createNode(iface, type, name, NULL, &node);
1741 if (hr == S_OK)
1743 IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMAttribute, (void**)attribute);
1744 IXMLDOMNode_Release(node);
1747 return hr;
1751 static HRESULT WINAPI domdoc_createEntityReference(
1752 IXMLDOMDocument3 *iface,
1753 BSTR name,
1754 IXMLDOMEntityReference** entityref )
1756 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1757 IXMLDOMNode *node;
1758 VARIANT type;
1759 HRESULT hr;
1761 TRACE("(%p)->(%s %p)\n", This, debugstr_w(name), entityref);
1763 if (!entityref) return E_INVALIDARG;
1765 *entityref = NULL;
1767 V_VT(&type) = VT_I1;
1768 V_I1(&type) = NODE_ENTITY_REFERENCE;
1770 hr = IXMLDOMDocument3_createNode(iface, type, name, NULL, &node);
1771 if (hr == S_OK)
1773 IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMEntityReference, (void**)entityref);
1774 IXMLDOMNode_Release(node);
1777 return hr;
1780 xmlChar* tagName_to_XPath(const BSTR tagName)
1782 xmlChar *query, *tmp;
1783 static const xmlChar mod_pre[] = "*[local-name()='";
1784 static const xmlChar mod_post[] = "']";
1785 static const xmlChar prefix[] = "descendant::";
1786 const WCHAR *tokBegin, *tokEnd;
1787 int len;
1789 query = xmlStrdup(prefix);
1791 tokBegin = tagName;
1792 while (tokBegin && *tokBegin)
1794 switch (*tokBegin)
1796 case '/':
1797 query = xmlStrcat(query, BAD_CAST "/");
1798 ++tokBegin;
1799 break;
1800 case '*':
1801 query = xmlStrcat(query, BAD_CAST "*");
1802 ++tokBegin;
1803 break;
1804 default:
1805 query = xmlStrcat(query, mod_pre);
1806 tokEnd = tokBegin;
1807 while (*tokEnd && *tokEnd != '/')
1808 ++tokEnd;
1809 len = WideCharToMultiByte(CP_UTF8, 0, tokBegin, tokEnd-tokBegin, NULL, 0, NULL, NULL);
1810 tmp = xmlMalloc(len);
1811 WideCharToMultiByte(CP_UTF8, 0, tokBegin, tokEnd-tokBegin, (char*)tmp, len, NULL, NULL);
1812 query = xmlStrncat(query, tmp, len);
1813 xmlFree(tmp);
1814 tokBegin = tokEnd;
1815 query = xmlStrcat(query, mod_post);
1819 return query;
1822 static HRESULT WINAPI domdoc_getElementsByTagName(
1823 IXMLDOMDocument3 *iface,
1824 BSTR tagName,
1825 IXMLDOMNodeList** resultList )
1827 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1828 xmlChar *query;
1829 HRESULT hr;
1830 BOOL XPath;
1832 TRACE("(%p)->(%s, %p)\n", This, debugstr_w(tagName), resultList);
1834 if (!tagName || !resultList) return E_INVALIDARG;
1836 XPath = This->properties->XPath;
1837 This->properties->XPath = TRUE;
1838 query = tagName_to_XPath(tagName);
1839 hr = create_selection((xmlNodePtr)get_doc(This), query, resultList);
1840 xmlFree(query);
1841 This->properties->XPath = XPath;
1843 return hr;
1846 static HRESULT get_node_type(VARIANT Type, DOMNodeType * type)
1848 VARIANT tmp;
1849 HRESULT hr;
1851 VariantInit(&tmp);
1852 hr = VariantChangeType(&tmp, &Type, 0, VT_I4);
1853 if(FAILED(hr))
1854 return E_INVALIDARG;
1856 *type = V_I4(&tmp);
1858 return S_OK;
1861 static HRESULT WINAPI domdoc_createNode(
1862 IXMLDOMDocument3 *iface,
1863 VARIANT Type,
1864 BSTR name,
1865 BSTR namespaceURI,
1866 IXMLDOMNode** node )
1868 domdoc *This = impl_from_IXMLDOMDocument3( iface );
1869 DOMNodeType node_type;
1870 xmlNodePtr xmlnode;
1871 xmlChar *xml_name, *href;
1872 HRESULT hr;
1874 TRACE("(%p)->(%s %s %s %p)\n", This, debugstr_variant(&Type), debugstr_w(name), debugstr_w(namespaceURI), node);
1876 if(!node) return E_INVALIDARG;
1878 hr = get_node_type(Type, &node_type);
1879 if(FAILED(hr)) return hr;
1881 if(namespaceURI && namespaceURI[0] && node_type != NODE_ELEMENT)
1882 FIXME("nodes with namespaces currently not supported.\n");
1884 TRACE("node_type %d\n", node_type);
1886 /* exit earlier for types that need name */
1887 switch(node_type)
1889 case NODE_ELEMENT:
1890 case NODE_ATTRIBUTE:
1891 case NODE_ENTITY_REFERENCE:
1892 case NODE_PROCESSING_INSTRUCTION:
1893 if (!name || *name == 0) return E_FAIL;
1894 break;
1895 default:
1896 break;
1899 xml_name = xmlchar_from_wchar(name);
1900 /* prevent empty href to be allocated */
1901 href = namespaceURI ? xmlchar_from_wchar(namespaceURI) : NULL;
1903 switch(node_type)
1905 case NODE_ELEMENT:
1907 xmlChar *local, *prefix;
1909 local = xmlSplitQName2(xml_name, &prefix);
1911 xmlnode = xmlNewDocNode(get_doc(This), NULL, local ? local : xml_name, NULL);
1913 /* allow to create default namespace xmlns= */
1914 if (local || (href && *href))
1916 xmlNsPtr ns = xmlNewNs(xmlnode, href, prefix);
1917 xmlSetNs(xmlnode, ns);
1920 xmlFree(local);
1921 xmlFree(prefix);
1923 break;
1925 case NODE_ATTRIBUTE:
1926 xmlnode = (xmlNodePtr)xmlNewDocProp(get_doc(This), xml_name, NULL);
1927 break;
1928 case NODE_TEXT:
1929 xmlnode = (xmlNodePtr)xmlNewDocText(get_doc(This), NULL);
1930 break;
1931 case NODE_CDATA_SECTION:
1932 xmlnode = xmlNewCDataBlock(get_doc(This), NULL, 0);
1933 break;
1934 case NODE_ENTITY_REFERENCE:
1935 xmlnode = xmlNewReference(get_doc(This), xml_name);
1936 break;
1937 case NODE_PROCESSING_INSTRUCTION:
1938 #ifdef HAVE_XMLNEWDOCPI
1939 xmlnode = xmlNewDocPI(get_doc(This), xml_name, NULL);
1940 #else
1941 FIXME("xmlNewDocPI() not supported, use libxml2 2.6.15 or greater\n");
1942 xmlnode = NULL;
1943 #endif
1944 break;
1945 case NODE_COMMENT:
1946 xmlnode = xmlNewDocComment(get_doc(This), NULL);
1947 break;
1948 case NODE_DOCUMENT_FRAGMENT:
1949 xmlnode = xmlNewDocFragment(get_doc(This));
1950 break;
1951 /* unsupported types */
1952 case NODE_DOCUMENT:
1953 case NODE_DOCUMENT_TYPE:
1954 case NODE_ENTITY:
1955 case NODE_NOTATION:
1956 heap_free(xml_name);
1957 return E_INVALIDARG;
1958 default:
1959 FIXME("unhandled node type %d\n", node_type);
1960 xmlnode = NULL;
1961 break;
1964 *node = create_node(xmlnode);
1965 heap_free(xml_name);
1966 heap_free(href);
1968 if(*node)
1970 TRACE("created node (%d, %p, %p)\n", node_type, *node, xmlnode);
1971 xmldoc_add_orphan(xmlnode->doc, xmlnode);
1972 return S_OK;
1975 return E_FAIL;
1978 static HRESULT WINAPI domdoc_nodeFromID(
1979 IXMLDOMDocument3 *iface,
1980 BSTR idString,
1981 IXMLDOMNode** node )
1983 domdoc *This = impl_from_IXMLDOMDocument3(iface);
1984 FIXME("(%p)->(%s %p)\n", This, debugstr_w(idString), node);
1985 return E_NOTIMPL;
1988 static HRESULT domdoc_onDataAvailable(void *obj, char *ptr, DWORD len)
1990 domdoc *This = obj;
1991 xmlDocPtr xmldoc;
1993 xmldoc = doparse(This, ptr, len, XML_CHAR_ENCODING_NONE);
1994 if(xmldoc) {
1995 xmldoc->_private = create_priv();
1996 return attach_xmldoc(This, xmldoc);
1999 return S_OK;
2002 static HRESULT domdoc_load_moniker(domdoc *This, IMoniker *mon)
2004 bsc_t *bsc;
2005 HRESULT hr;
2007 hr = bind_url(mon, domdoc_onDataAvailable, This, &bsc);
2008 if(FAILED(hr))
2009 return hr;
2011 if(This->bsc) {
2012 hr = detach_bsc(This->bsc);
2013 if(FAILED(hr))
2014 return hr;
2017 This->bsc = bsc;
2018 return S_OK;
2021 static HRESULT WINAPI domdoc_load(
2022 IXMLDOMDocument3 *iface,
2023 VARIANT source,
2024 VARIANT_BOOL* isSuccessful )
2026 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2027 LPWSTR filename = NULL;
2028 HRESULT hr = S_FALSE;
2029 IXMLDOMDocument3 *pNewDoc = NULL;
2030 IStream *pStream = NULL;
2031 xmlDocPtr xmldoc;
2033 TRACE("(%p)->(%s)\n", This, debugstr_variant(&source));
2035 if (!isSuccessful)
2036 return E_POINTER;
2037 *isSuccessful = VARIANT_FALSE;
2039 assert( &This->node );
2041 switch( V_VT(&source) )
2043 case VT_BSTR:
2044 filename = V_BSTR(&source);
2045 break;
2046 case VT_BSTR|VT_BYREF:
2047 if (!V_BSTRREF(&source)) return E_INVALIDARG;
2048 filename = *V_BSTRREF(&source);
2049 break;
2050 case VT_ARRAY|VT_UI1:
2052 SAFEARRAY *psa = V_ARRAY(&source);
2053 char *str;
2054 LONG len;
2055 UINT dim = SafeArrayGetDim(psa);
2057 switch (dim)
2059 case 0:
2060 ERR("SAFEARRAY == NULL\n");
2061 hr = This->error = E_INVALIDARG;
2062 break;
2063 case 1:
2064 /* Only takes UTF-8 strings.
2065 * NOT NULL-terminated. */
2066 SafeArrayAccessData(psa, (void**)&str);
2067 SafeArrayGetUBound(psa, 1, &len);
2069 if ((xmldoc = doparse(This, str, ++len, XML_CHAR_ENCODING_UTF8)))
2071 hr = This->error = S_OK;
2072 *isSuccessful = VARIANT_TRUE;
2073 TRACE("parsed document %p\n", xmldoc);
2075 else
2077 This->error = E_FAIL;
2078 TRACE("failed to parse document\n");
2081 SafeArrayUnaccessData(psa);
2083 if(xmldoc)
2085 xmldoc->_private = create_priv();
2086 return attach_xmldoc(This, xmldoc);
2088 break;
2089 default:
2090 FIXME("unhandled SAFEARRAY dim: %d\n", dim);
2091 hr = This->error = E_NOTIMPL;
2094 break;
2095 case VT_UNKNOWN:
2096 if (!V_UNKNOWN(&source)) return E_INVALIDARG;
2097 hr = IUnknown_QueryInterface(V_UNKNOWN(&source), &IID_IXMLDOMDocument3, (void**)&pNewDoc);
2098 if(hr == S_OK)
2100 if(pNewDoc)
2102 domdoc *newDoc = impl_from_IXMLDOMDocument3( pNewDoc );
2104 xmldoc = xmlCopyDoc(get_doc(newDoc), 1);
2105 xmldoc->_private = create_priv();
2106 hr = attach_xmldoc(This, xmldoc);
2108 if(SUCCEEDED(hr))
2109 *isSuccessful = VARIANT_TRUE;
2111 return hr;
2114 hr = IUnknown_QueryInterface(V_UNKNOWN(&source), &IID_IStream, (void**)&pStream);
2115 if(hr == S_OK)
2117 IPersistStream *pDocStream;
2118 hr = IUnknown_QueryInterface(iface, &IID_IPersistStream, (void**)&pDocStream);
2119 if(hr == S_OK)
2121 hr = IPersistStream_Load(pDocStream, pStream);
2122 IStream_Release(pStream);
2123 if(hr == S_OK)
2125 *isSuccessful = VARIANT_TRUE;
2127 TRACE("Using IStream to load Document\n");
2128 return S_OK;
2130 else
2132 ERR("xmldoc_IPersistStream_Load failed (%d)\n", hr);
2135 else
2137 ERR("QueryInterface IID_IPersistStream failed (%d)\n", hr);
2140 else
2142 /* ISequentialStream */
2143 FIXME("Unknown type not supported (%d) (%p)(%p)\n", hr, pNewDoc, V_UNKNOWN(&source)->lpVtbl);
2145 break;
2146 default:
2147 FIXME("VT type not supported (%d)\n", V_VT(&source));
2150 if ( filename )
2152 IMoniker *mon;
2154 hr = create_moniker_from_url( filename, &mon);
2155 if ( SUCCEEDED(hr) )
2157 hr = domdoc_load_moniker( This, mon );
2158 IMoniker_Release(mon);
2161 if ( FAILED(hr) )
2162 This->error = E_FAIL;
2163 else
2165 hr = This->error = S_OK;
2166 *isSuccessful = VARIANT_TRUE;
2170 if(!filename || FAILED(hr)) {
2171 xmldoc = xmlNewDoc(NULL);
2172 xmldoc->_private = create_priv();
2173 hr = attach_xmldoc(This, xmldoc);
2174 if(SUCCEEDED(hr))
2175 hr = S_FALSE;
2178 TRACE("ret (%d)\n", hr);
2180 return hr;
2184 static HRESULT WINAPI domdoc_get_readyState(
2185 IXMLDOMDocument3 *iface,
2186 LONG *value )
2188 domdoc *This = impl_from_IXMLDOMDocument3(iface);
2189 FIXME("stub! (%p)->(%p)\n", This, value);
2191 if (!value)
2192 return E_INVALIDARG;
2194 *value = READYSTATE_COMPLETE;
2195 return S_OK;
2199 static HRESULT WINAPI domdoc_get_parseError(
2200 IXMLDOMDocument3 *iface,
2201 IXMLDOMParseError** errorObj )
2203 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2204 static const WCHAR err[] = {'e','r','r','o','r',0};
2205 BSTR error_string = NULL;
2207 FIXME("(%p)->(%p): creating a dummy parseError\n", iface, errorObj);
2209 if(This->error)
2210 error_string = SysAllocString(err);
2212 *errorObj = create_parseError(This->error, NULL, error_string, NULL, 0, 0, 0);
2213 if(!*errorObj) return E_OUTOFMEMORY;
2214 return S_OK;
2218 static HRESULT WINAPI domdoc_get_url(
2219 IXMLDOMDocument3 *iface,
2220 BSTR* urlString )
2222 domdoc *This = impl_from_IXMLDOMDocument3(iface);
2223 FIXME("(%p)->(%p)\n", This, urlString);
2224 return E_NOTIMPL;
2228 static HRESULT WINAPI domdoc_get_async(
2229 IXMLDOMDocument3 *iface,
2230 VARIANT_BOOL* isAsync )
2232 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2234 TRACE("(%p)->(%p: %d)\n", This, isAsync, This->async);
2235 *isAsync = This->async;
2236 return S_OK;
2240 static HRESULT WINAPI domdoc_put_async(
2241 IXMLDOMDocument3 *iface,
2242 VARIANT_BOOL isAsync )
2244 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2246 TRACE("(%p)->(%d)\n", This, isAsync);
2247 This->async = isAsync;
2248 return S_OK;
2252 static HRESULT WINAPI domdoc_abort(
2253 IXMLDOMDocument3 *iface )
2255 domdoc *This = impl_from_IXMLDOMDocument3(iface);
2256 FIXME("%p\n", This);
2257 return E_NOTIMPL;
2260 /* don't rely on data to be in BSTR format, treat it as WCHAR string */
2261 static HRESULT WINAPI domdoc_loadXML(
2262 IXMLDOMDocument3 *iface,
2263 BSTR data,
2264 VARIANT_BOOL* isSuccessful )
2266 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2267 xmlDocPtr xmldoc = NULL;
2268 HRESULT hr = S_FALSE, hr2;
2270 TRACE("(%p)->(%s %p)\n", This, debugstr_w(data), isSuccessful );
2272 assert ( &This->node );
2274 if ( isSuccessful )
2276 *isSuccessful = VARIANT_FALSE;
2278 if (data)
2280 WCHAR *ptr = data;
2282 /* skip leading spaces if needed */
2283 if (This->properties->version == MSXML_DEFAULT || This->properties->version == MSXML26)
2284 while (*ptr && isspaceW(*ptr)) ptr++;
2286 xmldoc = doparse(This, (char*)ptr, strlenW(ptr)*sizeof(WCHAR), XML_CHAR_ENCODING_UTF16LE);
2287 if ( !xmldoc )
2289 This->error = E_FAIL;
2290 TRACE("failed to parse document\n");
2292 else
2294 hr = This->error = S_OK;
2295 *isSuccessful = VARIANT_TRUE;
2296 TRACE("parsed document %p\n", xmldoc);
2301 if(!xmldoc)
2302 xmldoc = xmlNewDoc(NULL);
2303 xmldoc->_private = create_priv();
2304 hr2 = attach_xmldoc(This, xmldoc);
2305 if( FAILED(hr2) )
2306 hr = hr2;
2308 return hr;
2311 static int XMLCALL domdoc_save_writecallback(void *ctx, const char *buffer, int len)
2313 DWORD written = -1;
2315 if(!WriteFile(ctx, buffer, len, &written, NULL))
2317 WARN("write error\n");
2318 return -1;
2320 else
2321 return written;
2324 static int XMLCALL domdoc_save_closecallback(void *ctx)
2326 return CloseHandle(ctx) ? 0 : -1;
2329 static int XMLCALL domdoc_stream_save_writecallback(void *ctx, const char *buffer, int len)
2331 ULONG written = 0;
2332 HRESULT hr;
2334 hr = IStream_Write((IStream*)ctx, buffer, len, &written);
2335 TRACE("0x%08x %p %d %u\n", hr, buffer, len, written);
2336 if (hr != S_OK)
2338 WARN("stream write error: 0x%08x\n", hr);
2339 return -1;
2341 else
2342 return len;
2345 static int XMLCALL domdoc_stream_save_closecallback(void *ctx)
2347 IStream_Release((IStream*)ctx);
2348 return 0;
2351 static HRESULT WINAPI domdoc_save(
2352 IXMLDOMDocument3 *iface,
2353 VARIANT destination )
2355 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2356 xmlSaveCtxtPtr ctx = NULL;
2357 xmlNodePtr xmldecl;
2358 HRESULT ret = S_OK;
2360 TRACE("(%p)->(%s)\n", This, debugstr_variant(&destination));
2362 switch (V_VT(&destination))
2364 case VT_UNKNOWN:
2366 IUnknown *pUnk = V_UNKNOWN(&destination);
2367 IXMLDOMDocument3 *document;
2368 IStream *stream;
2370 ret = IUnknown_QueryInterface(pUnk, &IID_IXMLDOMDocument3, (void**)&document);
2371 if(ret == S_OK)
2373 VARIANT_BOOL success;
2374 BSTR xml;
2376 ret = IXMLDOMDocument3_get_xml(iface, &xml);
2377 if(ret == S_OK)
2379 ret = IXMLDOMDocument3_loadXML(document, xml, &success);
2380 SysFreeString(xml);
2383 IXMLDOMDocument3_Release(document);
2384 return ret;
2387 ret = IUnknown_QueryInterface(pUnk, &IID_IStream, (void**)&stream);
2388 if(ret == S_OK)
2390 int options = get_doc(This)->standalone == -1 ? XML_SAVE_NO_DECL : 0;
2391 ctx = xmlSaveToIO(domdoc_stream_save_writecallback,
2392 domdoc_stream_save_closecallback, stream, NULL, options);
2394 if(!ctx)
2396 IStream_Release(stream);
2397 return E_FAIL;
2401 break;
2403 case VT_BSTR:
2404 case VT_BSTR | VT_BYREF:
2406 int options = get_doc(This)->standalone == -1 ? XML_SAVE_NO_DECL : 0;
2408 /* save with file path */
2409 HANDLE handle = CreateFileW( (V_VT(&destination) & VT_BYREF)? *V_BSTRREF(&destination) : V_BSTR(&destination),
2410 GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL );
2411 if( handle == INVALID_HANDLE_VALUE )
2413 WARN("failed to create file\n");
2414 return E_FAIL;
2417 /* disable top XML declaration */
2418 ctx = xmlSaveToIO(domdoc_save_writecallback, domdoc_save_closecallback,
2419 handle, NULL, options);
2420 if (!ctx)
2422 CloseHandle(handle);
2423 return E_FAIL;
2426 break;
2428 default:
2429 FIXME("Unhandled VARIANT: %s\n", debugstr_variant(&destination));
2430 return S_FALSE;
2433 xmldecl = xmldoc_unlink_xmldecl(get_doc(This));
2434 if (xmlSaveDoc(ctx, get_doc(This)) == -1) ret = S_FALSE;
2435 xmldoc_link_xmldecl(get_doc(This), xmldecl);
2437 /* will release resources through close callback */
2438 xmlSaveClose(ctx);
2440 return ret;
2443 static HRESULT WINAPI domdoc_get_validateOnParse(
2444 IXMLDOMDocument3 *iface,
2445 VARIANT_BOOL* isValidating )
2447 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2448 TRACE("(%p)->(%p: %d)\n", This, isValidating, This->validating);
2449 *isValidating = This->validating;
2450 return S_OK;
2454 static HRESULT WINAPI domdoc_put_validateOnParse(
2455 IXMLDOMDocument3 *iface,
2456 VARIANT_BOOL isValidating )
2458 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2459 TRACE("(%p)->(%d)\n", This, isValidating);
2460 This->validating = isValidating;
2461 return S_OK;
2465 static HRESULT WINAPI domdoc_get_resolveExternals(
2466 IXMLDOMDocument3 *iface,
2467 VARIANT_BOOL* isResolving )
2469 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2470 TRACE("(%p)->(%p: %d)\n", This, isResolving, This->resolving);
2471 *isResolving = This->resolving;
2472 return S_OK;
2476 static HRESULT WINAPI domdoc_put_resolveExternals(
2477 IXMLDOMDocument3 *iface,
2478 VARIANT_BOOL isResolving )
2480 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2481 TRACE("(%p)->(%d)\n", This, isResolving);
2482 This->resolving = isResolving;
2483 return S_OK;
2487 static HRESULT WINAPI domdoc_get_preserveWhiteSpace(
2488 IXMLDOMDocument3 *iface,
2489 VARIANT_BOOL* isPreserving )
2491 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2492 TRACE("(%p)->(%p: %d)\n", This, isPreserving, This->properties->preserving);
2493 *isPreserving = This->properties->preserving;
2494 return S_OK;
2498 static HRESULT WINAPI domdoc_put_preserveWhiteSpace(
2499 IXMLDOMDocument3 *iface,
2500 VARIANT_BOOL isPreserving )
2502 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2503 TRACE("(%p)->(%d)\n", This, isPreserving);
2504 This->properties->preserving = isPreserving;
2505 return S_OK;
2509 static HRESULT WINAPI domdoc_put_onreadystatechange(
2510 IXMLDOMDocument3 *iface,
2511 VARIANT event )
2513 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2515 TRACE("(%p)->(%s)\n", This, debugstr_variant(&event));
2516 return set_doc_event(This, EVENTID_READYSTATECHANGE, &event);
2520 static HRESULT WINAPI domdoc_put_onDataAvailable(IXMLDOMDocument3 *iface, VARIANT sink)
2522 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2523 FIXME("(%p)->(%s): stub\n", This, debugstr_variant(&sink));
2524 return E_NOTIMPL;
2527 static HRESULT WINAPI domdoc_put_onTransformNode(IXMLDOMDocument3 *iface, VARIANT sink )
2529 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2530 FIXME("(%p)->(%s): stub\n", This, debugstr_variant(&sink));
2531 return E_NOTIMPL;
2534 static HRESULT WINAPI domdoc_get_namespaces(
2535 IXMLDOMDocument3* iface,
2536 IXMLDOMSchemaCollection** collection )
2538 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2539 HRESULT hr;
2541 FIXME("(%p)->(%p): semi-stub\n", This, collection);
2543 if (!collection) return E_POINTER;
2545 if (!This->namespaces)
2547 hr = SchemaCache_create(This->properties->version, NULL, (void**)&This->namespaces);
2548 if (hr != S_OK) return hr;
2550 hr = cache_from_doc_ns(This->namespaces, &This->node);
2551 if (hr != S_OK)
2552 release_namespaces(This);
2555 if (This->namespaces)
2556 return IXMLDOMSchemaCollection2_QueryInterface(This->namespaces,
2557 &IID_IXMLDOMSchemaCollection, (void**)collection);
2559 return hr;
2562 static HRESULT WINAPI domdoc_get_schemas(
2563 IXMLDOMDocument3* iface,
2564 VARIANT* schema )
2566 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2567 IXMLDOMSchemaCollection2* cur_schema = This->properties->schemaCache;
2568 HRESULT hr = S_FALSE;
2570 TRACE("(%p)->(%p)\n", This, schema);
2572 V_VT(schema) = VT_NULL;
2573 /* just to reset pointer part, cause that's what application is expected to use */
2574 V_DISPATCH(schema) = NULL;
2576 if(cur_schema)
2578 hr = IXMLDOMSchemaCollection2_QueryInterface(cur_schema, &IID_IDispatch, (void**)&V_DISPATCH(schema));
2579 if(SUCCEEDED(hr))
2580 V_VT(schema) = VT_DISPATCH;
2582 return hr;
2585 static HRESULT WINAPI domdoc_putref_schemas(
2586 IXMLDOMDocument3* iface,
2587 VARIANT schema)
2589 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2590 HRESULT hr = E_FAIL;
2591 IXMLDOMSchemaCollection2* new_schema = NULL;
2593 FIXME("(%p)->(%s): semi-stub\n", This, debugstr_variant(&schema));
2594 switch(V_VT(&schema))
2596 case VT_UNKNOWN:
2597 if (V_UNKNOWN(&schema))
2599 hr = IUnknown_QueryInterface(V_UNKNOWN(&schema), &IID_IXMLDOMSchemaCollection, (void**)&new_schema);
2600 break;
2602 /* fallthrough */
2603 case VT_DISPATCH:
2604 if (V_DISPATCH(&schema))
2606 hr = IDispatch_QueryInterface(V_DISPATCH(&schema), &IID_IXMLDOMSchemaCollection, (void**)&new_schema);
2607 break;
2609 /* fallthrough */
2610 case VT_NULL:
2611 case VT_EMPTY:
2612 hr = S_OK;
2613 break;
2615 default:
2616 WARN("Can't get schema from vt %x\n", V_VT(&schema));
2619 if(SUCCEEDED(hr))
2621 IXMLDOMSchemaCollection2* old_schema = InterlockedExchangePointer((void**)&This->properties->schemaCache, new_schema);
2622 if(old_schema) IXMLDOMSchemaCollection2_Release(old_schema);
2625 return hr;
2628 static inline BOOL is_wellformed(xmlDocPtr doc)
2630 #ifdef HAVE_XMLDOC_PROPERTIES
2631 return doc->properties & XML_DOC_WELLFORMED;
2632 #else
2633 /* Not a full check, but catches the worst violations */
2634 xmlNodePtr child;
2635 int root = 0;
2637 for (child = doc->children; child != NULL; child = child->next)
2639 switch (child->type)
2641 case XML_ELEMENT_NODE:
2642 if (++root > 1)
2643 return FALSE;
2644 break;
2645 case XML_TEXT_NODE:
2646 case XML_CDATA_SECTION_NODE:
2647 return FALSE;
2648 break;
2649 default:
2650 break;
2654 return root == 1;
2655 #endif
2658 static void LIBXML2_LOG_CALLBACK validate_error(void* ctx, char const* msg, ...)
2660 va_list ap;
2661 va_start(ap, msg);
2662 LIBXML2_CALLBACK_ERR(domdoc_validateNode, msg, ap);
2663 va_end(ap);
2666 static void LIBXML2_LOG_CALLBACK validate_warning(void* ctx, char const* msg, ...)
2668 va_list ap;
2669 va_start(ap, msg);
2670 LIBXML2_CALLBACK_WARN(domdoc_validateNode, msg, ap);
2671 va_end(ap);
2674 static HRESULT WINAPI domdoc_validateNode(
2675 IXMLDOMDocument3* iface,
2676 IXMLDOMNode* node,
2677 IXMLDOMParseError** err)
2679 domdoc* This = impl_from_IXMLDOMDocument3(iface);
2680 LONG state, err_code = 0;
2681 HRESULT hr = S_OK;
2682 int validated = 0;
2684 TRACE("(%p)->(%p, %p)\n", This, node, err);
2685 IXMLDOMDocument3_get_readyState(iface, &state);
2686 if (state != READYSTATE_COMPLETE)
2688 if (err)
2689 *err = create_parseError(err_code, NULL, NULL, NULL, 0, 0, 0);
2690 return E_PENDING;
2693 if (!node)
2695 if (err)
2696 *err = create_parseError(err_code, NULL, NULL, NULL, 0, 0, 0);
2697 return E_POINTER;
2700 if (!get_node_obj(node)->node || get_node_obj(node)->node->doc != get_doc(This))
2702 if (err)
2703 *err = create_parseError(err_code, NULL, NULL, NULL, 0, 0, 0);
2704 return E_FAIL;
2707 if (!is_wellformed(get_doc(This)))
2709 ERR("doc not well-formed\n");
2710 if (err)
2711 *err = create_parseError(E_XML_NOTWF, NULL, NULL, NULL, 0, 0, 0);
2712 return S_FALSE;
2715 /* DTD validation */
2716 if (get_doc(This)->intSubset || get_doc(This)->extSubset)
2718 xmlValidCtxtPtr vctx = xmlNewValidCtxt();
2719 vctx->error = validate_error;
2720 vctx->warning = validate_warning;
2721 ++validated;
2723 if (!((node == (IXMLDOMNode*)iface)?
2724 xmlValidateDocument(vctx, get_doc(This)) :
2725 xmlValidateElement(vctx, get_doc(This), get_node_obj(node)->node)))
2727 /* TODO: get a real error code here */
2728 TRACE("DTD validation failed\n");
2729 err_code = E_XML_INVALID;
2730 hr = S_FALSE;
2732 xmlFreeValidCtxt(vctx);
2735 /* Schema validation */
2736 if (hr == S_OK && This->properties->schemaCache != NULL)
2739 hr = SchemaCache_validate_tree(This->properties->schemaCache, get_node_obj(node)->node);
2740 if (SUCCEEDED(hr))
2742 ++validated;
2743 /* TODO: get a real error code here */
2744 if (hr == S_OK)
2746 TRACE("schema validation succeeded\n");
2748 else
2750 ERR("schema validation failed\n");
2751 err_code = E_XML_INVALID;
2754 else
2756 /* not really OK, just didn't find a schema for the ns */
2757 hr = S_OK;
2761 if (!validated)
2763 ERR("no DTD or schema found\n");
2764 err_code = E_XML_NODTD;
2765 hr = S_FALSE;
2768 if (err)
2769 *err = create_parseError(err_code, NULL, NULL, NULL, 0, 0, 0);
2771 return hr;
2774 static HRESULT WINAPI domdoc_validate(
2775 IXMLDOMDocument3* iface,
2776 IXMLDOMParseError** err)
2778 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2779 TRACE("(%p)->(%p)\n", This, err);
2780 return IXMLDOMDocument3_validateNode(iface, (IXMLDOMNode*)iface, err);
2783 static HRESULT WINAPI domdoc_setProperty(
2784 IXMLDOMDocument3* iface,
2785 BSTR p,
2786 VARIANT value)
2788 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2790 TRACE("(%p)->(%s %s)\n", This, debugstr_w(p), debugstr_variant(&value));
2792 if (lstrcmpiW(p, PropertySelectionLanguageW) == 0)
2794 VARIANT varStr;
2795 HRESULT hr;
2796 BSTR bstr;
2798 V_VT(&varStr) = VT_EMPTY;
2799 if (V_VT(&value) != VT_BSTR)
2801 if (FAILED(hr = VariantChangeType(&varStr, &value, 0, VT_BSTR)))
2802 return hr;
2803 bstr = V_BSTR(&varStr);
2805 else
2806 bstr = V_BSTR(&value);
2808 hr = S_OK;
2809 if (lstrcmpiW(bstr, PropValueXPathW) == 0)
2810 This->properties->XPath = TRUE;
2811 else if (lstrcmpiW(bstr, PropValueXSLPatternW) == 0)
2812 This->properties->XPath = FALSE;
2813 else
2814 hr = E_FAIL;
2816 VariantClear(&varStr);
2817 return hr;
2819 else if (lstrcmpiW(p, PropertySelectionNamespacesW) == 0)
2821 xmlChar *nsStr = (xmlChar*)This->properties->selectNsStr;
2822 struct list *pNsList;
2823 VARIANT varStr;
2824 HRESULT hr;
2825 BSTR bstr;
2827 V_VT(&varStr) = VT_EMPTY;
2828 if (V_VT(&value) != VT_BSTR)
2830 if (FAILED(hr = VariantChangeType(&varStr, &value, 0, VT_BSTR)))
2831 return hr;
2832 bstr = V_BSTR(&varStr);
2834 else
2835 bstr = V_BSTR(&value);
2837 hr = S_OK;
2839 pNsList = &(This->properties->selectNsList);
2840 clear_selectNsList(pNsList);
2841 heap_free(nsStr);
2842 nsStr = xmlchar_from_wchar(bstr);
2844 TRACE("property value: \"%s\"\n", debugstr_w(bstr));
2846 This->properties->selectNsStr = nsStr;
2847 This->properties->selectNsStr_len = xmlStrlen(nsStr);
2848 if (bstr && *bstr)
2850 xmlChar *pTokBegin, *pTokEnd, *pTokInner;
2851 select_ns_entry* ns_entry = NULL;
2852 xmlXPathContextPtr ctx;
2854 ctx = xmlXPathNewContext(This->node.node->doc);
2855 pTokBegin = nsStr;
2857 /* skip leading spaces */
2858 while (*pTokBegin == ' ' || *pTokBegin == '\n' ||
2859 *pTokBegin == '\t' || *pTokBegin == '\r')
2860 ++pTokBegin;
2862 for (; *pTokBegin; pTokBegin = pTokEnd)
2864 if (ns_entry)
2865 memset(ns_entry, 0, sizeof(select_ns_entry));
2866 else
2867 ns_entry = heap_alloc_zero(sizeof(select_ns_entry));
2869 while (*pTokBegin == ' ')
2870 ++pTokBegin;
2871 pTokEnd = pTokBegin;
2872 while (*pTokEnd != ' ' && *pTokEnd != 0)
2873 ++pTokEnd;
2875 if (xmlStrncmp(pTokBegin, (xmlChar const*)"xmlns", 5) != 0)
2877 hr = E_FAIL;
2878 WARN("Syntax error in xmlns string: %s\n\tat token: %s\n",
2879 debugstr_w(bstr), debugstr_an((const char*)pTokBegin, pTokEnd-pTokBegin));
2880 continue;
2883 pTokBegin += 5;
2884 if (*pTokBegin == '=')
2886 /*valid for XSLPattern?*/
2887 FIXME("Setting default xmlns not supported - skipping.\n");
2888 continue;
2890 else if (*pTokBegin == ':')
2892 ns_entry->prefix = ++pTokBegin;
2893 for (pTokInner = pTokBegin; pTokInner != pTokEnd && *pTokInner != '='; ++pTokInner)
2896 if (pTokInner == pTokEnd)
2898 hr = E_FAIL;
2899 WARN("Syntax error in xmlns string: %s\n\tat token: %s\n",
2900 debugstr_w(bstr), debugstr_an((const char*)pTokBegin, pTokEnd-pTokBegin));
2901 continue;
2904 ns_entry->prefix_end = *pTokInner;
2905 *pTokInner = 0;
2906 ++pTokInner;
2908 if (pTokEnd-pTokInner > 1 &&
2909 ((*pTokInner == '\'' && *(pTokEnd-1) == '\'') ||
2910 (*pTokInner == '"' && *(pTokEnd-1) == '"')))
2912 ns_entry->href = ++pTokInner;
2913 ns_entry->href_end = *(pTokEnd-1);
2914 *(pTokEnd-1) = 0;
2915 list_add_tail(pNsList, &ns_entry->entry);
2916 /*let libxml figure out if they're valid from here ;)*/
2917 if (xmlXPathRegisterNs(ctx, ns_entry->prefix, ns_entry->href) != 0)
2919 hr = E_FAIL;
2921 ns_entry = NULL;
2922 continue;
2924 else
2926 WARN("Syntax error in xmlns string: %s\n\tat token: %s\n",
2927 debugstr_w(bstr), debugstr_an((const char*)pTokInner, pTokEnd-pTokInner));
2928 list_add_tail(pNsList, &ns_entry->entry);
2930 ns_entry = NULL;
2931 hr = E_FAIL;
2932 continue;
2935 else
2937 hr = E_FAIL;
2938 continue;
2941 heap_free(ns_entry);
2942 xmlXPathFreeContext(ctx);
2945 VariantClear(&varStr);
2946 return hr;
2948 else if (lstrcmpiW(p, PropertyProhibitDTDW) == 0 ||
2949 lstrcmpiW(p, PropertyNewParserW) == 0 ||
2950 lstrcmpiW(p, PropertyResolveExternalsW) == 0)
2952 /* Ignore */
2953 FIXME("Ignoring property %s, value %d\n", debugstr_w(p), V_BOOL(&value));
2954 return S_OK;
2957 FIXME("Unknown property %s\n", debugstr_w(p));
2958 return E_FAIL;
2961 static HRESULT WINAPI domdoc_getProperty(
2962 IXMLDOMDocument3* iface,
2963 BSTR p,
2964 VARIANT* var)
2966 domdoc *This = impl_from_IXMLDOMDocument3( iface );
2968 TRACE("(%p)->(%s)\n", This, debugstr_w(p));
2970 if (!var)
2971 return E_INVALIDARG;
2973 if (lstrcmpiW(p, PropertySelectionLanguageW) == 0)
2975 V_VT(var) = VT_BSTR;
2976 V_BSTR(var) = This->properties->XPath ?
2977 SysAllocString(PropValueXPathW) :
2978 SysAllocString(PropValueXSLPatternW);
2979 return V_BSTR(var) ? S_OK : E_OUTOFMEMORY;
2981 else if (lstrcmpiW(p, PropertySelectionNamespacesW) == 0)
2983 int lenA, lenW;
2984 BSTR rebuiltStr, cur;
2985 const xmlChar *nsStr;
2986 struct list *pNsList;
2987 select_ns_entry* pNsEntry;
2989 V_VT(var) = VT_BSTR;
2990 nsStr = This->properties->selectNsStr;
2991 pNsList = &This->properties->selectNsList;
2992 lenA = This->properties->selectNsStr_len;
2993 lenW = MultiByteToWideChar(CP_UTF8, 0, (LPCSTR)nsStr, lenA+1, NULL, 0);
2994 rebuiltStr = heap_alloc(lenW*sizeof(WCHAR));
2995 MultiByteToWideChar(CP_UTF8, 0, (LPCSTR)nsStr, lenA+1, rebuiltStr, lenW);
2996 cur = rebuiltStr;
2997 /* this is fine because all of the chars that end tokens are ASCII*/
2998 LIST_FOR_EACH_ENTRY(pNsEntry, pNsList, select_ns_entry, entry)
3000 while (*cur != 0) ++cur;
3001 if (pNsEntry->prefix_end)
3003 *cur = pNsEntry->prefix_end;
3004 while (*cur != 0) ++cur;
3007 if (pNsEntry->href_end)
3009 *cur = pNsEntry->href_end;
3012 V_BSTR(var) = SysAllocString(rebuiltStr);
3013 heap_free(rebuiltStr);
3014 return S_OK;
3017 FIXME("Unknown property %s\n", debugstr_w(p));
3018 return E_FAIL;
3021 static HRESULT WINAPI domdoc_importNode(
3022 IXMLDOMDocument3* iface,
3023 IXMLDOMNode* node,
3024 VARIANT_BOOL deep,
3025 IXMLDOMNode** clone)
3027 domdoc *This = impl_from_IXMLDOMDocument3( iface );
3028 FIXME("(%p)->(%p %d %p): stub\n", This, node, deep, clone);
3029 return E_NOTIMPL;
3032 static const struct IXMLDOMDocument3Vtbl XMLDOMDocument3Vtbl =
3034 domdoc_QueryInterface,
3035 domdoc_AddRef,
3036 domdoc_Release,
3037 domdoc_GetTypeInfoCount,
3038 domdoc_GetTypeInfo,
3039 domdoc_GetIDsOfNames,
3040 domdoc_Invoke,
3041 domdoc_get_nodeName,
3042 domdoc_get_nodeValue,
3043 domdoc_put_nodeValue,
3044 domdoc_get_nodeType,
3045 domdoc_get_parentNode,
3046 domdoc_get_childNodes,
3047 domdoc_get_firstChild,
3048 domdoc_get_lastChild,
3049 domdoc_get_previousSibling,
3050 domdoc_get_nextSibling,
3051 domdoc_get_attributes,
3052 domdoc_insertBefore,
3053 domdoc_replaceChild,
3054 domdoc_removeChild,
3055 domdoc_appendChild,
3056 domdoc_hasChildNodes,
3057 domdoc_get_ownerDocument,
3058 domdoc_cloneNode,
3059 domdoc_get_nodeTypeString,
3060 domdoc_get_text,
3061 domdoc_put_text,
3062 domdoc_get_specified,
3063 domdoc_get_definition,
3064 domdoc_get_nodeTypedValue,
3065 domdoc_put_nodeTypedValue,
3066 domdoc_get_dataType,
3067 domdoc_put_dataType,
3068 domdoc_get_xml,
3069 domdoc_transformNode,
3070 domdoc_selectNodes,
3071 domdoc_selectSingleNode,
3072 domdoc_get_parsed,
3073 domdoc_get_namespaceURI,
3074 domdoc_get_prefix,
3075 domdoc_get_baseName,
3076 domdoc_transformNodeToObject,
3077 domdoc_get_doctype,
3078 domdoc_get_implementation,
3079 domdoc_get_documentElement,
3080 domdoc_put_documentElement,
3081 domdoc_createElement,
3082 domdoc_createDocumentFragment,
3083 domdoc_createTextNode,
3084 domdoc_createComment,
3085 domdoc_createCDATASection,
3086 domdoc_createProcessingInstruction,
3087 domdoc_createAttribute,
3088 domdoc_createEntityReference,
3089 domdoc_getElementsByTagName,
3090 domdoc_createNode,
3091 domdoc_nodeFromID,
3092 domdoc_load,
3093 domdoc_get_readyState,
3094 domdoc_get_parseError,
3095 domdoc_get_url,
3096 domdoc_get_async,
3097 domdoc_put_async,
3098 domdoc_abort,
3099 domdoc_loadXML,
3100 domdoc_save,
3101 domdoc_get_validateOnParse,
3102 domdoc_put_validateOnParse,
3103 domdoc_get_resolveExternals,
3104 domdoc_put_resolveExternals,
3105 domdoc_get_preserveWhiteSpace,
3106 domdoc_put_preserveWhiteSpace,
3107 domdoc_put_onreadystatechange,
3108 domdoc_put_onDataAvailable,
3109 domdoc_put_onTransformNode,
3110 domdoc_get_namespaces,
3111 domdoc_get_schemas,
3112 domdoc_putref_schemas,
3113 domdoc_validate,
3114 domdoc_setProperty,
3115 domdoc_getProperty,
3116 domdoc_validateNode,
3117 domdoc_importNode
3120 /* IConnectionPointContainer */
3121 static HRESULT WINAPI ConnectionPointContainer_QueryInterface(IConnectionPointContainer *iface,
3122 REFIID riid, void **ppv)
3124 domdoc *This = impl_from_IConnectionPointContainer(iface);
3125 return IXMLDOMDocument3_QueryInterface(&This->IXMLDOMDocument3_iface, riid, ppv);
3128 static ULONG WINAPI ConnectionPointContainer_AddRef(IConnectionPointContainer *iface)
3130 domdoc *This = impl_from_IConnectionPointContainer(iface);
3131 return IXMLDOMDocument3_AddRef(&This->IXMLDOMDocument3_iface);
3134 static ULONG WINAPI ConnectionPointContainer_Release(IConnectionPointContainer *iface)
3136 domdoc *This = impl_from_IConnectionPointContainer(iface);
3137 return IXMLDOMDocument3_Release(&This->IXMLDOMDocument3_iface);
3140 static HRESULT WINAPI ConnectionPointContainer_EnumConnectionPoints(IConnectionPointContainer *iface,
3141 IEnumConnectionPoints **ppEnum)
3143 domdoc *This = impl_from_IConnectionPointContainer(iface);
3144 FIXME("(%p)->(%p): stub\n", This, ppEnum);
3145 return E_NOTIMPL;
3148 static HRESULT WINAPI ConnectionPointContainer_FindConnectionPoint(IConnectionPointContainer *iface,
3149 REFIID riid, IConnectionPoint **cp)
3151 domdoc *This = impl_from_IConnectionPointContainer(iface);
3152 ConnectionPoint *iter;
3154 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), cp);
3156 *cp = NULL;
3158 for(iter = This->cp_list; iter; iter = iter->next)
3160 if (IsEqualGUID(iter->iid, riid))
3161 *cp = &iter->IConnectionPoint_iface;
3164 if (*cp)
3166 IConnectionPoint_AddRef(*cp);
3167 return S_OK;
3170 FIXME("unsupported riid %s\n", debugstr_guid(riid));
3171 return CONNECT_E_NOCONNECTION;
3175 static const struct IConnectionPointContainerVtbl ConnectionPointContainerVtbl =
3177 ConnectionPointContainer_QueryInterface,
3178 ConnectionPointContainer_AddRef,
3179 ConnectionPointContainer_Release,
3180 ConnectionPointContainer_EnumConnectionPoints,
3181 ConnectionPointContainer_FindConnectionPoint
3184 /* IConnectionPoint */
3185 static HRESULT WINAPI ConnectionPoint_QueryInterface(IConnectionPoint *iface,
3186 REFIID riid, void **ppv)
3188 ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3190 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv );
3192 *ppv = NULL;
3194 if (IsEqualGUID(&IID_IUnknown, riid) ||
3195 IsEqualGUID(&IID_IConnectionPoint, riid))
3197 *ppv = iface;
3200 if (*ppv)
3202 IConnectionPoint_AddRef(iface);
3203 return S_OK;
3206 WARN("Unsupported interface %s\n", debugstr_guid(riid));
3207 return E_NOINTERFACE;
3210 static ULONG WINAPI ConnectionPoint_AddRef(IConnectionPoint *iface)
3212 ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3213 return IConnectionPointContainer_AddRef(This->container);
3216 static ULONG WINAPI ConnectionPoint_Release(IConnectionPoint *iface)
3218 ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3219 return IConnectionPointContainer_Release(This->container);
3222 static HRESULT WINAPI ConnectionPoint_GetConnectionInterface(IConnectionPoint *iface, IID *iid)
3224 ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3226 TRACE("(%p)->(%p)\n", This, iid);
3228 if (!iid) return E_POINTER;
3230 *iid = *This->iid;
3231 return S_OK;
3234 static HRESULT WINAPI ConnectionPoint_GetConnectionPointContainer(IConnectionPoint *iface,
3235 IConnectionPointContainer **container)
3237 ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3239 TRACE("(%p)->(%p)\n", This, container);
3241 if (!container) return E_POINTER;
3243 *container = This->container;
3244 IConnectionPointContainer_AddRef(*container);
3245 return S_OK;
3248 static HRESULT WINAPI ConnectionPoint_Advise(IConnectionPoint *iface, IUnknown *pUnkSink,
3249 DWORD *pdwCookie)
3251 ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3252 FIXME("(%p)->(%p %p): stub\n", This, pUnkSink, pdwCookie);
3253 return E_NOTIMPL;
3256 static HRESULT WINAPI ConnectionPoint_Unadvise(IConnectionPoint *iface, DWORD cookie)
3258 ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3260 TRACE("(%p)->(%d)\n", This, cookie);
3262 if (cookie == 0 || cookie > This->sinks_size || !This->sinks[cookie-1].unk)
3263 return CONNECT_E_NOCONNECTION;
3265 IUnknown_Release(This->sinks[cookie-1].unk);
3266 This->sinks[cookie-1].unk = NULL;
3268 return S_OK;
3271 static HRESULT WINAPI ConnectionPoint_EnumConnections(IConnectionPoint *iface,
3272 IEnumConnections **ppEnum)
3274 ConnectionPoint *This = impl_from_IConnectionPoint(iface);
3275 FIXME("(%p)->(%p): stub\n", This, ppEnum);
3276 return E_NOTIMPL;
3279 static const IConnectionPointVtbl ConnectionPointVtbl =
3281 ConnectionPoint_QueryInterface,
3282 ConnectionPoint_AddRef,
3283 ConnectionPoint_Release,
3284 ConnectionPoint_GetConnectionInterface,
3285 ConnectionPoint_GetConnectionPointContainer,
3286 ConnectionPoint_Advise,
3287 ConnectionPoint_Unadvise,
3288 ConnectionPoint_EnumConnections
3291 static void ConnectionPoint_Init(ConnectionPoint *cp, struct domdoc *doc, REFIID riid)
3293 cp->IConnectionPoint_iface.lpVtbl = &ConnectionPointVtbl;
3294 cp->doc = doc;
3295 cp->iid = riid;
3296 cp->sinks = NULL;
3297 cp->sinks_size = 0;
3299 cp->next = doc->cp_list;
3300 doc->cp_list = cp;
3302 cp->container = &doc->IConnectionPointContainer_iface;
3305 /* domdoc implementation of IObjectWithSite */
3306 static HRESULT WINAPI
3307 domdoc_ObjectWithSite_QueryInterface( IObjectWithSite* iface, REFIID riid, void** ppvObject )
3309 domdoc *This = impl_from_IObjectWithSite(iface);
3310 return IXMLDOMDocument3_QueryInterface(&This->IXMLDOMDocument3_iface, riid, ppvObject);
3313 static ULONG WINAPI domdoc_ObjectWithSite_AddRef( IObjectWithSite* iface )
3315 domdoc *This = impl_from_IObjectWithSite(iface);
3316 return IXMLDOMDocument3_AddRef(&This->IXMLDOMDocument3_iface);
3319 static ULONG WINAPI domdoc_ObjectWithSite_Release( IObjectWithSite* iface )
3321 domdoc *This = impl_from_IObjectWithSite(iface);
3322 return IXMLDOMDocument3_Release(&This->IXMLDOMDocument3_iface);
3325 static HRESULT WINAPI domdoc_ObjectWithSite_GetSite( IObjectWithSite *iface, REFIID iid, void **ppvSite )
3327 domdoc *This = impl_from_IObjectWithSite(iface);
3329 TRACE("(%p)->(%s %p)\n", This, debugstr_guid( iid ), ppvSite );
3331 if ( !This->site )
3332 return E_FAIL;
3334 return IUnknown_QueryInterface( This->site, iid, ppvSite );
3337 static HRESULT WINAPI domdoc_ObjectWithSite_SetSite( IObjectWithSite *iface, IUnknown *punk )
3339 domdoc *This = impl_from_IObjectWithSite(iface);
3341 TRACE("(%p)->(%p)\n", iface, punk);
3343 if(!punk)
3345 if(This->site)
3347 IUnknown_Release( This->site );
3348 This->site = NULL;
3351 return S_OK;
3354 IUnknown_AddRef( punk );
3356 if(This->site)
3357 IUnknown_Release( This->site );
3359 This->site = punk;
3361 return S_OK;
3364 static const IObjectWithSiteVtbl domdocObjectSite =
3366 domdoc_ObjectWithSite_QueryInterface,
3367 domdoc_ObjectWithSite_AddRef,
3368 domdoc_ObjectWithSite_Release,
3369 domdoc_ObjectWithSite_SetSite,
3370 domdoc_ObjectWithSite_GetSite
3373 static HRESULT WINAPI domdoc_Safety_QueryInterface(IObjectSafety *iface, REFIID riid, void **ppv)
3375 domdoc *This = impl_from_IObjectSafety(iface);
3376 return IXMLDOMDocument3_QueryInterface(&This->IXMLDOMDocument3_iface, riid, ppv);
3379 static ULONG WINAPI domdoc_Safety_AddRef(IObjectSafety *iface)
3381 domdoc *This = impl_from_IObjectSafety(iface);
3382 return IXMLDOMDocument3_AddRef(&This->IXMLDOMDocument3_iface);
3385 static ULONG WINAPI domdoc_Safety_Release(IObjectSafety *iface)
3387 domdoc *This = impl_from_IObjectSafety(iface);
3388 return IXMLDOMDocument3_Release(&This->IXMLDOMDocument3_iface);
3391 #define SAFETY_SUPPORTED_OPTIONS (INTERFACESAFE_FOR_UNTRUSTED_CALLER|INTERFACESAFE_FOR_UNTRUSTED_DATA|INTERFACE_USES_SECURITY_MANAGER)
3393 static HRESULT WINAPI domdoc_Safety_GetInterfaceSafetyOptions(IObjectSafety *iface, REFIID riid,
3394 DWORD *supported, DWORD *enabled)
3396 domdoc *This = impl_from_IObjectSafety(iface);
3398 TRACE("(%p)->(%s %p %p)\n", This, debugstr_guid(riid), supported, enabled);
3400 if(!supported || !enabled) return E_POINTER;
3402 *supported = SAFETY_SUPPORTED_OPTIONS;
3403 *enabled = This->safeopt;
3405 return S_OK;
3408 static HRESULT WINAPI domdoc_Safety_SetInterfaceSafetyOptions(IObjectSafety *iface, REFIID riid,
3409 DWORD mask, DWORD enabled)
3411 domdoc *This = impl_from_IObjectSafety(iface);
3412 TRACE("(%p)->(%s %x %x)\n", This, debugstr_guid(riid), mask, enabled);
3414 if ((mask & ~SAFETY_SUPPORTED_OPTIONS) != 0)
3415 return E_FAIL;
3417 This->safeopt = (This->safeopt & ~mask) | (mask & enabled);
3419 return S_OK;
3422 #undef SAFETY_SUPPORTED_OPTIONS
3424 static const IObjectSafetyVtbl domdocObjectSafetyVtbl = {
3425 domdoc_Safety_QueryInterface,
3426 domdoc_Safety_AddRef,
3427 domdoc_Safety_Release,
3428 domdoc_Safety_GetInterfaceSafetyOptions,
3429 domdoc_Safety_SetInterfaceSafetyOptions
3432 static const tid_t domdoc_iface_tids[] = {
3433 IXMLDOMDocument3_tid,
3437 static dispex_static_data_t domdoc_dispex = {
3438 NULL,
3439 IXMLDOMDocument3_tid,
3440 NULL,
3441 domdoc_iface_tids
3444 HRESULT get_domdoc_from_xmldoc(xmlDocPtr xmldoc, IXMLDOMDocument3 **document)
3446 domdoc *doc;
3448 doc = heap_alloc( sizeof (*doc) );
3449 if( !doc )
3450 return E_OUTOFMEMORY;
3452 doc->IXMLDOMDocument3_iface.lpVtbl = &XMLDOMDocument3Vtbl;
3453 doc->IPersistStreamInit_iface.lpVtbl = &xmldoc_IPersistStreamInit_VTable;
3454 doc->IObjectWithSite_iface.lpVtbl = &domdocObjectSite;
3455 doc->IObjectSafety_iface.lpVtbl = &domdocObjectSafetyVtbl;
3456 doc->IConnectionPointContainer_iface.lpVtbl = &ConnectionPointContainerVtbl;
3457 doc->ref = 1;
3458 doc->async = VARIANT_TRUE;
3459 doc->validating = 0;
3460 doc->resolving = 0;
3461 doc->properties = properties_from_xmlDocPtr(xmldoc);
3462 doc->error = S_OK;
3463 doc->stream = NULL;
3464 doc->site = NULL;
3465 doc->safeopt = 0;
3466 doc->bsc = NULL;
3467 doc->cp_list = NULL;
3468 doc->namespaces = NULL;
3469 memset(doc->events, 0, sizeof(doc->events));
3471 /* events connection points */
3472 ConnectionPoint_Init(&doc->cp_dispatch, doc, &IID_IDispatch);
3473 ConnectionPoint_Init(&doc->cp_propnotif, doc, &IID_IPropertyNotifySink);
3474 ConnectionPoint_Init(&doc->cp_domdocevents, doc, &DIID_XMLDOMDocumentEvents);
3476 init_xmlnode(&doc->node, (xmlNodePtr)xmldoc, (IXMLDOMNode*)&doc->IXMLDOMDocument3_iface,
3477 &domdoc_dispex);
3479 *document = &doc->IXMLDOMDocument3_iface;
3481 TRACE("returning iface %p\n", *document);
3482 return S_OK;
3485 HRESULT DOMDocument_create(MSXML_VERSION version, IUnknown *pUnkOuter, void **ppObj)
3487 xmlDocPtr xmldoc;
3488 HRESULT hr;
3490 TRACE("(%d, %p, %p)\n", version, pUnkOuter, ppObj);
3492 xmldoc = xmlNewDoc(NULL);
3493 if(!xmldoc)
3494 return E_OUTOFMEMORY;
3496 xmldoc_init(xmldoc, version);
3498 hr = get_domdoc_from_xmldoc(xmldoc, (IXMLDOMDocument3**)ppObj);
3499 if(FAILED(hr))
3501 free_properties(properties_from_xmlDocPtr(xmldoc));
3502 heap_free(xmldoc->_private);
3503 xmlFreeDoc(xmldoc);
3504 return hr;
3507 return hr;
3510 IUnknown* create_domdoc( xmlNodePtr document )
3512 void* pObj = NULL;
3513 HRESULT hr;
3515 TRACE("(%p)\n", document);
3517 hr = get_domdoc_from_xmldoc((xmlDocPtr)document, (IXMLDOMDocument3**)&pObj);
3518 if (FAILED(hr))
3519 return NULL;
3521 return pObj;
3524 #else
3526 HRESULT DOMDocument_create(MSXML_VERSION version, IUnknown *pUnkOuter, void **ppObj)
3528 MESSAGE("This program tried to use a DOMDocument object, but\n"
3529 "libxml2 support was not present at compile time.\n");
3530 return E_NOTIMPL;
3533 #endif